2010-05-25 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / security / httpcfg.cs
blob26c0300faa3c210b6f93fcbe09365bd0c8c71513
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 //
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;
18 [assembly: AssemblyTitle ("Mono Certificate Management for HttpListener use")]
19 [assembly: AssemblyDescription ("Manage X.509 certificates to be used in HttpListener.")]
21 namespace Mono.Tools {
22 class HttpCfg {
23 enum Action {
24 None,
25 Add,
26 Delete,
27 List
30 static Action action;
31 static string pvkfile;
32 static string certfile;
34 static string p12file;
35 static string passwd;
37 static ushort port;
39 static void Help (bool exit)
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);
49 static void ProcessArguments (string [] args)
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);
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);
67 action = Action.Delete;
68 break;
69 case "-list":
70 if (action != Action.None) {
71 Console.Error.WriteLine ("error: conflicting options.");
72 Help (true);
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);
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);
91 break;
93 case "-p12":
94 if (p12file != null) {
95 Console.Error.WriteLine ("error: more than one p12 file specified.");
96 Help (true);
99 if (pvkfile != null || certfile != null) {
100 Console.Error.WriteLine ("error: use either -p12 or -pvk and -cert.");
101 Help (true);
103 p12file = args [++i];
104 break;
106 case "-pvk":
107 if (pvkfile != null) {
108 Console.Error.WriteLine ("error: more than one PVK file specified.");
109 Help (true);
113 if (p12file != null) {
114 Console.Error.WriteLine ("error: use either -p12 or -pvk and -cert.");
115 Help (true);
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);
127 if (p12file != null) {
128 Console.Error.WriteLine ("error: use either -p12 or -pvk and -cert.");
129 Help (true);
132 certfile = args [++i];
133 break;
135 case "-passwd":
136 if (passwd != null) {
137 Console.Error.WriteLine ("error: more than one password specified.");
138 Help (true);
140 passwd = args [++i];
141 break;
143 default:
144 Console.Error.WriteLine ("error: Unknown argument: {0}", arg);
145 Help (true);
146 break;
150 if (action == Action.None) {
151 Console.Error.WriteLine ("error: no action specified.");
152 Help (true);
155 if ((pvkfile != null && certfile == null) || (pvkfile == null && certfile != null)) {
156 Console.Error.WriteLine ("error: -cert and -pvk must be used.");
157 Help (true);
160 if (action != Action.List && port == 0) {
161 Console.Error.WriteLine ("error: -port is missing or bogus.");
162 Help (true);
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);
173 static void AddP12 (string path, string filename, string password, ushort port)
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);
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);
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);
194 using (Stream cer = File.OpenWrite (target_cert)) {
195 byte [] raw = x509.RawData;
196 cer.Write (raw, 0, raw.Length);
199 x509.PrivateKey.Save (target_pvk);
203 static void AddCertPvk (string path, string cert, string pvk, ushort port)
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);
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);
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);
223 File.Copy (cert, target_cert);
224 File.Copy (pvk, target_pvk);
227 static void Delete (string path, ushort port)
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);
240 static void List (string path)
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);
251 static int Main (string[] args)
253 try {
254 ProcessArguments (args);
255 } catch (IndexOutOfRangeException) {
256 Console.Error.WriteLine ("error: missing argument.");
257 Help (true);
260 if (action == Action.None) {
261 Help (true);
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;
276 switch (action) {
277 case Action.Add:
279 if (p12file != null)
280 AddP12 (path, p12file, passwd, port);
281 else
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;
292 return 0;