Null constant cannot be used for ref/out variables
[mono.git] / mcs / tools / security / sn.cs
index 7ea5cabd9b14ce44bf0ceef5e7ad2cad3db7eaf5..28ee366d4e46d0efc9a5cfdf056cf2fd6d3af38a 100644 (file)
@@ -5,7 +5,7 @@
 //     Sebastien Pouliot  <sebastien@ximian.com>
 //
 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
+// Copyright (C) 2004-2006,2008 Novell, Inc (http://www.novell.com)
 //
 
 using System;
@@ -16,6 +16,7 @@ using System.Text;
 
 using Mono.Security;
 using Mono.Security.Cryptography;
+using Mono.Security.X509;
 
 [assembly: AssemblyTitle("Mono StrongName")]
 [assembly: AssemblyDescription("StrongName utility for signing assemblies")]
@@ -26,22 +27,12 @@ namespace Mono.Tools {
 
                static private void Header () 
                {
-                       Assembly a = Assembly.GetExecutingAssembly ();
-                       AssemblyName an = a.GetName ();
-               
-                       object [] att = a.GetCustomAttributes (typeof (AssemblyTitleAttribute), false);
-                       string title = ((att.Length > 0) ? ((AssemblyTitleAttribute) att [0]).Title : "Mono StrongName");
-
-                       att = a.GetCustomAttributes (typeof (AssemblyCopyrightAttribute), false);
-                       string copyright = ((att.Length > 0) ? ((AssemblyCopyrightAttribute) att [0]).Copyright : "");
-
-                       Console.WriteLine ("{0} {1}", title, an.Version.ToString ());
-                       Console.WriteLine ("{0}{1}", copyright, Environment.NewLine);
+                       Console.WriteLine (new AssemblyInfo ().ToString ());
                }
 
                static string defaultCSP;
 
-               static bool LoadConfig () 
+               static bool LoadConfig (bool quiet
                {
                        MethodInfo config = typeof (System.Environment).GetMethod ("GetMachineConfigPath",
                                BindingFlags.Static|BindingFlags.NonPublic);
@@ -49,9 +40,15 @@ namespace Mono.Tools {
                        if (config != null) {
                                string path = (string) config.Invoke (null, null);
 
+                               bool exist = File.Exists (path);
+                               if (!quiet && !exist)
+                                       Console.WriteLine ("Couldn't find machine.config");
+
                                StrongNameManager.LoadConfig (path);
-                               return true;
+                               return exist;
                        }
+                       else if (!quiet)
+                               Console.WriteLine ("Couldn't resolve machine.config location (corlib issue)");
                        
                        // default CSP
                        return false;
@@ -112,7 +109,8 @@ namespace Mono.Tools {
                                if ((i % 39 == 0) && (data.Length > 39))
                                        sb.Append (Environment.NewLine);
                                sb.Append (data [i].ToString ("x2"));
-                               if (i > 1000) {
+                               if (i > 2080) {
+                                       // ensure we can display up to 16384 bits keypair
                                        sb.Append (" !!! TOO LONG !!!");
                                        break;
                                }
@@ -120,6 +118,29 @@ namespace Mono.Tools {
                        return sb.ToString ();
                }
 
+               static RSA GetKeyFromFile (string filename)
+               {
+                       byte[] data = ReadFromFile (filename);
+                       try {
+                               // for SNK files (including the ECMA pseudo-key)
+                               return new StrongName (data).RSA;
+                       }
+                       catch {
+                               if (data [0] != 0x30)
+                                       throw;
+                               // this could be a PFX file
+                               Console.Write ("Enter password for private key (will be visible when typed): ");
+                               PKCS12 pfx = new PKCS12 (data, Console.ReadLine ());
+                               // works only if a single key is present
+                               if (pfx.Keys.Count != 1)
+                                       throw;
+                               RSA rsa = (pfx.Keys [0] as RSA);
+                               if (rsa == null)
+                                       throw;
+                               return rsa;
+                       }
+               }
+#if false
                // is assembly signed (or delayed signed) ?
                static bool IsStrongNamed (Assembly assembly) 
                {
@@ -135,12 +156,17 @@ namespace Mono.Tools {
                        }
                        return false;
                }
-
+#endif
                static bool ReSign (string assemblyName, RSA key) 
                {
                        // this doesn't load the assembly (well it unloads it ;)
                        // http://weblogs.asp.net/nunitaddin/posts/9991.aspx
-                       AssemblyName an = AssemblyName.GetAssemblyName (assemblyName);
+                       AssemblyName an = null;
+                       try {
+                               an = AssemblyName.GetAssemblyName (assemblyName);
+                       }
+                       catch {
+                       }
                        if (an == null) {
                                Console.WriteLine ("Unable to load assembly: {0}", assemblyName);
                                return false;
@@ -175,7 +201,12 @@ namespace Mono.Tools {
                {
                        // this doesn't load the assembly (well it unloads it ;)
                        // http://weblogs.asp.net/nunitaddin/posts/9991.aspx
-                       AssemblyName an = AssemblyName.GetAssemblyName (assemblyName);
+                       AssemblyName an = null;
+                       try {
+                               an = AssemblyName.GetAssemblyName (assemblyName);
+                       }
+                       catch {
+                       }
                        if (an == null) {
                                Console.WriteLine ("Unable to load assembly: {0}", assemblyName);
                                return 2;
@@ -192,7 +223,7 @@ namespace Mono.Tools {
                        }
 
                        // Note: MustVerify is based on the original token (by design). Public key
-                       // remapping won't affect if the assebmly is verified or not.
+                       // remapping won't affect if the assembly is verified or not.
                        if (forceVerification || StrongNameManager.MustVerify (an)) {
                                RSA rsa = CryptoConvert.FromCapiPublicKeyBlob (publicKey, 12);
                                StrongName sn = new StrongName (rsa);
@@ -201,7 +232,7 @@ namespace Mono.Tools {
                                        return 0;
                                }
                                else {
-                                       Console.WriteLine ("Assembly {0} isn't strongnamed", assemblyName);
+                                       Console.WriteLine ("Assembly {0} is delay-signed but not strongnamed", assemblyName);
                                        return 1;
                                }
                        }
@@ -238,6 +269,7 @@ namespace Mono.Tools {
                                        Console.WriteLine (" -Vr assembly [userlist]{0}\tExempt the specified assembly from verification for the user list", Environment.NewLine);
                                        Console.WriteLine (" -Vu assembly{0}\tRemove exemption entry for the specified assembly", Environment.NewLine);
                                        Console.WriteLine (" -Vx{0}\tRemove all exemptions entries", Environment.NewLine);
+                                       Console.WriteLine ("{0}<1> Currently not implemented in the tool", Environment.NewLine);
                                        break;
                                case "csp":
                                        Console.WriteLine ("CSP related options");
@@ -258,9 +290,9 @@ namespace Mono.Tools {
                                        Console.WriteLine (" -k keypair.snk{0}\tCreate a new keypair in the specified file", Environment.NewLine);
                                        Console.WriteLine (" -R assembly keypair.snk{0}\tResign the assembly with the specified StrongName key file", Environment.NewLine);
                                        Console.WriteLine (" -Rc assembly container{0}\tResign the assembly with the specified CSP container", Environment.NewLine);
-                                       Console.WriteLine (" -t file{0}\tShow the public key from the specified file", Environment.NewLine);
+                                       Console.WriteLine (" -t file{0}\tShow the public key token from the specified file", Environment.NewLine);
                                        Console.WriteLine (" -tp file{0}\tShow the public key and pk token from the specified file", Environment.NewLine);
-                                       Console.WriteLine (" -T assembly{0}\tShow the public key from the specified assembly", Environment.NewLine);
+                                       Console.WriteLine (" -T assembly{0}\tShow the public key token from the specified assembly", Environment.NewLine);
                                        Console.WriteLine (" -Tp assembly{0}\tShow the public key and pk token from the specified assembly", Environment.NewLine);
                                        Console.WriteLine (" -v assembly{0}\tVerify the specified assembly signature", Environment.NewLine);
                                        Console.WriteLine (" -vf assembly{0}\tVerify the specified assembly signature (even if disabled).", Environment.NewLine);
@@ -274,18 +306,10 @@ namespace Mono.Tools {
                                        Console.WriteLine (" -? | -h sn     \tStrongName signing options");
                                        break;
                        }
-                       Console.WriteLine ("{0}<1> Currently not implemented in the tool", Environment.NewLine);
                }
 
-               [STAThread]
-               static int Main (string[] args)
+               static int Process (string[] args)
                {
-                       if (args.Length < 1) {
-                               Header ();
-                               Help (null);
-                               return 1;
-                       }
-
                        int i = 0;
                        string param = args [i];
                        bool quiet = ((param == "-quiet") || (param == "-q"));
@@ -294,7 +318,7 @@ namespace Mono.Tools {
                        else
                                Header();
 
-                       bool config = LoadConfig ();
+                       LoadConfig (quiet);
 
                        StrongName sn = null;
                        AssemblyName an = null;
@@ -344,10 +368,20 @@ namespace Mono.Tools {
                                case "-k":
                                        // Create a new strong name key pair
                                        // (a new RSA keypair automagically if none is present)
-                                       sn = new StrongName ();
+                                       int size = 1024;
+                                       if (i < args.Length + 2) {
+                                               try {
+                                                       size = Int32.Parse (args[i++]);
+                                               }
+                                               catch {
+                                                       // oops, that wasn't a valid key size (assume 1024 bits)
+                                                       i--;
+                                               }
+                                       }
+                                       sn = new StrongName (size);
                                        WriteToFile (args[i], CryptoConvert.ToCapiKeyBlob (sn.RSA, true));
                                        if (!quiet)
-                                               Console.WriteLine ("A new strong name keypair has been generated in {0}", args [i]);
+                                               Console.WriteLine ("A new {0} bits strong name keypair has been generated in file '{1}'.", size, args [i]);
                                        break;
                                case "-m":
                                        Console.WriteLine ("Unimplemented option");
@@ -356,7 +390,7 @@ namespace Mono.Tools {
                                        byte[] infileD = ReadFromFile (args [i++]);
                                        WriteCSVToFile (args [i], infileD, "D");
                                        if (!quiet)
-                                               Console.WriteLine ("Output CVS file is {0} (decimal format)", args [i]);
+                                               Console.WriteLine ("Output CSV file is {0} (decimal format)", args [i]);
                                        break;
                                case "-oh":
                                        byte[] infileX2 = ReadFromFile (args [i++]);
@@ -365,8 +399,8 @@ namespace Mono.Tools {
                                                Console.WriteLine ("Output CVS file is {0} (hexadecimal format)", args [i]);
                                        break;
                                case "-p":
-                                       // Extract public key from SNK file
-                                       sn = new StrongName (ReadFromFile (args [i++]));
+                                       // Extract public key from SNK or PKCS#12/PFX file
+                                       sn = new StrongName (GetKeyFromFile (args [i++]));
                                        WriteToFile (args[i], sn.PublicKey);
                                        if (!quiet)
                                                Console.WriteLine ("Public Key extracted to file {0}", args [i]);
@@ -382,8 +416,7 @@ namespace Mono.Tools {
                                        break;
                                case "-R":
                                        string filename = args [i++];
-                                       sn = new StrongName (ReadFromFile (args [i]));
-                                       if (! ReSign (filename, sn.RSA))
+                                       if (! ReSign (filename, GetKeyFromFile (args [i])))
                                                return 1;
                                        break;
                                case "-Rc":
@@ -458,5 +491,30 @@ namespace Mono.Tools {
                        }
                        return 0;
                }
+
+               [STAThread]
+               static int Main (string[] args)
+               {
+                       try {
+                               if (args.Length < 1) {
+                                       Header ();
+                                       Help (null);
+                               } else {
+                                       return Process (args);
+                               }
+                       }
+                       catch (IndexOutOfRangeException) {
+                               Console.WriteLine ("ERROR: Invalid number of parameters.{0}", Environment.NewLine);
+                               Help (null);
+                       }
+                       catch (CryptographicException ce) {
+                               Console.WriteLine ("ERROR: {0}", ce.Message);
+                       }
+                       catch (Exception e) {
+                               Console.WriteLine ("ERROR: Unknown error during processing: {0}", e);
+                       }
+
+                       return 1;
+               }
        }
 }