add ISafeSerializationData
[mcs.git] / tools / mono-configuration-crypto / cli / main.cs
blobeba13eba3791c3b41ad03145a9019266851b5b51
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Reflection;
6 using Mono.Options;
7 using Mono.Configuration.Crypto;
9 [assembly: AssemblyTitle ("mono-configuration-crypto")]
10 [assembly: AssemblyDescription ("Mono configuration utility to manage encryption keys and encrypt/decrypt config file sections")]
11 [assembly: AssemblyCompany (Consts.MonoCompany)]
12 [assembly: AssemblyProduct ("Mono Configuration Cryptography Tools")]
13 [assembly: AssemblyCopyright ("Copyright (c) 2010 Novell, Inc (http://novell.com, http://mono-project.com/)")]
14 [assembly: AssemblyVersion (Consts.FxVersion)]
16 namespace MonoConfigurationCrypto
18 class MonoConfigurationCrypto
20 void Success ()
22 Console.WriteLine ("Success.");
25 void Failure (Exception ex, Config cfg)
27 Failure (ex, cfg, null);
30 void Failure (Config cfg, string message, params object[] parms)
32 Failure (null, cfg, message, parms);
35 void Failure (Exception ex, Config cfg, string message, params object[] parms)
37 if (!String.IsNullOrEmpty (message)) {
38 if (parms == null || parms.Length == 0)
39 Console.Error.WriteLine (message);
40 else
41 Console.Error.WriteLine (message, parms);
44 if (ex != null) {
45 if (cfg.Verbose)
46 Console.Error.WriteLine (ex.ToString ());
47 else
48 Console.Error.WriteLine (ex.Message);
50 Console.Error.WriteLine ("Failure.");
53 bool ListContainers (Config cfg)
55 try {
56 var kc = new KeyContainerCollection (cfg.UseMachinePath);
57 int count;
58 foreach (KeyContainer c in kc) {
59 count = c.Count;
60 Console.WriteLine ("{0} container '{1}' ({2} key{3})", c.Local ? "Local" : "Global", c.Name, count,
61 count == 1 ? String.Empty : "s");
63 } catch (Exception ex) {
64 Failure (ex, cfg);
67 return true;
70 string FindConfigFile (string path, string configFileName)
72 if (!Directory.Exists (path))
73 return null;
75 string fileName = null;
76 foreach (var s in Directory.GetFiles (path, "*.*", SearchOption.TopDirectoryOnly)) {
77 string fn = Path.GetFileName (s);
78 if (String.Compare (fn, configFileName, StringComparison.OrdinalIgnoreCase) == 0) {
79 fileName = fn;
80 break;
84 if (fileName == null)
85 return null;
87 return Path.Combine (path, fileName);
90 bool EncryptSection (Config cfg)
92 string configSection = cfg.ConfigSectionName;
93 string containerName = cfg.ContainerName;
94 string configFile = FindConfigFile (cfg.ApplicationPhysicalPath, cfg.ConfigFileName);
96 Console.WriteLine ("Encrypting section '{0}' in config file '{1}' using key container '{2}'...", configSection, configFile, containerName);
98 if (String.IsNullOrEmpty (configFile)) {
99 Failure (cfg, "No config file found in directory '{0}'", cfg.ApplicationPhysicalPath);
100 return true;
103 if (String.IsNullOrEmpty (configSection)) {
104 Failure (cfg, "No config section name specified.");
105 return true;
108 try {
109 var cs = new ConfigSection ();
110 cs.Encrypt (configFile, configSection, containerName, cfg.UseMachinePath);
111 Console.WriteLine ("Success.");
112 } catch (Exception ex) {
113 Failure (ex, cfg);
114 return true;
117 return false;
120 bool DecryptSection (Config cfg)
122 string configSection = cfg.ConfigSectionName;
123 string containerName = cfg.ContainerName;
124 string configFile = FindConfigFile (cfg.ApplicationPhysicalPath, cfg.ConfigFileName);
126 Console.WriteLine ("Decrypting section '{0}' in config file '{1}' using key container '{2}'...", configSection, configFile, containerName);
128 if (String.IsNullOrEmpty (configFile)) {
129 Failure (cfg, "No config file found in directory '{0}'", cfg.ApplicationPhysicalPath);
130 return true;
133 if (String.IsNullOrEmpty (configSection)) {
134 Failure (cfg, "No config section name specified.");
135 return true;
138 try {
139 var cs = new ConfigSection ();
140 cs.Decrypt (configFile, configSection, containerName, cfg.UseMachinePath);
141 Console.WriteLine ("Success.");
142 } catch (Exception ex) {
143 Failure (ex, cfg);
144 return true;
147 return false;
150 bool CreateKey (Config cfg)
152 string name = cfg.ContainerName;
153 KeyContainerCollection kc;
155 Console.WriteLine ("Creating RSA key container '{0}'...", name);
156 try {
157 kc = new KeyContainerCollection (cfg.UseMachinePath);
158 if (kc.Contains (name)) {
159 Failure (cfg, "The RSA container already exists.");
160 return true;
163 var k = new Key (name, cfg.KeySize, cfg.UseMachinePath);
164 if (!k.IsValid) {
165 Failure (cfg, "Failed to generate RSA key pair.");
166 return true;
168 k.Save ();
169 Success ();
170 } catch (Exception ex) {
171 Failure (ex, cfg);
172 return true;
175 return false;
178 bool ImportKey (Config cfg)
180 string containerName = cfg.ContainerName;
181 string fileName = cfg.FileName;
183 Console.WriteLine ("Importing an RSA key from file '{0}' into the container '{1}'...", fileName, containerName);
184 if (String.IsNullOrEmpty (containerName)) {
185 Failure (cfg, "Unspecified container name.");
186 return true;
189 if (String.IsNullOrEmpty (fileName)) {
190 Failure (cfg, "Unspecified file name.");
191 return true;
194 if (!File.Exists (fileName)) {
195 Failure (cfg, "Key file '{0}' does not exist.", fileName);
196 return true;
199 KeyContainerCollection kcc;
200 Key key;
201 KeyContainer kc;
202 try {
203 kcc = new KeyContainerCollection (cfg.UseMachinePath);
204 kc = kcc [containerName];
206 if (kc != null)
207 key = kc [0];
208 else
209 key = null;
211 // No validation is performed on the key - this is left for the
212 // encryption algorithm implementation to do.
213 string keyvalue = File.ReadAllText (fileName);
214 if (key == null)
215 key = new Key (containerName, keyvalue, cfg.UseMachinePath);
216 else {
217 key.KeyValue = keyvalue;
218 key.ContainerName = containerName;
221 key.Save ();
222 Console.WriteLine ("Success.");
223 } catch (Exception ex) {
224 Failure (ex, cfg);
225 return true;
228 return false;
231 bool ExportKey (Config cfg)
233 string containerName = cfg.ContainerName;
234 string fileName = cfg.FileName;
236 Console.WriteLine ("Exporting an RSA key from container '{0}' to file '{1}'...", containerName, fileName);
237 if (String.IsNullOrEmpty (containerName)) {
238 Failure (cfg, "Unspecified container name.");
239 return true;
242 if (String.IsNullOrEmpty (fileName)) {
243 Failure (cfg, "Unspecified file name.");
244 return true;
247 KeyContainerCollection kcc;
248 Key key;
249 KeyContainer kc;
250 try {
251 kcc = new KeyContainerCollection (cfg.UseMachinePath);
252 kc = kcc [containerName];
254 if (kc != null)
255 key = kc [0];
256 else {
257 Failure (cfg, "Container '{0}' does not exist.", containerName);
258 return true;
261 if (key == null) {
262 Failure (cfg, "Container '{0}' exists but it does not contain any keys.", containerName);
263 return true;
266 File.WriteAllText (fileName, key.KeyValue);
267 Console.WriteLine ("Success.");
268 } catch (Exception ex) {
269 Failure (ex, cfg);
270 return true;
273 return false;
276 bool RemoveContainer (Config cfg)
278 string containerName = cfg.ContainerName;
279 Console.WriteLine ("Removing container '{0}'...", containerName);
280 if (String.IsNullOrEmpty (containerName)) {
281 Failure (cfg, "Unspecified container name.");
282 return true;
285 try {
286 KeyContainer.RemoveFromDisk (containerName, cfg.UseMachinePath);
288 Console.WriteLine ("Success.");
289 } catch (Exception ex) {
290 Failure (ex, cfg);
291 return true;
294 return false;
297 void ShowHeader ()
299 string title = String.Empty, version = String.Empty, description = String.Empty, copyright = String.Empty;
300 Assembly asm = Assembly.GetExecutingAssembly ();
301 foreach (object o in asm.GetCustomAttributes (false)) {
302 if (o is AssemblyTitleAttribute)
303 title = ((AssemblyTitleAttribute)o).Title;
304 else if (o is AssemblyCopyrightAttribute)
305 copyright = ((AssemblyCopyrightAttribute)o).Copyright;
306 else if (o is AssemblyDescriptionAttribute)
307 description = ((AssemblyDescriptionAttribute)o).Description;
310 version = asm.GetName ().Version.ToString ();
312 Console.WriteLine ("{1} - version {2}{0}{3}{0}{4}{0}",
313 Environment.NewLine,
314 title,
315 version,
316 description,
317 copyright);
320 void Run (string[] args)
322 var cfg = new Config ();
323 var actions = new List <Func <Config, bool>> ();
324 var options = new OptionSet () {
325 { "h|?|help", "Show usage information", v => cfg.ShowHelp = true },
326 { "v|verbose", "Show verbose information (including exception stacktraces)", v => cfg.Verbose = true },
327 { "m|machine|global", "Use machine (global) store for all the key actions", v => cfg.UseMachinePath = true },
328 { "u|user|local", "Use local (user) store for all the key actions [*]", v => cfg.UseMachinePath = false },
329 { "l|list", "List all the key container names in the store", v => actions.Add (ListContainers) },
330 { "c|create", "Creates an RSA public/private key pair", v => actions.Add (CreateKey) },
331 { "i|import", "Import key to a container", v => actions.Add (ImportKey) },
332 { "x|export", "Export key from a container", v => actions.Add (ExportKey) },
333 { "r|remove", "Remove a container", v => actions.Add (RemoveContainer) },
334 { "f=|file=", "File name for import or export operations", (string s) => cfg.FileName = s },
335 { "cf=|config-file=", String.Format ("Config file name (not path) [{0}]", Config.DefaultConfigFileName), (string s) => cfg.ConfigFileName = s },
336 { "n=|name=", String.Format ("Container name [{0}]", Config.DefaultContainerName), (string s) => cfg.ContainerName = s },
337 { "s=|size=", String.Format ("Key size [{0}]", Config.DefaultKeySize), (uint s) => cfg.KeySize = s },
338 { "p=|path=", String.Format ("Application physical path [{0}]", Config.DefaultApplicationPhysicalPath), (string s) => cfg.ApplicationPhysicalPath = s },
339 { "d=|dec=|decrypt=", "Decrypt configuration section", (string s) => { cfg.ConfigSectionName = s; actions.Add (DecryptSection);} },
340 { "e=|enc=|encrypt=", "Encrypt configuration section", (string s) => { cfg.ConfigSectionName = s; actions.Add (EncryptSection);} },
342 options.Parse (args);
344 if (cfg.ShowHelp) {
345 ShowHeader ();
346 options.WriteOptionDescriptions (Console.Out);
347 return;
350 foreach (var action in actions)
351 if (action (cfg))
352 Environment.Exit (0);
355 static void Main (string[] args)
357 new MonoConfigurationCrypto ().Run (args);