Add a tool which can sync the Mono cert store from an arbitrary cert bundle (i.e...
[mono.git] / mcs / tools / security / sn.cs
index 5127b713790e0276ddb8d7a87837df1019273871..4f6660077050d007c56f426b49c7265bf1271f60 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,17 +27,7 @@ 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;
@@ -118,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;
                                }
@@ -126,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.Length == 0 || 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) 
                {
@@ -141,12 +156,17 @@ namespace Mono.Tools {
                        }
                        return false;
                }
-
-               static bool ReSign (string assemblyName, RSA key) 
+#endif
+               static bool ReSign (string assemblyName, RSA key, bool quiet
                {
                        // 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;
@@ -168,8 +188,10 @@ namespace Mono.Tools {
 
                        if (same) {
                                bool signed = sign.Sign (assemblyName);
-                               Console.WriteLine (signed ? "Assembly {0} signed." : "Couldn't sign the assembly {0}.", 
-                                                  assemblyName);
+                               if (!quiet || !signed) {
+                                       Console.WriteLine (signed ? "Assembly {0} signed." : "Couldn't sign the assembly {0}.", 
+                                                          assemblyName);
+                               }
                                return signed;
                        }
                        
@@ -177,11 +199,16 @@ namespace Mono.Tools {
                        return false;
                }
 
-               static int Verify (string assemblyName, bool forceVerification) 
+               static int Verify (string assemblyName, bool forceVerification, bool quiet
                {
                        // 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;
@@ -198,16 +225,17 @@ 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);
                                if (sn.Verify (assemblyName)) {
-                                       Console.WriteLine ("Assembly {0} is strongnamed.", assemblyName);
+                                       if (!quiet)
+                                               Console.WriteLine ("Assembly {0} is strongnamed.", assemblyName);
                                        return 0;
                                }
                                else {
-                                       Console.WriteLine ("Assembly {0} isn't strongnamed", assemblyName);
+                                       Console.WriteLine ("Assembly {0} is delay-signed but not strongnamed", assemblyName);
                                        return 1;
                                }
                        }
@@ -244,6 +272,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");
@@ -264,9 +293,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);
@@ -280,18 +309,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"));
@@ -300,7 +321,7 @@ namespace Mono.Tools {
                        else
                                Header();
 
-                       bool config = LoadConfig (quiet);
+                       LoadConfig (quiet);
 
                        StrongName sn = null;
                        AssemblyName an = null;
@@ -350,10 +371,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");
@@ -362,7 +393,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++]);
@@ -371,8 +402,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]);
@@ -388,15 +419,14 @@ 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]), quiet))
                                                return 1;
                                        break;
                                case "-Rc":
                                        filename = args [i++];
                                        csp.KeyContainerName = args [i];
                                        rsa = new RSACryptoServiceProvider (csp);
-                                       if (! ReSign (filename, rsa))
+                                       if (! ReSign (filename, rsa, quiet))
                                                return 1;
                                        break;
                                case "-t":
@@ -436,10 +466,10 @@ namespace Mono.Tools {
                                        break;
                                case "-v":
                                        filename = args [i++];
-                                       return Verify (filename, false);
+                                       return Verify (filename, false, quiet);
                                case "-vf":
                                        filename = args [i++];
-                                       return Verify (filename, true); // force verification
+                                       return Verify (filename, true, quiet);  // force verification
                                case "-Vl":
                                        Console.WriteLine (new StrongNameManager ().ToString ());
                                        break;
@@ -464,5 +494,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;
+               }
        }
 }