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 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 md5 | sha1\tHash Algorithm (default: MD5)");
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);
65 PrivateKey pvk = PrivateKey.CreateFromFile (keyfile);
67 Console.WriteLine ("Enter password for {0}: ", keyfile);
68 string password = Console.ReadLine ();
69 pvk = PrivateKey.CreateFromFile (keyfile, password);
71 Console.WriteLine ("Invalid password!");
76 rsa = new RSACryptoServiceProvider (csp);
82 static private X509CertificateCollection GetCertificates (string spcfile)
84 if (spcfile == null) {
85 Console.WriteLine ("Missing SPC (certificate) file.");
88 if (!File.Exists (spcfile)) {
89 Console.WriteLine ("Couldn't find '{0}' file.", spcfile);
93 SoftwarePublisherCertificate spc = SoftwarePublisherCertificate.CreateFromFile (spcfile);
94 return spc.Certificates;
98 static int Main(string[] args)
101 if (args.Length < 1) {
106 CspParameters csp = new CspParameters ();
107 string pvkFilename = null;
108 string spcFilename = null;
109 int timestampRetry = 1;
110 int timestampDelay = 0;
114 string tbsFilename = args [args.Length - 1];
116 AuthenticodeFormatter af = new AuthenticodeFormatter ();
119 while (i < args.Length - 1) {
122 spcFilename = args [i++];
125 pvkFilename = args [i++];
128 af.Hash = args [i++];
131 string auth = args [i++].ToLower ();
134 af.Authority = Authority.Commercial;
137 af.Authority = Authority.Individual;
140 Console.WriteLine ("Unknown authority {0}", auth);
145 af.Description = args [i++];
148 af.Url = new Uri (args [i++]);
152 af.TimestampUrl = new Uri (args [i++]);
155 timestampRetry = Convert.ToInt32 (args [i++]);
158 timestampDelay = Convert.ToInt32 (args [i++]) * 1000;
164 // CSP provider options
166 csp.KeyContainerName = args [i++];
169 csp.ProviderName = args [i++];
172 csp.ProviderType = Convert.ToInt32 (args [i++]);
175 string key = args [i++];
184 csp.KeyNumber = Convert.ToInt32 (key);
189 string location = args [i++];
192 csp.Flags = CspProviderFlags.UseMachineKeyStore;
195 csp.Flags = CspProviderFlags.UseDefaultKeyContainer;
198 Console.WriteLine ("Unknown location {0}", location);
202 // unsupported options
205 Console.WriteLine ("Unsupported option {0}", args[i-1]);
214 // no need to continue if we can't find the assembly
215 // to be signed (and/or timestamped)
216 if (!File.Exists (tbsFilename)) {
217 Console.WriteLine ("Couldn't find {0}.", tbsFilename);
222 RSA rsa = GetPrivateKey (pvkFilename, csp);
224 Console.WriteLine ("No private key available to sign the assembly.");
229 X509CertificateCollection certs = GetCertificates (spcFilename);
230 if ((certs == null) || (certs.Count == 0)) {
231 Console.WriteLine ("No certificates available to sign the assembly.");
234 af.Certificates.AddRange (certs);
\r
236 if (!af.Sign (tbsFilename)) {
\r
237 Console.WriteLine ("Couldn't sign file '{0}'.", tbsFilename);
\r
240 } else if (af.TimestampUrl != null) {
\r
242 // only timestamp an already signed file
\r
243 for (int j = 0; j < timestampRetry && !ts; j++) {
\r
244 ts = af.Timestamp (tbsFilename);
\r
245 // wait (unless it's the last try) and retry
\r
246 if (!ts && (j < timestampRetry - 1)) {
\r
247 Console.WriteLine ("Couldn't timestamp file '{0}', will retry in {1} ms", tbsFilename, timestampDelay);
\r
248 Thread.Sleep (timestampDelay);
\r
252 Console.WriteLine ("Couldn't timestamp file '{0}' after {1} retries.", tbsFilename, timestampRetry);
\r
260 Console.WriteLine ("Success");