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 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
);
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");