Fix null sessions in HttpContextWrapper.Session
[mono.git] / mcs / class / corlib / System.Security.Cryptography / CryptoConfig.cs
index cffa845268b71180b8b7ec8a1fd92b0a3d475c4e..bb3a7399759f5c88eb7507547346ede9a848dd26 100644 (file)
@@ -7,7 +7,8 @@
 //
 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
 // Copyright (C) Tim Coleman, 2004
-// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2007,2011 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2011 Xamarin Inc. http://www.xamarin.com
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+#if !MOONLIGHT
+
 using System.Collections;
+using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
 using System.Reflection;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Security.Permissions;
 using System.Text;
 
@@ -41,105 +46,94 @@ using Mono.Xml;
 
 namespace System.Security.Cryptography {
 
-public class CryptoConfig {
+[ComVisible (true)]
+public partial class CryptoConfig {
 
        static private object lockObject;
-       static private Hashtable algorithms;
-       static private Hashtable oid;
+       static private Dictionary<string,Type> algorithms;
+       static private Dictionary<string,string> unresolved_algorithms;
+       static private Dictionary<string,string> oids;
 
        private const string defaultNamespace = "System.Security.Cryptography.";
-       private const string defaultSHA1 = defaultNamespace + "SHA1CryptoServiceProvider";
-       private const string defaultMD5 = defaultNamespace + "MD5CryptoServiceProvider";
-       private const string defaultSHA256 = defaultNamespace + "SHA256Managed";
-       private const string defaultSHA384 = defaultNamespace + "SHA384Managed";
-       private const string defaultSHA512 = defaultNamespace + "SHA512Managed";
-       private const string defaultRSA = defaultNamespace + "RSACryptoServiceProvider";
-       private const string defaultDSA = defaultNamespace + "DSACryptoServiceProvider";
-       private const string defaultDES = defaultNamespace + "DESCryptoServiceProvider";
-       private const string default3DES = defaultNamespace + "TripleDESCryptoServiceProvider";
-       private const string defaultRC2 = defaultNamespace + "RC2CryptoServiceProvider";
-       private const string defaultAES = defaultNamespace + "RijndaelManaged";
+       static Type defaultSHA1 = typeof (SHA1CryptoServiceProvider);
+       static Type defaultMD5 = typeof (MD5CryptoServiceProvider);
+       static Type defaultSHA256 = typeof (SHA256Managed);
+       static Type defaultSHA384 = typeof (SHA384Managed);
+       static Type defaultSHA512 = typeof (SHA512Managed);
+       static Type defaultRSA = typeof (RSACryptoServiceProvider);
+       static Type defaultDSA = typeof (DSACryptoServiceProvider);
+       static Type defaultDES = typeof (DESCryptoServiceProvider);
+       static Type default3DES = typeof (TripleDESCryptoServiceProvider);
+       static Type defaultRC2 = typeof (RC2CryptoServiceProvider);
+       static Type defaultAES = typeof (RijndaelManaged);
        // LAMESPEC: undocumented names in CryptoConfig
-       private const string defaultRNG = defaultNamespace + "RNGCryptoServiceProvider";
-       private const string defaultHMAC = defaultNamespace + "HMACSHA1";
-       private const string defaultMAC3DES = defaultNamespace + "MACTripleDES";
+       static Type defaultRNG = typeof (RNGCryptoServiceProvider);
+       static Type defaultHMAC = typeof (HMACSHA1);
+       static Type defaultMAC3DES = typeof (MACTripleDES);
        // LAMESPEC: undocumented classes (also undocumented in CryptoConfig ;-)
-       private const string defaultDSASigDesc = defaultNamespace + "DSASignatureDescription";
-       private const string defaultRSASigDesc = defaultNamespace + "RSAPKCS1SHA1SignatureDescription";
-#if NET_2_0
-       private const string defaultRIPEMD160 = defaultNamespace + "RIPEMD160Managed";
-       private const string defaultHMACMD5 = defaultNamespace + "HMACMD5";
-       private const string defaultHMACRIPEMD160 = defaultNamespace + "HMACRIPEMD160";
-       private const string defaultHMACSHA256 = defaultNamespace + "HMACSHA256";
-       private const string defaultHMACSHA384 = defaultNamespace + "HMACSHA384";
-       private const string defaultHMACSHA512 = defaultNamespace + "HMACSHA512";
-#endif
+       static Type defaultDSASigDesc = typeof (DSASignatureDescription);
+       static Type defaultRSASigDesc = typeof (RSAPKCS1SHA1SignatureDescription);
+       static Type defaultRIPEMD160 = typeof (RIPEMD160Managed);
+       static Type defaultHMACMD5 = typeof (HMACMD5);
+       static Type defaultHMACRIPEMD160 = typeof (HMACRIPEMD160);
+       static Type defaultHMACSHA256 = typeof (HMACSHA256);
+       static Type defaultHMACSHA384 = typeof (HMACSHA384);
+       static Type defaultHMACSHA512 = typeof (HMACSHA512);
 
        // LAMESPEC: undocumented names in CryptoConfig
-#if (NET_2_0)
-       private const string xmlAssembly = ", System.Security, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
-#elif (NET_1_1)
-       private const string xmlAssembly = ", System.Security, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
-#elif (NET_1_0)
-       private const string xmlAssembly = ", System.Security, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
-#else
-       private const string xmlAssembly = ", System.Security, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
-#endif
-       private const string defaultC14N = defaultNamespace + "Xml.XmlDsigC14NTransform" + xmlAssembly;
-       private const string defaultC14NWithComments = defaultNamespace + "Xml.XmlDsigC14NWithCommentsTransform" + xmlAssembly;
-       private const string defaultBase64 = defaultNamespace + "Xml.XmlDsigBase64Transform" + xmlAssembly;
-       private const string defaultXPath = defaultNamespace + "Xml.XmlDsigXPathTransform" + xmlAssembly;
-       private const string defaultXslt = defaultNamespace + "Xml.XmlDsigXsltTransform" + xmlAssembly;
-       private const string defaultEnveloped = defaultNamespace + "Xml.XmlDsigEnvelopedSignatureTransform" + xmlAssembly;
-#if NET_2_0
-       private const string defaultXmlDecryption = defaultNamespace + "Xml.XmlDecryptionTransform" + xmlAssembly;
-       private const string defaultExcC14N = defaultNamespace + "Xml.XmlDsigExcC14NTransform" + xmlAssembly;
-       private const string defaultExcC14NWithComments = defaultNamespace + "Xml.XmlDsigExcC14NWithCommentsTransform" + xmlAssembly;
-#endif
+       private const string defaultC14N = defaultNamespace + "Xml.XmlDsigC14NTransform, " + Consts.AssemblySystem_Security;
+       private const string defaultC14NWithComments = defaultNamespace + "Xml.XmlDsigC14NWithCommentsTransform, " + Consts.AssemblySystem_Security;
+       private const string defaultBase64 = defaultNamespace + "Xml.XmlDsigBase64Transform, " + Consts.AssemblySystem_Security;
+       private const string defaultXPath = defaultNamespace + "Xml.XmlDsigXPathTransform, " + Consts.AssemblySystem_Security;
+       private const string defaultXslt = defaultNamespace + "Xml.XmlDsigXsltTransform, " + Consts.AssemblySystem_Security;
+       private const string defaultEnveloped = defaultNamespace + "Xml.XmlDsigEnvelopedSignatureTransform, " + Consts.AssemblySystem_Security;
+       private const string defaultXmlDecryption = defaultNamespace + "Xml.XmlDecryptionTransform, " + Consts.AssemblySystem_Security;
+       private const string defaultExcC14N = defaultNamespace + "Xml.XmlDsigExcC14NTransform, " + Consts.AssemblySystem_Security;
+       private const string defaultExcC14NWithComments = defaultNamespace + "Xml.XmlDsigExcC14NWithCommentsTransform, " + Consts.AssemblySystem_Security;
 
        // LAMESPEC: only documentated in ".NET Framework Security" book
-       private const string defaultX509Data = defaultNamespace + "Xml.KeyInfoX509Data" + xmlAssembly;
-       private const string defaultKeyName = defaultNamespace + "Xml.KeyInfoName" + xmlAssembly;
-       private const string defaultKeyValueDSA = defaultNamespace + "Xml.DSAKeyValue" + xmlAssembly;
-       private const string defaultKeyValueRSA = defaultNamespace + "Xml.RSAKeyValue" + xmlAssembly;
-       private const string defaultRetrievalMethod = defaultNamespace + "Xml.KeyInfoRetrievalMethod" + xmlAssembly;
+       private const string defaultX509Data = defaultNamespace + "Xml.KeyInfoX509Data, " + Consts.AssemblySystem_Security;
+       private const string defaultKeyName = defaultNamespace + "Xml.KeyInfoName, " + Consts.AssemblySystem_Security;
+       private const string defaultKeyValueDSA = defaultNamespace + "Xml.DSAKeyValue, " + Consts.AssemblySystem_Security;
+       private const string defaultKeyValueRSA = defaultNamespace + "Xml.RSAKeyValue, " + Consts.AssemblySystem_Security;
+       private const string defaultRetrievalMethod = defaultNamespace + "Xml.KeyInfoRetrievalMethod, " + Consts.AssemblySystem_Security;
 
        private const string managedSHA1 = defaultNamespace + "SHA1Managed";
 
        // Oddly OID seems only available for hash algorithms
        private const string oidSHA1 = "1.3.14.3.2.26";
        private const string oidMD5 = "1.2.840.113549.2.5";
-#if NET_2_0
        // changed in 2.0
        private const string oidSHA256 = "2.16.840.1.101.3.4.2.1";
        private const string oidSHA384 = "2.16.840.1.101.3.4.2.2";
        private const string oidSHA512 = "2.16.840.1.101.3.4.2.3";
+       private const string oidRIPEMD160 = "1.3.36.3.2.1";
        // new in 2.0
-       private const string oidRSA = "1.2.840.113549.1.1.1";
-       private const string oidDSA = "1.2.840.10040.4.1";
+//     private const string oidRSA = "1.2.840.113549.1.1.1";
+//     private const string oidDSA = "1.2.840.10040.4.1";
        private const string oidDES = "1.3.14.3.2.7";
        private const string oid3DES = "1.2.840.113549.3.7";
        private const string oidRC2 = "1.2.840.113549.3.2";
-#else
-       private const string oidSHA256 = "2.16.840.1.101.3.4.1";
-       private const string oidSHA384 = "2.16.840.1.101.3.4.2";
-       private const string oidSHA512 = "2.16.840.1.101.3.4.3";
-#endif
        // LAMESPEC: only documentated in ".NET Framework Security" book
        private const string oid3DESKeyWrap = "1.2.840.113549.1.9.16.3.6";
 
+       private const string nameSHA1 = "System.Security.Cryptography.SHA1CryptoServiceProvider";
        private const string nameSHA1a = "SHA";
        private const string nameSHA1b = "SHA1";
        private const string nameSHA1c = "System.Security.Cryptography.SHA1";
        private const string nameSHA1d = "System.Security.Cryptography.HashAlgorithm";
+       private const string nameMD5 = "System.Security.Cryptography.MD5CryptoServiceProvider";
        private const string nameMD5a = "MD5";
        private const string nameMD5b = "System.Security.Cryptography.MD5";
+       private const string nameSHA256 = "System.Security.Cryptography.SHA256Managed";
        private const string nameSHA256a = "SHA256";
        private const string nameSHA256b = "SHA-256";
        private const string nameSHA256c = "System.Security.Cryptography.SHA256";
+       private const string nameSHA384 = "System.Security.Cryptography.SHA384Managed";
        private const string nameSHA384a = "SHA384";
        private const string nameSHA384b = "SHA-384";
        private const string nameSHA384c = "System.Security.Cryptography.SHA384";
+       private const string nameSHA512 = "System.Security.Cryptography.SHA512Managed";
        private const string nameSHA512a = "SHA512";
        private const string nameSHA512b = "SHA-512";
        private const string nameSHA512c = "System.Security.Cryptography.SHA512";
@@ -169,11 +163,11 @@ public class CryptoConfig {
        private const string nameMAC3DESb = "System.Security.Cryptography.MACTripleDES";
        // LAMESPEC: only documentated in ".NET Framework Security" book
        private const string name3DESKeyWrap = "TripleDESKeyWrap";
-#if NET_2_0
+       private const string nameRIPEMD160 = "System.Security.Cryptography.RIPEMD160Managed";
        private const string nameRIPEMD160a = "RIPEMD160";
        private const string nameRIPEMD160b = "RIPEMD-160";
        private const string nameRIPEMD160c = "System.Security.Cryptography.RIPEMD160";
-       private const string nameHMACa = "HMAC";
+//     private const string nameHMACa = "HMAC";
        private const string nameHMACb = "System.Security.Cryptography.HMAC";
        private const string nameHMACMD5a = "HMACMD5";
        private const string nameHMACMD5b = "System.Security.Cryptography.HMACMD5";
@@ -185,7 +179,6 @@ public class CryptoConfig {
        private const string nameHMACSHA384b = "System.Security.Cryptography.HMACSHA384";
        private const string nameHMACSHA512a = "HMACSHA512";
        private const string nameHMACSHA512b = "System.Security.Cryptography.HMACSHA512";
-#endif
 
        private const string urlXmlDsig = "http://www.w3.org/2000/09/xmldsig#";
        // LAMESPEC: undocumented URLs in CryptoConfig
@@ -198,11 +191,15 @@ public class CryptoConfig {
        private const string urlXPath = "http://www.w3.org/TR/1999/REC-xpath-19991116";
        private const string urlXslt = "http://www.w3.org/TR/1999/REC-xslt-19991116";
        private const string urlEnveloped = urlXmlDsig + "enveloped-signature";         // no space
-#if NET_2_0
        private const string urlXmlDecryption = "http://www.w3.org/2002/07/decrypt#XML";
-       private const string urlExcC14N = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments";
-       private const string urlExcC14NWithComments = "http://www.w3.org/2001/10/xml-exc-c14n#";
-#endif
+       private const string urlExcC14NWithComments = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments";
+       private const string urlExcC14N = "http://www.w3.org/2001/10/xml-exc-c14n#";
+       private const string urlSHA256 = "http://www.w3.org/2001/04/xmlenc#sha256";
+       private const string urlSHA512 = "http://www.w3.org/2001/04/xmlenc#sha512";
+       private const string urlHMACSHA256 = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256";
+       private const string urlHMACSHA384 = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384";
+       private const string urlHMACSHA512 = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512";
+       private const string urlHMACRIPEMD160 = "http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160";
 
        // LAMESPEC: only documentated in ".NET Framework Security" book
        private const string urlX509Data = urlXmlDsig + " X509Data";                    // space is required
@@ -211,6 +208,72 @@ public class CryptoConfig {
        private const string urlKeyValueRSA = urlXmlDsig + " KeyValue/RSAKeyValue";     // space is required
        private const string urlRetrievalMethod = urlXmlDsig + " RetrievalMethod";      // space is required
 
+       // new (2.0) X509 certificate extensions
+       private const string oidX509SubjectKeyIdentifier = "2.5.29.14";
+       private const string oidX509KeyUsage = "2.5.29.15";
+       private const string oidX509BasicConstraints = "2.5.29.19";
+       private const string oidX509EnhancedKeyUsage = "2.5.29.37";
+
+       private const string nameX509SubjectKeyIdentifier = defaultNamespace + "X509Certificates.X509SubjectKeyIdentifierExtension, " + Consts.AssemblySystem;
+       private const string nameX509KeyUsage = defaultNamespace + "X509Certificates.X509KeyUsageExtension, " + Consts.AssemblySystem;
+       private const string nameX509BasicConstraints = defaultNamespace + "X509Certificates.X509BasicConstraintsExtension, " + Consts.AssemblySystem;
+       private const string nameX509EnhancedKeyUsage = defaultNamespace + "X509Certificates.X509EnhancedKeyUsageExtension, " + Consts.AssemblySystem;
+
+       // new (2.0) X509 Chain
+       private const string nameX509Chain = "X509Chain";
+       private const string defaultX509Chain = defaultNamespace + "X509Certificates.X509Chain, " + Consts.AssemblySystem;
+#if NET_4_0
+       // AES
+       const string system_core_assembly = ", System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
+       const string nameAES_1 = "AES";
+       const string nameAES_2 = "System.Security.Cryptography.AesCryptoServiceProvider";
+       const string defaultAES_1 = "System.Security.Cryptography.AesCryptoServiceProvider" + system_core_assembly;
+       
+       const string nameAESManaged_1 = "AesManaged";
+       const string nameAESManaged_2 = "System.Security.Cryptography.AesManaged";
+       const string defaultAESManaged = "System.Security.Cryptography.AesManaged" + system_core_assembly;
+
+       // ECDiffieHellman - not implemented in System.Core at the moment
+       const string nameECDiffieHellman_1 = "ECDH";
+       const string nameECDiffieHellman_2 = "ECDiffieHellman";
+       const string nameECDiffieHellman_3 = "ECDiffieHellmanCng";
+       const string nameECDiffieHellman_4 = "System.Security.Cryptography.ECDiffieHellmanCng";
+       const string defaultECDiffieHellman = "System.Security.Cryptography.ECDiffieHellmanCng" + system_core_assembly;
+
+       // ECDsa - not implemented in System.Core at the moment
+       const string nameECDsa_1 = "ECDsa";
+       const string nameECDsa_2 = "ECDsaCng";
+       const string nameECDsa_3 = "System.Security.Cryptography.ECDsaCng";
+       const string defaultECDsa = "System.Security.Cryptography.ECDsaCng" + system_core_assembly;
+
+       // SHA1Cng
+       const string nameSHA1Cng = "System.Security.Cryptography.SHA1Cng";
+       const string defaultSHA1Cng = "System.Security.Cryptography.SHA1Cng" + system_core_assembly;
+
+       // SHA256Cng
+       const string nameSHA256Cng = "System.Security.Cryptography.SHA256Cng";
+       const string defaultSHA256Cng = "System.Security.Cryptography.SHA256Cng" + system_core_assembly;
+
+       // SHA256 provider
+       const string nameSHA256Provider = "System.Security.Cryptography.SHA256CryptoServiceProvider";
+       const string defaultSHA256Provider = "System.Security.Cryptography.SHA256CryptoServiceProvider" + system_core_assembly;
+
+       // SHA384Cng
+       const string nameSHA384Cng = "System.Security.Cryptography.SHA384Cng";
+       const string defaultSHA384Cng = "System.Security.Cryptography.SHA384Cng" + system_core_assembly;
+
+       // SHA384 provider
+       const string nameSHA384Provider = "System.Security.Cryptography.SHA384CryptoServiceProvider";
+       const string defaultSHA384Provider = "System.Security.Cryptography.SHA384CryptoServiceProvider" + system_core_assembly;
+
+       // SHA512Cng
+       const string nameSHA512Cng = "System.Security.Cryptography.SHA512Cng";
+       const string defaultSHA512Cng = "System.Security.Cryptography.SHA512Cng" + system_core_assembly;
+
+       // SHA512 provider
+       const string nameSHA512Provider = "System.Security.Cryptography.SHA512CryptoServiceProvider";
+       const string defaultSHA512Provider = "System.Security.Cryptography.SHA512CryptoServiceProvider" + system_core_assembly;
+#endif
        static CryptoConfig () 
        {
                // lock(this) is bad
@@ -220,7 +283,7 @@ public class CryptoConfig {
 
        private static void Initialize () 
        {
-               algorithms = new Hashtable ();
+               Dictionary<string,Type> algorithms = new Dictionary<string, Type> (StringComparer.OrdinalIgnoreCase);
                // see list @ http://msdn.microsoft.com/library/en-us/cpref/html/
                // frlrfSystemSecurityCryptographyCryptoConfigClassTopic.asp
                algorithms.Add (nameSHA1a, defaultSHA1);
@@ -275,7 +338,6 @@ public class CryptoConfig {
                algorithms.Add (nameHMACSHA1b, defaultHMAC);
                algorithms.Add (nameMAC3DESa, defaultMAC3DES);
                algorithms.Add (nameMAC3DESb, defaultMAC3DES);
-#if NET_2_0
                algorithms.Add (nameRIPEMD160a, defaultRIPEMD160);
                algorithms.Add (nameRIPEMD160b, defaultRIPEMD160);
                algorithms.Add (nameRIPEMD160c, defaultRIPEMD160);
@@ -290,135 +352,130 @@ public class CryptoConfig {
                algorithms.Add (nameHMACSHA384b, defaultHMACSHA384);
                algorithms.Add (nameHMACSHA512a, defaultHMACSHA512);
                algorithms.Add (nameHMACSHA512b, defaultHMACSHA512);
-#endif
-
+                       
+               // we do not want to load the types (and assemblies) unless we really need them
+               // so we keep those names as strings
+               Dictionary<string,string> unresolved_algorithms = new Dictionary<string, string> (StringComparer.OrdinalIgnoreCase);
+                       
                // LAMESPEC These URLs aren't documented but (hint) installing the WSDK
                // add some of the XMLDSIG urls into machine.config (and they make a LOT
                // of sense for implementing XMLDSIG in System.Security.Cryptography.Xml)
                algorithms.Add (urlDSASHA1, defaultDSASigDesc); 
                algorithms.Add (urlRSASHA1, defaultRSASigDesc);
                algorithms.Add (urlSHA1, defaultSHA1);
-               algorithms.Add (urlC14N, defaultC14N);
-               algorithms.Add (urlC14NWithComments, defaultC14NWithComments);
-               algorithms.Add (urlBase64, defaultBase64);
-               algorithms.Add (urlXPath, defaultXPath);
-               algorithms.Add (urlXslt, defaultXslt);
-               algorithms.Add (urlEnveloped, defaultEnveloped);
-#if NET_2_0
-               algorithms.Add (urlExcC14N, defaultExcC14N);
-               algorithms.Add (urlExcC14NWithComments, defaultExcC14NWithComments);
-               algorithms.Add (urlXmlDecryption, defaultXmlDecryption);
-#endif
+               unresolved_algorithms.Add (urlC14N, defaultC14N);
+               unresolved_algorithms.Add (urlC14NWithComments, defaultC14NWithComments);
+               unresolved_algorithms.Add (urlBase64, defaultBase64);
+               unresolved_algorithms.Add (urlXPath, defaultXPath);
+               unresolved_algorithms.Add (urlXslt, defaultXslt);
+               unresolved_algorithms.Add (urlEnveloped, defaultEnveloped);
+               unresolved_algorithms.Add (urlExcC14N, defaultExcC14N);
+               unresolved_algorithms.Add (urlExcC14NWithComments, defaultExcC14NWithComments);
+               unresolved_algorithms.Add (urlXmlDecryption, defaultXmlDecryption);
+               algorithms.Add (urlSHA256, defaultSHA256);
+               // xmlenc does not include a definition for SHA384
+               algorithms.Add (urlSHA512, defaultSHA512);
+               algorithms.Add (urlHMACSHA256, defaultHMACSHA256);
+               algorithms.Add (urlHMACSHA384, defaultHMACSHA384);
+               algorithms.Add (urlHMACSHA512, defaultHMACSHA512);
+               algorithms.Add (urlHMACRIPEMD160, defaultHMACRIPEMD160);
                // LAMESPEC: only documentated in ".NET Framework Security" book
-               algorithms.Add (urlX509Data, defaultX509Data);
-               algorithms.Add (urlKeyName, defaultKeyName);
-               algorithms.Add (urlKeyValueDSA, defaultKeyValueDSA);
-               algorithms.Add (urlKeyValueRSA, defaultKeyValueRSA);
-               algorithms.Add (urlRetrievalMethod, defaultRetrievalMethod);
+               unresolved_algorithms.Add (urlX509Data, defaultX509Data);
+               unresolved_algorithms.Add (urlKeyName, defaultKeyName);
+               unresolved_algorithms.Add (urlKeyValueDSA, defaultKeyValueDSA);
+               unresolved_algorithms.Add (urlKeyValueRSA, defaultKeyValueRSA);
+               unresolved_algorithms.Add (urlRetrievalMethod, defaultRetrievalMethod);
+
+               // note: X.509 extensions aren't part of OID but names
+               unresolved_algorithms.Add (oidX509SubjectKeyIdentifier, nameX509SubjectKeyIdentifier);
+               unresolved_algorithms.Add (oidX509KeyUsage, nameX509KeyUsage);
+               unresolved_algorithms.Add (oidX509BasicConstraints, nameX509BasicConstraints);
+               unresolved_algorithms.Add (oidX509EnhancedKeyUsage, nameX509EnhancedKeyUsage);
+               // note: the default X.509Chain can also be created this way
+               unresolved_algorithms.Add (nameX509Chain, defaultX509Chain);
+#if NET_4_0
+               unresolved_algorithms.Add (nameAES_1, defaultAES_1);
+               unresolved_algorithms.Add (nameAES_2, defaultAES_1);
+               unresolved_algorithms.Add (nameAESManaged_1, defaultAESManaged);
+               unresolved_algorithms.Add (nameAESManaged_2, defaultAESManaged);
+
+               unresolved_algorithms.Add (nameECDiffieHellman_1, defaultECDiffieHellman);
+               unresolved_algorithms.Add (nameECDiffieHellman_2, defaultECDiffieHellman);
+               unresolved_algorithms.Add (nameECDiffieHellman_3, defaultECDiffieHellman);
+               unresolved_algorithms.Add (nameECDiffieHellman_4, defaultECDiffieHellman);
+
+               unresolved_algorithms.Add (nameECDsa_1, defaultECDsa);
+               unresolved_algorithms.Add (nameECDsa_2, defaultECDsa);
+               unresolved_algorithms.Add (nameECDsa_3, defaultECDsa);
+
+               unresolved_algorithms.Add (nameSHA1Cng, defaultSHA1Cng);
+               unresolved_algorithms.Add (nameSHA256Cng, defaultSHA256Cng);
+               unresolved_algorithms.Add (nameSHA256Provider, defaultSHA256Provider);
+               unresolved_algorithms.Add (nameSHA384Cng, defaultSHA384Cng);
+               unresolved_algorithms.Add (nameSHA384Provider, defaultSHA384Provider);
+               unresolved_algorithms.Add (nameSHA512Cng, defaultSHA512Cng);
+               unresolved_algorithms.Add (nameSHA512Provider, defaultSHA512Provider);
+#endif
+               Dictionary<string,string> oid = new Dictionary<string, string> (StringComparer.OrdinalIgnoreCase);
 
-               oid = new Hashtable ();
                // comments here are to match with MS implementation (but not with doc)
                // LAMESPEC: only HashAlgorithm seems to have their OID included
-               oid.Add (defaultSHA1, oidSHA1);
+               oid.Add (nameSHA1, oidSHA1);
                oid.Add (managedSHA1, oidSHA1);
                oid.Add (nameSHA1b, oidSHA1);
                oid.Add (nameSHA1c, oidSHA1);
 
-               oid.Add (defaultMD5, oidMD5);
+               oid.Add (nameMD5, oidMD5);
                oid.Add (nameMD5a, oidMD5);
                oid.Add (nameMD5b, oidMD5);
 
-               oid.Add (defaultSHA256, oidSHA256);
+               oid.Add (nameSHA256, oidSHA256);
                oid.Add (nameSHA256a, oidSHA256);
                oid.Add (nameSHA256c, oidSHA256);
 
-               oid.Add (defaultSHA384, oidSHA384);
+               oid.Add (nameSHA384, oidSHA384);
                oid.Add (nameSHA384a, oidSHA384);
                oid.Add (nameSHA384c, oidSHA384);
 
-               oid.Add (defaultSHA512, oidSHA512);
+               oid.Add (nameSHA512, oidSHA512);
                oid.Add (nameSHA512a, oidSHA512);
                oid.Add (nameSHA512c, oidSHA512);
 
+               oid.Add (nameRIPEMD160, oidRIPEMD160);
+               oid.Add (nameRIPEMD160a, oidRIPEMD160);
+               oid.Add (nameRIPEMD160c, oidRIPEMD160);
+
                // surprise! documented in ".NET Framework Security" book
                oid.Add (name3DESKeyWrap, oid3DESKeyWrap);
 
-#if NET_2_0
-               oid.Add (nameRSAa, oidRSA);
-               oid.Add (nameDSAa, oidDSA);
                oid.Add (nameDESa, oidDES);
-               oid.Add (name3DESa, oid3DES);
                oid.Add (name3DESb, oid3DES);
                oid.Add (nameRC2a, oidRC2);
-#endif
 
                // Add/modify the config as specified by machine.config
                string config = Environment.GetMachineConfigPath ();
-               LoadConfig (config);
+               LoadConfig (config, algorithms, oid);
+
+               // update
+               CryptoConfig.algorithms = algorithms;
+               CryptoConfig.unresolved_algorithms = unresolved_algorithms;
+               CryptoConfig.oids = oid;
        }
 
        [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
-       private static void LoadConfig (string filename
+       private static void LoadConfig (string filename, IDictionary<string,Type> algorithms, IDictionary<string,string> oid)
        {
                if (!File.Exists (filename))
                        return;
 
-               SecurityParser sp = new SecurityParser ();
-               StreamReader sr = new StreamReader (filename);
                try {
-                       sp.LoadXml (sr.ReadToEnd ());
-               }
-               finally {
-                       sr.Close ();
-               }
-
-               try {
-                       SecurityElement root = sp.ToXml ();
-                       SecurityElement mscorlib = root.SearchForChildByTag ("mscorlib");
-                       if (mscorlib == null)
-                               return;
-                       SecurityElement cryptographySettings = mscorlib.SearchForChildByTag ("cryptographySettings");
-                       if (cryptographySettings == null)
-                               return;
-
-                       // algorithms
-                       SecurityElement cryptoNameMapping = cryptographySettings.SearchForChildByTag ("cryptoNameMapping");
-                       if (cryptoNameMapping != null) {
-                               SecurityElement cryptoClasses = cryptoNameMapping.SearchForChildByTag ("cryptoClasses");
-                               if (cryptoClasses != null) {
-                                       foreach (SecurityElement nameEntry in cryptoNameMapping.Children) {
-                                               if (nameEntry.Tag == "nameEntry") {
-                                                       string name = (string) nameEntry.Attributes ["name"];
-                                                       string clas = (string) nameEntry.Attributes ["class"];
-                                                       foreach (SecurityElement cryptoClass in cryptoClasses.Children) {
-                                                               string fullname = (string) cryptoClass.Attributes [clas];
-                                                               if (fullname != null) {
-                                                                       if (algorithms.ContainsKey (name)) 
-                                                                               algorithms.Remove (name);
-                                                                       algorithms.Add (name, fullname);
-                                                                       break;
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-
-                       // oid
-                       SecurityElement oidMap = cryptographySettings.SearchForChildByTag ("oidMap");
-                       if (oidMap == null)
-                               return;
-                       foreach (SecurityElement oidEntry in oidMap.Children) {
-                               if (oidEntry.Tag == "oidEntry") {
-                                       string oids = (string) oidEntry.Attributes ["OID"];
-                                       if (oid.ContainsKey (oids)) 
-                                               oid.Remove (oids);
-                                       oid.Add (oids, oidEntry.Attributes ["name"]);
-                               }
+                       using (TextReader reader = new StreamReader (filename)) {
+                               CryptoHandler handler = new CryptoHandler (algorithms, oid);
+                               SmallXmlParser parser = new SmallXmlParser ();
+                               parser.Parse (reader, handler);
                        }
                }
                catch {
-                       // there's no error/warning in case the machine.config contains bad entries
                }
        }
 
@@ -428,24 +485,27 @@ public class CryptoConfig {
        }
 
        [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
-       public static object CreateFromName (string name, object[] args)
+       public static object CreateFromName (string name, params object[] args)
        {
                if (name == null)
                        throw new ArgumentNullException ("name");
 
-               if (algorithms == null) {
-                       lock (lockObject) {
+               lock (lockObject) {
+                       if (algorithms == null) {
                                Initialize ();
                        }
                }
        
                try {
                        Type algoClass = null;
-                       string algo = (string) algorithms [name];
-                       // do we have an entry
-                       if (algo == null)
-                               algo = name;
-                       algoClass = Type.GetType (algo);
+                       if (!algorithms.TryGetValue (name, out algoClass)) {
+                               string algo = null;
+                               if (!unresolved_algorithms.TryGetValue (name, out algo))
+                                               algo = name;
+                               algoClass = Type.GetType (algo);
+                       }
+                       if (algoClass == null)
+                               return null;
                        // call the constructor for the type
                        return Activator.CreateInstance (algoClass, args);
                }
@@ -455,109 +515,183 @@ public class CryptoConfig {
                }
        }
 
-       // encode (7bits array) number greater than 127
-       private static byte[] EncodeLongNumber (long x)
+       public static string MapNameToOID (string name)
        {
-               // for MS BCL compatibility
-               // comment next two lines to remove restriction
-               if ((x > Int32.MaxValue) || (x < Int32.MinValue))
-                       throw new OverflowException (Locale.GetText ("Part of OID doesn't fit in Int32"));
-
-               long y = x;
-               // number of bytes required to encode this number
-               int n = 1;
-               while (y > 0x7F) {
-                       y = y >> 7;
-                       n++;
+               if (name == null)
+                       throw new ArgumentNullException ("name");
+
+               lock (lockObject) {
+                       if (oids == null) {
+                               Initialize ();
+                       }
                }
-               byte[] num = new byte [n];
-               // encode all bytes 
-               for (int i = 0; i < n; i++) {
-                       y = x >> (7 * i);
-                       y = y & 0x7F;
-                       if (i != 0)
-                               y += 0x80;
-                       num[n-i-1] = Convert.ToByte (y);
+                       
+               string result = null;
+               oids.TryGetValue (name, out result);
+               return result;
+       }
+
+#if NET_4_0
+       [MonoLimitation ("nothing is FIPS certified so it never make sense to restrict to this (empty) subset")]
+       public static bool AllowOnlyFipsAlgorithms {
+               get { return false; }
+       }
+
+       public static void AddAlgorithm (Type algorithm, params string[] names)
+       {
+               if (algorithm == null)
+                               throw new ArgumentNullException ("algorithm");
+               if (names  == null)
+                               throw new ArgumentNullException ("names");
+                       
+               foreach (string name in names) {
+                               if (String.IsNullOrWhiteSpace (name))
+                                       throw new ArithmeticException ("names");
+                               algorithms [name] = algorithm;
                }
-               return num;
        }
 
-       public static byte[] EncodeOID (string str)
+       public static void AddOID (string oid, params string[] names)
        {
-               char[] delim = { '.' };
-               string[] parts = str.Split (delim);
-               // according to X.208 n is always at least 2
-               if (parts.Length < 2) {
-                       throw new CryptographicUnexpectedOperationException (
-                               Locale.GetText ("OID must have at least two parts"));
+               if (oid == null)
+                               throw new ArgumentNullException ("oid");
+               if (names  == null)
+                               throw new ArgumentNullException ("names");
+                       
+               foreach (string name in names) {
+                               if (String.IsNullOrWhiteSpace (name))
+                                       throw new ArithmeticException ("names");
+                               oids [oid] = name;
                }
+       }
+#endif
 
-               // we're sure that the encoded OID is shorter than its string representation
-               byte[] oid = new byte [str.Length];
-               // now encoding value
-               try {
-                       byte part0 = Convert.ToByte (parts [0]);
-                       // OID[0] > 2 is invalid but "supported" in MS BCL
-                       // uncomment next line to trap this error
-                       // if (part0 > 2) throw new CryptographicUnexpectedOperationException ();
-                       byte part1 = Convert.ToByte (parts [1]);
-                       // OID[1] >= 40 is illegal for OID[0] < 2 because of the % 40
-                       // however the syntax is "supported" in MS BCL
-                       // uncomment next 2 lines to trap this error
-                       //if ((part0 < 2) && (part1 >= 40))
-                       //      throw new CryptographicUnexpectedOperationException ();
-                       oid[2] = Convert.ToByte (part0 * 40 + part1);
+       class CryptoHandler: SmallXmlParser.IContentHandler {
+
+               IDictionary<string,Type> algorithms;
+               IDictionary<string,string> oid;
+               Dictionary<string,string> names;
+               Dictionary<string,string> classnames;
+               int level;
+
+               public CryptoHandler (IDictionary<string,Type> algorithms, IDictionary<string,string> oid)
+               {
+                       this.algorithms = algorithms;
+                       this.oid = oid;
+                       // temporary tables to reconstruct algorithms
+                       names = new Dictionary<string,string> ();
+                       classnames = new Dictionary<string,string> ();
                }
-               catch {
-                       throw new CryptographicUnexpectedOperationException (
-                               Locale.GetText ("Invalid OID"));
+
+               public void OnStartParsing (SmallXmlParser parser)
+               {
+                       // don't care
                }
-               int j = 3;
-               for (int i = 2; i < parts.Length; i++) {
-                       long x = Convert.ToInt64 (parts [i]);
-                       if (x > 0x7F) {
-                               byte[] num = EncodeLongNumber (x);
-                               Buffer.BlockCopy (num, 0, oid, j, num.Length);
-                               j += num.Length;
+
+               public void OnEndParsing (SmallXmlParser parser)
+               {
+                       foreach (var kpv in names) {
+                               try {
+                                       algorithms [kpv.Key] = Type.GetType (classnames [kpv.Value]);
+                               }
+                               catch {
+                               }
                        }
-                       else
-                               oid[j++] = Convert.ToByte (x);
+                       // matching is done, data no more required
+                       names.Clear ();
+                       classnames.Clear ();
                }
 
-               int k = 2;
-               // copy the exact number of byte required
-               byte[] oid2 = new byte [j];
-               oid2[0] = 0x06; // always - this tag means OID
-               // Length (of value)
-               if (j > 0x7F) {
-                       // for compatibility with MS BCL
-                       throw new CryptographicUnexpectedOperationException (
-                               Locale.GetText ("OID > 127 bytes"));
-                       // comment exception and uncomment next 3 lines to remove restriction
-                       //byte[] num = EncodeLongNumber (j);
-                       //Buffer.BlockCopy (num, 0, oid, j, num.Length);
-                       //k = num.Length + 1;
+               private string Get (SmallXmlParser.IAttrList attrs, string name)
+               {
+                       for (int i = 0; i < attrs.Names.Length; i++) {
+                               if (attrs.Names[i] == name)
+                                       return attrs.Values[i];
+                       }
+                       return String.Empty;
                }
-               else
-                       oid2 [1] = Convert.ToByte (j - 2); 
-
-               Buffer.BlockCopy (oid, k, oid2, k, j - k);
-               return oid2;
-       }
 
-       public static string MapNameToOID (string name)
-       {
-               if (name == null)
-                       throw new ArgumentNullException ("name");
+               public void OnStartElement (string name, SmallXmlParser.IAttrList attrs)
+               {
+                       switch (level) {
+                       case 0:
+                               if (name == "configuration")
+                                       level++;
+                               break;
+                       case 1:
+                               if (name == "mscorlib")
+                                       level++;
+                               break;
+                       case 2:
+                               if (name == "cryptographySettings")
+                                       level++;
+                               break;
+                       case 3:
+                               if (name == "oidMap")
+                                       level++;
+                               else if (name == "cryptoNameMapping")
+                                       level++;
+                               break;
+                       case 4:
+                               if (name == "oidEntry") {
+                                       oid [Get (attrs, "name")] = Get (attrs, "OID");
+                               } else if (name == "nameEntry") {
+                                       names [Get (attrs, "name")] = Get (attrs, "class");
+                               } else if (name == "cryptoClasses") {
+                                       level++;
+                               }
+                               break;
+                       case 5:
+                               if (name == "cryptoClass")
+                                       classnames [attrs.Names[0]] = attrs.Values[0];
+                               break;
+                       }
+               }
 
-               if (oid == null) {
-                       lock (lockObject) {
-                               Initialize ();
+               public void OnEndElement (string name)
+               {
+                       // parser will make sure the XML structure is respected
+                       switch (level) {
+                       case 1:
+                               if (name == "configuration")
+                                       level--;
+                               break;
+                       case 2:
+                               if (name == "mscorlib")
+                                       level--;
+                               break;
+                       case 3:
+                               if (name == "cryptographySettings")
+                                       level--;
+                               break;
+                       case 4:
+                               if ((name == "oidMap") || (name == "cryptoNameMapping"))
+                                       level--;
+                               break;
+                       case 5:
+                               if (name == "cryptoClasses")
+                                       level--;
+                               break;
                        }
                }
 
-               return (string)oid [name];
+               public void OnProcessingInstruction (string name, string text)
+               {
+                       // don't care
+               }
+
+               public void OnChars (string text)
+               {
+                       // don't care
+               }
+
+               public void OnIgnorableWhitespace (string text)
+               {
+                       // don't care
+               }
        }
 }
-
 }
+
+#endif
+