2010-05-25 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / security / signcode.cs
blobf6df11103bc8b14f4e96963e904b49e2ca4058b6
1 //
2 // SignCode.cs: secutil clone tool
3 //
4 // Author:
5 // Sebastien Pouliot <sebastien@ximian.com>
6 //
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004,2006-2007 Novell, Inc (http://www.novell.com)
9 //
11 using System;
12 using System.IO;
13 using System.Reflection;
14 using System.Security.Cryptography;
15 using System.Text;
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 {
26 class SignCode {
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)
57 RSA rsa = null;
59 if (keyfile != null) {
60 if (!File.Exists (keyfile)) {
61 Console.WriteLine ("Couldn't find '{0}' file.", keyfile);
62 return null;
65 try {
66 PrivateKey pvk = PrivateKey.CreateFromFile (keyfile);
67 rsa = pvk.RSA;
69 catch (CryptographicException) {
70 Console.WriteLine ("Enter password for {0}: ", keyfile);
71 string password = Console.ReadLine ();
72 try {
73 PrivateKey pvk = PrivateKey.CreateFromFile (keyfile, password);
74 rsa = pvk.RSA;
76 catch (CryptographicException) {
77 Console.WriteLine ("Invalid password!");
81 else {
82 rsa = new RSACryptoServiceProvider (csp);
85 return rsa;
88 static private X509CertificateCollection GetCertificates (string spcfile)
90 if (spcfile == null) {
91 Console.WriteLine ("Missing SPC (certificate) file.");
92 return null;
94 if (!File.Exists (spcfile)) {
95 Console.WriteLine ("Couldn't find '{0}' file.", spcfile);
96 return null;
99 SoftwarePublisherCertificate spc = SoftwarePublisherCertificate.CreateFromFile (spcfile);
100 return spc.Certificates;
103 [STAThread]
104 static int Main(string[] args)
106 Header ();
107 if (args.Length < 1) {
108 Help ();
109 return 1;
112 CspParameters csp = new CspParameters ();
113 string pvkFilename = null;
114 string spcFilename = null;
115 int timestampRetry = 1;
116 int timestampDelay = 0;
117 bool sign = true;
119 // to be signed
120 string tbsFilename = args [args.Length - 1];
122 AuthenticodeFormatter af = new AuthenticodeFormatter ();
124 int i = 0;
125 while (i < args.Length - 1) {
126 switch (args[i++]) {
127 case "-spc":
128 spcFilename = args [i++];
129 break;
130 case "-v":
131 pvkFilename = args [i++];
132 break;
133 case "-a":
134 af.Hash = args [i++];
135 break;
136 case "-$":
137 string auth = args [i++].ToLower ();
138 switch (auth) {
139 case "individual":
140 af.Authority = Authority.Individual;
141 break;
142 case "commercial":
143 af.Authority = Authority.Commercial;
144 break;
145 default:
146 Console.WriteLine ("Unknown authority {0}", auth);
147 return 1;
149 break;
150 case "-n":
151 af.Description = args [i++];
152 break;
153 case "-i":
154 af.Url = new Uri (args [i++]);
155 break;
156 // timestamp options
157 case "-t":
158 af.TimestampUrl = new Uri (args [i++]);
159 break;
160 case "-tr":
161 timestampRetry = Convert.ToInt32 (args [i++]);
162 break;
163 case "-tw":
164 timestampDelay = Convert.ToInt32 (args [i++]) * 1000;
165 break;
166 case "-x":
167 // only timestamp
168 sign = false;
169 break;
170 // CSP provider options
171 case "-k":
172 csp.KeyContainerName = args [i++];
173 break;
174 case "-p":
175 csp.ProviderName = args [i++];
176 break;
177 case "-y":
178 csp.ProviderType = Convert.ToInt32 (args [i++]);
179 break;
180 case "-ky":
181 string key = args [i++];
182 switch (key) {
183 case "signature":
184 csp.KeyNumber = 0;
185 break;
186 case "exchange":
187 csp.KeyNumber = 0;
188 break;
189 default:
190 csp.KeyNumber = Convert.ToInt32 (key);
191 break;
193 break;
194 case "-r":
195 string location = args [i++];
196 switch (location) {
197 case "localMachine":
198 csp.Flags = CspProviderFlags.UseMachineKeyStore;
199 break;
200 case "currentUser":
201 csp.Flags = CspProviderFlags.UseDefaultKeyContainer;
202 break;
203 default:
204 Console.WriteLine ("Unknown location {0}", location);
205 return 1;
207 break;
208 // unsupported options
209 case "-j":
210 case "-jp":
211 Console.WriteLine ("Unsupported option {0}", args[i-1]);
212 return 1;
213 // other options
214 case "-?":
215 Help ();
216 return 0;
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);
224 return 1;
227 if (sign) {
228 RSA rsa = GetPrivateKey (pvkFilename, csp);
229 if (rsa == null) {
230 Console.WriteLine ("No private key available to sign the assembly.");
231 return 1;
233 af.RSA = rsa;
235 X509CertificateCollection certs = GetCertificates (spcFilename);
236 if ((certs == null) || (certs.Count == 0)) {
237 Console.WriteLine ("No certificates available to sign the assembly.");
238 return 1;
240 af.Certificates.AddRange (certs);
242 if (!af.Sign (tbsFilename)) {
243 Console.WriteLine ("Couldn't sign file '{0}'.", tbsFilename);
244 return 1;
246 } else if (af.TimestampUrl != null) {
247 bool ts = false;
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);
257 if (!ts) {
258 Console.WriteLine ("Couldn't timestamp file '{0}' after {1} retries.", tbsFilename, timestampRetry);
259 return 1;
261 } else {
262 Help ();
263 return 1;
266 Console.WriteLine ("Success");
267 return 0;