2 // SignCode.cs: secutil clone tool
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004,2006-2007 Novell, Inc (http://www.novell.com)
13 using System.Reflection;
14 using System.Security.Cryptography;
16 using System.Threading;
18 using Mono.Security.Authenticode;
19 using Mono.Security.X509;
21 [assembly: AssemblyTitle("Mono SignCode")]
22 [assembly: AssemblyDescription("Sign assemblies and PE files using Authenticode(tm).")]
24 namespace Mono.Tools {
28 static private void Header ()
30 Console.WriteLine (new AssemblyInfo ().ToString ());
33 static private void Help ()
35 Console.WriteLine ("Usage: signcode [options] filename{0}", Environment.NewLine);
36 Console.WriteLine ("\t-spc spc\tSoftware Publisher Certificate file");
37 Console.WriteLine ("\t-v pvk\t\tPrivate Key file");
38 Console.WriteLine ("\t-a sha1 | md5\tHash Algorithm (default: SHA1)");
39 Console.WriteLine ("\t-$ indivisual | commercial\tSignature type");
40 Console.WriteLine ("\t-n description\tDescription for the signed file");
41 Console.WriteLine ("\t-i url\tURL for the signed file");
42 Console.WriteLine ("Timestamp options");
43 Console.WriteLine ("\t-t url\tTimestamp service http URL");
44 Console.WriteLine ("\t-tr #\tNumber of retries for timestamp");
45 Console.WriteLine ("\t-tw #\tDelay between retries");
46 Console.WriteLine ("\t-x\tOnly timestamp (no signature)");
47 Console.WriteLine ("CSP options");
48 Console.WriteLine ("\t-k name\tKey Container Name");
49 Console.WriteLine ("\t-p name\tProvider Name");
50 Console.WriteLine ("\t-y #\tProvider Type");
51 Console.WriteLine ("\t-ky [signature|exchange|#]\tKey Type");
52 Console.WriteLine ("\t-r [localMachine|currentUser]\tKey Location");
55 static private RSA GetPrivateKey (string keyfile, CspParameters csp)
59 if (keyfile != null) {
60 if (!File.Exists (keyfile)) {
61 Console.WriteLine ("Couldn't find '{0}' file.", keyfile);
66 PrivateKey pvk = PrivateKey.CreateFromFile (keyfile);
69 catch (CryptographicException) {
70 Console.WriteLine ("Enter password for {0}: ", keyfile);
71 string password = Console.ReadLine ();
73 PrivateKey pvk = PrivateKey.CreateFromFile (keyfile, password);
76 catch (CryptographicException) {
77 Console.WriteLine ("Invalid password!");
82 rsa = new RSACryptoServiceProvider (csp);
88 static private X509CertificateCollection GetCertificates (string spcfile)
90 if (spcfile == null) {
91 Console.WriteLine ("Missing SPC (certificate) file.");
94 if (!File.Exists (spcfile)) {
95 Console.WriteLine ("Couldn't find '{0}' file.", spcfile);
99 SoftwarePublisherCertificate spc = SoftwarePublisherCertificate.CreateFromFile (spcfile);
100 return spc.Certificates;
104 static int Main(string[] args)
107 if (args.Length < 1) {
112 CspParameters csp = new CspParameters ();
113 string pvkFilename = null;
114 string spcFilename = null;
115 int timestampRetry = 1;
116 int timestampDelay = 0;
120 string tbsFilename = args [args.Length - 1];
122 AuthenticodeFormatter af = new AuthenticodeFormatter ();
125 while (i < args.Length - 1) {
128 spcFilename = args [i++];
131 pvkFilename = args [i++];
134 af.Hash = args [i++];
137 string auth = args [i++].ToLower ();
140 af.Authority = Authority.Individual;
143 af.Authority = Authority.Commercial;
146 Console.WriteLine ("Unknown authority {0}", auth);
151 af.Description = args [i++];
154 af.Url = new Uri (args [i++]);
158 af.TimestampUrl = new Uri (args [i++]);
161 timestampRetry = Convert.ToInt32 (args [i++]);
164 timestampDelay = Convert.ToInt32 (args [i++]) * 1000;
170 // CSP provider options
172 csp.KeyContainerName = args [i++];
175 csp.ProviderName = args [i++];
178 csp.ProviderType = Convert.ToInt32 (args [i++]);
181 string key = args [i++];
190 csp.KeyNumber = Convert.ToInt32 (key);
195 string location = args [i++];
198 csp.Flags = CspProviderFlags.UseMachineKeyStore;
201 csp.Flags = CspProviderFlags.UseDefaultKeyContainer;
204 Console.WriteLine ("Unknown location {0}", location);
208 // unsupported options
211 Console.WriteLine ("Unsupported option {0}", args[i-1]);
220 // no need to continue if we can't find the assembly
221 // to be signed (and/or timestamped)
222 if (!File.Exists (tbsFilename)) {
223 Console.WriteLine ("Couldn't find {0}.", tbsFilename);
228 RSA rsa = GetPrivateKey (pvkFilename, csp);
230 Console.WriteLine ("No private key available to sign the assembly.");
235 X509CertificateCollection certs = GetCertificates (spcFilename);
236 if ((certs == null) || (certs.Count == 0)) {
237 Console.WriteLine ("No certificates available to sign the assembly.");
240 af.Certificates.AddRange (certs);
242 if (!af.Sign (tbsFilename)) {
243 Console.WriteLine ("Couldn't sign file '{0}'.", tbsFilename);
246 } else if (af.TimestampUrl != null) {
248 // only timestamp an already signed file
249 for (int j = 0; j < timestampRetry && !ts; j++) {
250 ts = af.Timestamp (tbsFilename);
251 // wait (unless it's the last try) and retry
252 if (!ts && (j < timestampRetry - 1)) {
253 Console.WriteLine ("Couldn't timestamp file '{0}', will retry in {1} ms", tbsFilename, timestampDelay);
254 Thread.Sleep (timestampDelay);
258 Console.WriteLine ("Couldn't timestamp file '{0}' after {1} retries.", tbsFilename, timestampRetry);
266 Console.WriteLine ("Success");