Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

361 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Mono.Options;
using Mono.Configuration.Crypto;
[assembly: AssemblyTitle ("mono-configuration-crypto")]
[assembly: AssemblyDescription ("Mono configuration utility to manage encryption keys and encrypt/decrypt config file sections")]
[assembly: AssemblyCompany (Consts.MonoCompany)]
[assembly: AssemblyProduct ("Mono Configuration Cryptography Tools")]
[assembly: AssemblyCopyright ("Copyright (c) 2010 Novell, Inc (http://novell.com, http://mono-project.com/)")]
[assembly: AssemblyVersion (Consts.FxVersion)]
namespace MonoConfigurationCrypto
{
class MonoConfigurationCrypto
{
void Success ()
{
Console.WriteLine ("Success.");
}
void Failure (Exception ex, Config cfg)
{
Failure (ex, cfg, null);
}
void Failure (Config cfg, string message, params object[] parms)
{
Failure (null, cfg, message, parms);
}
void Failure (Exception ex, Config cfg, string message, params object[] parms)
{
if (!String.IsNullOrEmpty (message)) {
if (parms == null || parms.Length == 0)
Console.Error.WriteLine (message);
else
Console.Error.WriteLine (message, parms);
}
if (ex != null) {
if (cfg.Verbose)
Console.Error.WriteLine (ex.ToString ());
else
Console.Error.WriteLine (ex.Message);
}
Console.Error.WriteLine ("Failure.");
}
bool ListContainers (Config cfg)
{
try {
var kc = new KeyContainerCollection (cfg.UseMachinePath);
int count;
foreach (KeyContainer c in kc) {
count = c.Count;
Console.WriteLine ("{0} container '{1}' ({2} key{3})", c.Local ? "Local" : "Global", c.Name, count,
count == 1 ? String.Empty : "s");
}
} catch (Exception ex) {
Failure (ex, cfg);
}
return true;
}
string FindConfigFile (string path, string configFileName)
{
if (!Directory.Exists (path))
return null;
string fileName = null;
foreach (var s in Directory.GetFiles (path, "*.*", SearchOption.TopDirectoryOnly)) {
string fn = Path.GetFileName (s);
if (String.Compare (fn, configFileName, StringComparison.OrdinalIgnoreCase) == 0) {
fileName = fn;
break;
}
}
if (fileName == null)
return null;
return Path.Combine (path, fileName);
}
bool EncryptSection (Config cfg)
{
string configSection = cfg.ConfigSectionName;
string containerName = cfg.ContainerName;
string configFile = FindConfigFile (cfg.ApplicationPhysicalPath, cfg.ConfigFileName);
Console.WriteLine ("Encrypting section '{0}' in config file '{1}' using key container '{2}'...", configSection, configFile, containerName);
if (String.IsNullOrEmpty (configFile)) {
Failure (cfg, "No config file found in directory '{0}'", cfg.ApplicationPhysicalPath);
return true;
}
if (String.IsNullOrEmpty (configSection)) {
Failure (cfg, "No config section name specified.");
return true;
}
try {
var cs = new ConfigSection ();
cs.Encrypt (configFile, configSection, containerName, cfg.UseMachinePath);
Console.WriteLine ("Success.");
} catch (Exception ex) {
Failure (ex, cfg);
return true;
}
return false;
}
bool DecryptSection (Config cfg)
{
string configSection = cfg.ConfigSectionName;
string containerName = cfg.ContainerName;
string configFile = FindConfigFile (cfg.ApplicationPhysicalPath, cfg.ConfigFileName);
Console.WriteLine ("Decrypting section '{0}' in config file '{1}' using key container '{2}'...", configSection, configFile, containerName);
if (String.IsNullOrEmpty (configFile)) {
Failure (cfg, "No config file found in directory '{0}'", cfg.ApplicationPhysicalPath);
return true;
}
if (String.IsNullOrEmpty (configSection)) {
Failure (cfg, "No config section name specified.");
return true;
}
try {
var cs = new ConfigSection ();
cs.Decrypt (configFile, configSection, containerName, cfg.UseMachinePath);
Console.WriteLine ("Success.");
} catch (Exception ex) {
Failure (ex, cfg);
return true;
}
return false;
}
bool CreateKey (Config cfg)
{
string name = cfg.ContainerName;
KeyContainerCollection kc;
Console.WriteLine ("Creating RSA key container '{0}'...", name);
try {
kc = new KeyContainerCollection (cfg.UseMachinePath);
if (kc.Contains (name)) {
Failure (cfg, "The RSA container already exists.");
return true;
}
var k = new Key (name, cfg.KeySize, cfg.UseMachinePath);
if (!k.IsValid) {
Failure (cfg, "Failed to generate RSA key pair.");
return true;
}
k.Save ();
Success ();
} catch (Exception ex) {
Failure (ex, cfg);
return true;
}
return false;
}
bool ImportKey (Config cfg)
{
string containerName = cfg.ContainerName;
string fileName = cfg.FileName;
Console.WriteLine ("Importing an RSA key from file '{0}' into the container '{1}'...", fileName, containerName);
if (String.IsNullOrEmpty (containerName)) {
Failure (cfg, "Unspecified container name.");
return true;
}
if (String.IsNullOrEmpty (fileName)) {
Failure (cfg, "Unspecified file name.");
return true;
}
if (!File.Exists (fileName)) {
Failure (cfg, "Key file '{0}' does not exist.", fileName);
return true;
}
KeyContainerCollection kcc;
Key key;
KeyContainer kc;
try {
kcc = new KeyContainerCollection (cfg.UseMachinePath);
kc = kcc [containerName];
if (kc != null)
key = kc [0];
else
key = null;
// No validation is performed on the key - this is left for the
// encryption algorithm implementation to do.
string keyvalue = File.ReadAllText (fileName);
if (key == null)
key = new Key (containerName, keyvalue, cfg.UseMachinePath);
else {
key.KeyValue = keyvalue;
key.ContainerName = containerName;
}
key.Save ();
Console.WriteLine ("Success.");
} catch (Exception ex) {
Failure (ex, cfg);
return true;
}
return false;
}
bool ExportKey (Config cfg)
{
string containerName = cfg.ContainerName;
string fileName = cfg.FileName;
Console.WriteLine ("Exporting an RSA key from container '{0}' to file '{1}'...", containerName, fileName);
if (String.IsNullOrEmpty (containerName)) {
Failure (cfg, "Unspecified container name.");
return true;
}
if (String.IsNullOrEmpty (fileName)) {
Failure (cfg, "Unspecified file name.");
return true;
}
KeyContainerCollection kcc;
Key key;
KeyContainer kc;
try {
kcc = new KeyContainerCollection (cfg.UseMachinePath);
kc = kcc [containerName];
if (kc != null)
key = kc [0];
else {
Failure (cfg, "Container '{0}' does not exist.", containerName);
return true;
}
if (key == null) {
Failure (cfg, "Container '{0}' exists but it does not contain any keys.", containerName);
return true;
}
File.WriteAllText (fileName, key.KeyValue);
Console.WriteLine ("Success.");
} catch (Exception ex) {
Failure (ex, cfg);
return true;
}
return false;
}
bool RemoveContainer (Config cfg)
{
string containerName = cfg.ContainerName;
Console.WriteLine ("Removing container '{0}'...", containerName);
if (String.IsNullOrEmpty (containerName)) {
Failure (cfg, "Unspecified container name.");
return true;
}
try {
KeyContainer.RemoveFromDisk (containerName, cfg.UseMachinePath);
Console.WriteLine ("Success.");
} catch (Exception ex) {
Failure (ex, cfg);
return true;
}
return false;
}
void ShowHeader ()
{
string title = String.Empty, version = String.Empty, description = String.Empty, copyright = String.Empty;
Assembly asm = Assembly.GetExecutingAssembly ();
foreach (object o in asm.GetCustomAttributes (false)) {
if (o is AssemblyTitleAttribute)
title = ((AssemblyTitleAttribute)o).Title;
else if (o is AssemblyCopyrightAttribute)
copyright = ((AssemblyCopyrightAttribute)o).Copyright;
else if (o is AssemblyDescriptionAttribute)
description = ((AssemblyDescriptionAttribute)o).Description;
}
version = asm.GetName ().Version.ToString ();
Console.WriteLine ("{1} - version {2}{0}{3}{0}{4}{0}",
Environment.NewLine,
title,
version,
description,
copyright);
}
void Run (string[] args)
{
var cfg = new Config ();
var actions = new List <Func <Config, bool>> ();
var options = new OptionSet () {
{ "h|?|help", "Show usage information", v => cfg.ShowHelp = true },
{ "v|verbose", "Show verbose information (including exception stacktraces)", v => cfg.Verbose = true },
{ "m|machine|global", "Use machine (global) store for all the key actions", v => cfg.UseMachinePath = true },
{ "u|user|local", "Use local (user) store for all the key actions [*]", v => cfg.UseMachinePath = false },
{ "l|list", "List all the key container names in the store", v => actions.Add (ListContainers) },
{ "c|create", "Creates an RSA public/private key pair", v => actions.Add (CreateKey) },
{ "i|import", "Import key to a container", v => actions.Add (ImportKey) },
{ "x|export", "Export key from a container", v => actions.Add (ExportKey) },
{ "r|remove", "Remove a container", v => actions.Add (RemoveContainer) },
{ "f=|file=", "File name for import or export operations", (string s) => cfg.FileName = s },
{ "cf=|config-file=", String.Format ("Config file name (not path) [{0}]", Config.DefaultConfigFileName), (string s) => cfg.ConfigFileName = s },
{ "n=|name=", String.Format ("Container name [{0}]", Config.DefaultContainerName), (string s) => cfg.ContainerName = s },
{ "s=|size=", String.Format ("Key size [{0}]", Config.DefaultKeySize), (uint s) => cfg.KeySize = s },
{ "p=|path=", String.Format ("Application physical path [{0}]", Config.DefaultApplicationPhysicalPath), (string s) => cfg.ApplicationPhysicalPath = s },
{ "d=|dec=|decrypt=", "Decrypt configuration section", (string s) => { cfg.ConfigSectionName = s; actions.Add (DecryptSection);} },
{ "e=|enc=|encrypt=", "Encrypt configuration section", (string s) => { cfg.ConfigSectionName = s; actions.Add (EncryptSection);} },
};
options.Parse (args);
if (cfg.ShowHelp) {
ShowHeader ();
options.WriteOptionDescriptions (Console.Out);
return;
}
foreach (var action in actions)
if (action (cfg))
Environment.Exit (0);
}
static void Main (string[] args)
{
new MonoConfigurationCrypto ().Run (args);
}
}
}