* xbuild/Microsoft.Common.targets (ResolveAssemblyReference):
[mono.git] / mcs / tools / security / httpcfg.cs
1 //
2 // httpcfg.cs: manages certificates used by HttpListener
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier <gonzalo@novell.com>
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //
8 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
9 //
10
11 using System;
12 using System.IO;
13 using System.Reflection;
14 using System.Security.Cryptography;
15 using System.Security.Cryptography.X509Certificates;
16 using Mono.Security.Authenticode;
17
18 [assembly: AssemblyTitle ("Mono Certificate Management for HttpListener use")]
19 [assembly: AssemblyDescription ("Manage X.509 certificates to be used in HttpListener.")]
20
21 namespace Mono.Tools {
22         class HttpCfg {
23                 enum Action {
24                         None,
25                         Add,
26                         Delete,
27                         List
28                 }
29
30                 static Action action;
31                 static string pvkfile;
32                 static string certfile;
33                 /*
34                 static string p12file;
35                 static string passwd;
36                 */
37                 static ushort port;
38
39                 static void Help (bool exit)
40                 {
41                         Console.WriteLine ("Usage is:\n" + 
42                                            "\thttpcfg -add -port NN -cert CERT -pvk PVK\n" +
43                                            "\thttpcfg -del -port NN\n" +
44                                            "\thttpcfg -list");
45                         if (exit)
46                                 Environment.Exit (1);
47                 }
48
49                 static void ProcessArguments (string [] args)
50                 {
51                         for (int i = 0; i < args.Length; i++){
52                                 string arg = args [i];
53                                 switch (arg){
54                                 case "-add":
55                                         if (action != Action.None) {
56                                                 Console.Error.WriteLine ("error: conflicting options.");
57                                                 Help (true);
58                                         }
59                                         action = Action.Add;
60                                         break;
61                                 case "-del":
62                                 case "-delete":
63                                         if (action != Action.None) {
64                                                 Console.Error.WriteLine ("error: conflicting options.");
65                                                 Help (true);
66                                         }
67                                         action = Action.Delete;
68                                         break;
69                                 case "-list":
70                                         if (action != Action.None) {
71                                                 Console.Error.WriteLine ("error: conflicting options.");
72                                                 Help (true);
73                                         }
74                                         action = Action.List;
75                                         break;
76                                 case "-port":
77                                         if (port != 0) {
78                                                 Console.Error.WriteLine ("error: more than one port specified.");
79                                                 Help (true);
80                                         }
81
82                                         try {
83                                                 port = Convert.ToUInt16 (args [++i]);
84                                         } catch (IndexOutOfRangeException) {
85                                                 Console.Error.WriteLine ("Error: no port specified.");
86                                                 Help (true);
87                                         } catch {
88                                                 Console.Error.WriteLine ("Error: invalid port.");
89                                                 Help (true);
90                                         }
91                                         break;
92                                 /*
93                                 case "-p12":
94                                         if (p12file != null) {
95                                                 Console.Error.WriteLine ("error: more than one p12 file specified.");
96                                                 Help (true);
97                                         }
98
99                                         if (pvkfile != null || certfile != null) {
100                                                 Console.Error.WriteLine ("error: use either -p12 or -pvk and -cert.");
101                                                 Help (true);
102                                         }
103                                         p12file = args [++i];
104                                         break;
105                                 */
106                                 case "-pvk":
107                                         if (pvkfile != null) {
108                                                 Console.Error.WriteLine ("error: more than one PVK file specified.");
109                                                 Help (true);
110                                         }
111
112                                         /*
113                                         if (p12file != null) {
114                                                 Console.Error.WriteLine ("error: use either -p12 or -pvk and -cert.");
115                                                 Help (true);
116                                         }
117                                         */
118                                         pvkfile = args [++i];
119                                         break;
120                                 case "-cert":
121                                         if (certfile != null) {
122                                                 Console.Error.WriteLine ("error: more than one CER file specified.");
123                                                 Help (true);
124                                         }
125
126                                         /*
127                                         if (p12file != null) {
128                                                 Console.Error.WriteLine ("error: use either -p12 or -pvk and -cert.");
129                                                 Help (true);
130                                         }
131                                         */
132                                         certfile = args [++i];
133                                         break;
134                                 /*
135                                 case "-passwd":
136                                         if (passwd != null) {
137                                                 Console.Error.WriteLine ("error: more than one password specified.");
138                                                 Help (true);
139                                         }
140                                         passwd = args [++i];
141                                         break;
142                                 */
143                                 default:
144                                         Console.Error.WriteLine ("error: Unknown argument: {0}", arg);
145                                         Help (true);
146                                         break;
147                                 }
148                         }
149
150                         if (action == Action.None) {
151                                 Console.Error.WriteLine ("error: no action specified.");
152                                 Help (true);
153                         }
154
155                         if ((pvkfile != null && certfile == null) || (pvkfile == null && certfile != null)) {
156                                 Console.Error.WriteLine ("error: -cert and -pvk must be used.");
157                                 Help (true);
158                         }
159
160                         if (action != Action.List && port == 0) {
161                                 Console.Error.WriteLine ("error: -port is missing or bogus.");
162                                 Help (true);
163                         }
164
165                         //if (action == Action.Delete && (pvkfile != null || certfile != null || p12file != null)) {
166                         if (action == Action.Delete && (pvkfile != null || certfile != null)) {
167                                 Console.Error.WriteLine ("error: -delete only expects a -port option.");
168                                 Help (true);
169                         }
170                 }
171
172                 /*
173                 static void AddP12 (string path, string filename, string password, ushort port)
174                 {
175                         X509Certificate2 x509 = null;
176                         try {
177                                 x509 = new X509Certificate2 (filename, password);
178                         } catch (Exception e) {
179                                 Console.Error.WriteLine ("error loading certificate [{0}]", e.Message);
180                                 Help (true);
181                         }
182
183                         string target_cert = Path.Combine (path, String.Format ("{0}.cer", port));
184                         if (File.Exists (target_cert)) {
185                                 Console.Error.WriteLine ("error: there is already a certificate for that port.");
186                                 Help (true);
187                         }
188                         string target_pvk = Path.Combine (path, String.Format ("{0}.pvk", port));
189                         if (File.Exists (target_pvk)) {
190                                 Console.Error.WriteLine ("error: there is already a certificate for that port.");
191                                 Help (true);
192                         }
193
194                         using (Stream cer = File.OpenWrite (target_cert)) {
195                                 byte [] raw = x509.RawData;
196                                 cer.Write (raw, 0, raw.Length);
197                         }
198
199                         x509.PrivateKey.Save (target_pvk);
200                 }
201                 */
202
203                 static void AddCertPvk (string path, string cert, string pvk, ushort port)
204                 {
205                         try {
206                                 X509Certificate2 x509 = new X509Certificate2 (cert);
207                                 x509.PrivateKey = PrivateKey.CreateFromFile (pvk).RSA;
208                         } catch (Exception e) {
209                                 Console.Error.WriteLine ("error loading certificate or private key [{0}]", e.Message);
210                                 Help (true);
211                         }
212
213                         string target_cert = Path.Combine (path, String.Format ("{0}.cer", port));
214                         if (File.Exists (target_cert)) {
215                                 Console.Error.WriteLine ("error: there is already a certificate for that port.");
216                                 Help (true);
217                         }
218                         string target_pvk = Path.Combine (path, String.Format ("{0}.pvk", port));
219                         if (File.Exists (target_pvk)) {
220                                 Console.Error.WriteLine ("error: there is already a certificate for that port.");
221                                 Help (true);
222                         }
223                         File.Copy (cert, target_cert);
224                         File.Copy (pvk, target_pvk);
225                 }
226
227                 static void Delete (string path, ushort port)
228                 {
229                         string pattern = String.Format ("{0}.*", port);
230                         string [] files = Directory.GetFiles (path, pattern);
231                         foreach (string f in files) {
232                                 try {
233                                         File.Delete (f);
234                                 } catch (Exception e) {
235                                         Console.Error.WriteLine ("error removing file {0} [{1}].", f, e.Message);
236                                 }
237                         }
238                 }
239
240                 static void List (string path)
241                 {
242                         string [] files = Directory.GetFiles (path, "*");
243                         foreach (string f in files) {
244                                 if (f.EndsWith (".cer")) {
245                                         X509Certificate2 x509 = new X509Certificate2 (f);
246                                         Console.WriteLine ("Port: {0} Thumbprint: {1}", Path.GetFileNameWithoutExtension (f), x509.Thumbprint);
247                                 }
248                         }
249                 }
250
251                 static int Main (string[] args)
252                 {
253                         try {
254                                 ProcessArguments (args);
255                         } catch (IndexOutOfRangeException) {
256                                 Console.Error.WriteLine ("error: missing argument.");
257                                 Help (true);
258                         }
259
260                         if (action == Action.None) {
261                                 Help (true);
262                         }
263
264                         string dirname = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
265                         string path = Path.Combine (dirname, ".mono");
266                         path = Path.Combine (path, "httplistener");
267                         if (false == Directory.Exists (path)) {
268                                 try {
269                                         Directory.CreateDirectory (path);
270                                 } catch (Exception e) {
271                                         Console.Error.WriteLine ("error: creating directory {0} [{1}]", path, e.Message);
272                                         return 1;
273                                 }
274                         }
275
276                         switch (action) {
277                         case Action.Add:
278                                 /*
279                                 if (p12file != null)
280                                         AddP12 (path, p12file, passwd, port);
281                                 else
282                                 */
283                                         AddCertPvk (path, certfile, pvkfile, port);
284                                 break;
285                         case Action.Delete:
286                                 Delete (path, port);
287                                 break;
288                         case Action.List:
289                                 List (path);
290                                 break;
291                         }
292                         return 0;
293                 }
294         }
295 }
296