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