2005-06-10 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / System.Security.Cryptography / CryptoConfig.cs
index d7741c1947eb937ce3b182eda8216c8847f8f39e..e51ce0f45f0b0ff661156a77772a32a112b7d7ac 100644 (file)
@@ -1,25 +1,53 @@
 //
-// CryptoConfig.cs: Handles cryptographic implementations and OIDs.
+// CryptoConfig.cs: Handles cryptographic implementations and OIDs mappings.
 //
 // Author:
-//     Sebastien Pouliot (spouliot@motus.com)
+//     Sebastien Pouliot (sebastien@ximian.com)
+//     Tim Coleman (tim@timcoleman.com)
 //
 // (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)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.Collections;
+using System.Globalization;
 using System.IO;
 using System.Reflection;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Permissions;
 using System.Text;
 
 using Mono.Xml;
 
 namespace System.Security.Cryptography {
 
+#if NET_2_0
+[ComVisible (true)]
+#endif
 public class CryptoConfig {
 
+       static private object lockObject;
        static private Hashtable algorithms;
        static private Hashtable oid;
 
@@ -42,14 +70,37 @@ public class CryptoConfig {
        // 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
+
        // 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
+
        // LAMESPEC: only documentated in ".NET Framework Security" book
        private const string defaultX509Data = defaultNamespace + "Xml.KeyInfoX509Data" + xmlAssembly;
        private const string defaultKeyName = defaultNamespace + "Xml.KeyInfoName" + xmlAssembly;
@@ -62,9 +113,22 @@ public class CryptoConfig {
        // 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";
+       // 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 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";
 
@@ -103,12 +167,29 @@ public class CryptoConfig {
        private const string nameRNGa = "RandomNumberGenerator";
        private const string nameRNGb = "System.Security.Cryptography.RandomNumberGenerator";
        private const string nameKeyHasha = "System.Security.Cryptography.KeyedHashAlgorithm";
-       private const string nameHMACa = "HMACSHA1";
-       private const string nameHMACb = "System.Security.Cryptography.HMACSHA1";
+       private const string nameHMACSHA1a = "HMACSHA1";
+       private const string nameHMACSHA1b = "System.Security.Cryptography.HMACSHA1";
        private const string nameMAC3DESa = "MACTripleDES";
        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 nameRIPEMD160a = "RIPEMD160";
+       private const string nameRIPEMD160b = "RIPEMD-160";
+       private const string nameRIPEMD160c = "System.Security.Cryptography.RIPEMD160";
+       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";
+       private const string nameHMACRIPEMD160a = "HMACRIPEMD160";
+       private const string nameHMACRIPEMD160b = "System.Security.Cryptography.HMACRIPEMD160";
+       private const string nameHMACSHA256a = "HMACSHA256";
+       private const string nameHMACSHA256b = "System.Security.Cryptography.HMACSHA256";
+       private const string nameHMACSHA384a = "HMACSHA384";
+       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
@@ -121,6 +202,12 @@ 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
+
        // LAMESPEC: only documentated in ".NET Framework Security" book
        private const string urlX509Data = urlXmlDsig + " X509Data";                    // space is required
        private const string urlKeyName = urlXmlDsig + " KeyName";                      // space is required
@@ -128,9 +215,16 @@ public class CryptoConfig {
        private const string urlKeyValueRSA = urlXmlDsig + " KeyValue/RSAKeyValue";     // space is required
        private const string urlRetrievalMethod = urlXmlDsig + " RetrievalMethod";      // space is required
 
-       static CryptoConfig ()
+       static CryptoConfig () 
        {
-               algorithms = new Hashtable ();
+               // lock(this) is bad
+               // http://msdn.microsoft.com/library/en-us/dnaskdr/html/askgui06032003.asp?frame=true
+               lockObject = new object ();
+       }
+
+       private static void Initialize () 
+       {
+               Hashtable algorithms = new Hashtable ();
                // see list @ http://msdn.microsoft.com/library/en-us/cpref/html/
                // frlrfSystemSecurityCryptographyCryptoConfigClassTopic.asp
                algorithms.Add (nameSHA1a, defaultSHA1);
@@ -159,15 +253,15 @@ public class CryptoConfig {
 
                algorithms.Add (nameDSAa, defaultDSA);  
                algorithms.Add (nameDSAb, defaultDSA);  
-       
+
                algorithms.Add (nameDESa, defaultDES);
                algorithms.Add (nameDESb, defaultDES);
-       
+
                algorithms.Add (name3DESa, default3DES);
                algorithms.Add (name3DESb, default3DES);
                algorithms.Add (name3DESc, default3DES);
                algorithms.Add (name3DESd, default3DES);
-       
+
                algorithms.Add (nameRC2a, defaultRC2);
                algorithms.Add (nameRC2b, defaultRC2);
 
@@ -181,10 +275,26 @@ public class CryptoConfig {
                algorithms.Add (nameRNGa, defaultRNG);
                algorithms.Add (nameRNGb, defaultRNG);
                algorithms.Add (nameKeyHasha, defaultHMAC);
-               algorithms.Add (nameHMACa, defaultHMAC);
-               algorithms.Add (nameHMACb, defaultHMAC);
+               algorithms.Add (nameHMACSHA1a, defaultHMAC);
+               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);
+               algorithms.Add (nameHMACb, defaultHMAC);
+               algorithms.Add (nameHMACMD5a, defaultHMACMD5);
+               algorithms.Add (nameHMACMD5b, defaultHMACMD5);
+               algorithms.Add (nameHMACRIPEMD160a, defaultHMACRIPEMD160);
+               algorithms.Add (nameHMACRIPEMD160b, defaultHMACRIPEMD160);
+               algorithms.Add (nameHMACSHA256a, defaultHMACSHA256);
+               algorithms.Add (nameHMACSHA256b, defaultHMACSHA256);
+               algorithms.Add (nameHMACSHA384a, defaultHMACSHA384);
+               algorithms.Add (nameHMACSHA384b, defaultHMACSHA384);
+               algorithms.Add (nameHMACSHA512a, defaultHMACSHA512);
+               algorithms.Add (nameHMACSHA512b, defaultHMACSHA512);
+#endif
 
                // 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
@@ -198,6 +308,11 @@ public class CryptoConfig {
                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
                // LAMESPEC: only documentated in ".NET Framework Security" book
                algorithms.Add (urlX509Data, defaultX509Data);
                algorithms.Add (urlKeyName, defaultKeyName);
@@ -205,7 +320,7 @@ public class CryptoConfig {
                algorithms.Add (urlKeyValueRSA, defaultKeyValueRSA);
                algorithms.Add (urlRetrievalMethod, defaultRetrievalMethod);
 
-               oid = new Hashtable ();
+               Hashtable 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);
@@ -232,14 +347,26 @@ public class CryptoConfig {
                // 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 = GetMachineConfigPath ();
-               // debug @"D:\Program Files\Mono-0.25\etc\mono\machine.config";
-               if (config != null)
-                       LoadConfig (config);
+               string config = Environment.GetMachineConfigPath ();
+               LoadConfig (config, algorithms, oid);
+
+               // update
+               CryptoConfig.algorithms = algorithms;
+               CryptoConfig.oid = oid;
        }
 
-       internal static void LoadConfig (string filename) 
+       [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
+       private static void LoadConfig (string filename, Hashtable algorithms, Hashtable oid)
        {
                if (!File.Exists (filename))
                        return;
@@ -303,36 +430,22 @@ public class CryptoConfig {
                }
        }
 
-       // managed version of "get_machine_config_path"
-       internal static string GetMachineConfigPath () 
-       {
-               string env = Environment.GetEnvironmentVariable ("MONO_CONFIG");
-               if (env != null)
-                       return env;
-               env = Environment.GetEnvironmentVariable ("MONO_BASEPATH");
-               if (env == null)
-                       return null;
-
-               StringBuilder sb = new StringBuilder ();
-               sb.Append (env);
-               sb.Append (Path.DirectorySeparatorChar);
-               sb.Append ("etc");
-               sb.Append (Path.DirectorySeparatorChar);
-               sb.Append ("mono");
-               sb.Append (Path.DirectorySeparatorChar);
-               sb.Append ("machine.config");
-               return sb.ToString ();
-       }
-
        public static object CreateFromName (string name)
        {
                return CreateFromName (name, null);
        }
 
+       [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
        public static object CreateFromName (string name, object[] args)
        {
                if (name == null)
-                       throw new ArgumentNullException ();
+                       throw new ArgumentNullException ("name");
+
+               lock (lockObject) {
+                       if (algorithms == null) {
+                               Initialize ();
+                       }
+               }
        
                try {
                        Type algoClass = null;
@@ -345,7 +458,7 @@ public class CryptoConfig {
                        return Activator.CreateInstance (algoClass, args);
                }
                catch {
-                       // method deosn't throw any exception
+                       // method doesn't throw any exception
                        return null;
                }
        }
@@ -356,7 +469,7 @@ public class CryptoConfig {
                // for MS BCL compatibility
                // comment next two lines to remove restriction
                if ((x > Int32.MaxValue) || (x < Int32.MinValue))
-                       throw new OverflowException ("part of OID doesn't fit in Int32");
+                       throw new OverflowException (Locale.GetText ("Part of OID doesn't fit in Int32"));
 
                long y = x;
                // number of bytes required to encode this number
@@ -379,11 +492,18 @@ public class CryptoConfig {
 
        public static byte[] EncodeOID (string str)
        {
+#if NET_2_0
+               if (str == null)
+                       throw new ArgumentNullException ("str");
+#endif
                char[] delim = { '.' };
                string[] parts = str.Split (delim);
                // according to X.208 n is always at least 2
-               if (parts.Length < 2)
-                       throw new CryptographicUnexpectedOperationException ();
+               if (parts.Length < 2) {
+                       throw new CryptographicUnexpectedOperationException (
+                               Locale.GetText ("OID must have at least two parts"));
+               }
+
                // we're sure that the encoded OID is shorter than its string representation
                byte[] oid = new byte [str.Length];
                // now encoding value
@@ -401,14 +521,15 @@ public class CryptoConfig {
                        oid[2] = Convert.ToByte (part0 * 40 + part1);
                }
                catch {
-                       throw new CryptographicUnexpectedOperationException ();
+                       throw new CryptographicUnexpectedOperationException (
+                               Locale.GetText ("Invalid OID"));
                }
                int j = 3;
                for (int i = 2; i < parts.Length; i++) {
-                       long x = Convert.ToInt64parts [i]);
+                       long x = Convert.ToInt64 (parts [i]);
                        if (x > 0x7F) {
                                byte[] num = EncodeLongNumber (x);
-                               Array.Copy(num, 0, oid, j, num.Length);
+                               Buffer.BlockCopy (num, 0, oid, j, num.Length);
                                j += num.Length;
                        }
                        else
@@ -422,16 +543,17 @@ public class CryptoConfig {
                // Length (of value)
                if (j > 0x7F) {
                        // for compatibility with MS BCL
-                       throw new CryptographicUnexpectedOperationException ("OID > 127 bytes");
+                       throw new CryptographicUnexpectedOperationException (
+                               Locale.GetText ("OID > 127 bytes"));
                        // comment exception and uncomment next 3 lines to remove restriction
                        //byte[] num = EncodeLongNumber (j);
-                       //Array.Copy (num, 0, oid, j, num.Length);
+                       //Buffer.BlockCopy (num, 0, oid, j, num.Length);
                        //k = num.Length + 1;
                }
                else
                        oid2 [1] = Convert.ToByte (j - 2); 
 
-               Array.Copy (oid, k, oid2, k, j - k);
+               Buffer.BlockCopy (oid, k, oid2, k, j - k);
                return oid2;
        }
 
@@ -440,8 +562,14 @@ public class CryptoConfig {
                if (name == null)
                        throw new ArgumentNullException ("name");
 
+               lock (lockObject) {
+                       if (oid == null) {
+                               Initialize ();
+                       }
+               }
+
                return (string)oid [name];
        }
 }
 
-}
\ No newline at end of file
+}