mirror of
https://github.com/twiglet/cs2j.git
synced 2025-01-18 13:15:17 +01:00
228 lines
8.8 KiB
C#
228 lines
8.8 KiB
C#
|
/*
|
|||
|
Copyright 2010,2011 Kevin Glynn (kevin.glynn@twigletsoftware.com)
|
|||
|
*/
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Reflection;
|
|||
|
using System.IO;
|
|||
|
using System.Xml.Serialization;
|
|||
|
using System.Xml;
|
|||
|
using System.Text;
|
|||
|
using NDesk.Options;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Security.Cryptography;
|
|||
|
using System.Security.Cryptography.Xml;
|
|||
|
|
|||
|
namespace Twiglet.CS2J.Utility
|
|||
|
{
|
|||
|
public class TemplateSigner
|
|||
|
{
|
|||
|
private const string CS2JSIGNER_VERSION = "pre-release";
|
|||
|
private int Verbose { get; set; }
|
|||
|
public delegate void FileProcessor(string fName);
|
|||
|
private List<string> XmlDirs { get; set; }
|
|||
|
private List<string> ExcludeXmlDirs { get; set; }
|
|||
|
private String KeyFile = null;
|
|||
|
RSACryptoServiceProvider RsaKey { get; set; }
|
|||
|
|
|||
|
public TemplateSigner()
|
|||
|
{
|
|||
|
Verbose = 0;
|
|||
|
XmlDirs = new List<string>();
|
|||
|
ExcludeXmlDirs = new List<string>();
|
|||
|
RsaKey = null;
|
|||
|
}
|
|||
|
|
|||
|
private static void printUsageAndExit()
|
|||
|
{
|
|||
|
Console.Out.WriteLine("Usage: " + Path.GetFileNameWithoutExtension(System.Environment.GetCommandLineArgs()[0]) + " <type to dump, if not given dump all>");
|
|||
|
Console.Out.WriteLine(" [-version] (show version information)");
|
|||
|
Console.Out.WriteLine(" [-help|h|?] (this usage message)");
|
|||
|
Console.Out.WriteLine(" [-v] (be [somewhat more] verbose, repeat for more verbosity)");
|
|||
|
Console.Out.WriteLine(" [-privkeyfile <path to rsa private key file (xml format)");
|
|||
|
Console.Out.WriteLine(" [-xmlpath <a root of xml files to be signed>] (can be multiple directories, separated by semi-colons)");
|
|||
|
Console.Out.WriteLine(" [-exxmlpath <directories/files to be excluded from signing>] (can be multiple directories/files, separated by semi-colons)");
|
|||
|
Console.Out.WriteLine(" [<root of xml files to be signed>] (can be multiple directories, separated by semi-colons)");
|
|||
|
Environment.Exit(0);
|
|||
|
}
|
|||
|
|
|||
|
private static void printVersion()
|
|||
|
{
|
|||
|
Console.Out.WriteLine(Path.GetFileNameWithoutExtension(System.Environment.GetCommandLineArgs()[0]));
|
|||
|
Console.WriteLine("Version: {0}", CS2JSIGNER_VERSION);
|
|||
|
}
|
|||
|
|
|||
|
private static void addDirectories(IList<string> strs, string rawStr)
|
|||
|
{
|
|||
|
string[] argDirs = rawStr.Split(';');
|
|||
|
for (int i = 0; i < argDirs.Length; i++)
|
|||
|
strs.Add(Path.GetFullPath(argDirs[i]));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public static void Main(string[] args)
|
|||
|
{
|
|||
|
|
|||
|
TemplateSigner templateSigner = new TemplateSigner();
|
|||
|
List<string> xmlDirs = new List<string>();
|
|||
|
List<string> excludeXmlDirs = new List<string>();
|
|||
|
OptionSet p = new OptionSet()
|
|||
|
.Add("v", v => templateSigner.Verbose++)
|
|||
|
.Add("version", v => printVersion())
|
|||
|
.Add("help|h|?", v => printUsageAndExit())
|
|||
|
.Add("keyfile=", fname => templateSigner.KeyFile = Path.GetFullPath(fname))
|
|||
|
.Add("xmlpath=", dirs => addDirectories(xmlDirs, dirs))
|
|||
|
.Add("exxmlpath=", dirs => addDirectories(excludeXmlDirs, dirs))
|
|||
|
;
|
|||
|
List<string> leftovers = p.Parse(args);
|
|||
|
if (leftovers != null)
|
|||
|
{
|
|||
|
foreach (string d in leftovers)
|
|||
|
{
|
|||
|
addDirectories(xmlDirs, d);
|
|||
|
}
|
|||
|
}
|
|||
|
templateSigner.XmlDirs = xmlDirs;
|
|||
|
templateSigner.ExcludeXmlDirs = excludeXmlDirs;
|
|||
|
if (!File.Exists(templateSigner.KeyFile)) {
|
|||
|
Console.Out.WriteLine("Error: RSA key at '" + templateSigner.KeyFile + "' not found, aborting.");
|
|||
|
Environment.Exit(1);
|
|||
|
}
|
|||
|
templateSigner.SignXmlFiles();
|
|||
|
}
|
|||
|
|
|||
|
public void SignXmlFiles() {
|
|||
|
try
|
|||
|
{
|
|||
|
XmlReader reader = XmlReader.Create(KeyFile);
|
|||
|
reader.MoveToContent();
|
|||
|
|
|||
|
// Create a new CspParameters object to specify
|
|||
|
// a key container.
|
|||
|
CspParameters cspParams = new CspParameters();
|
|||
|
cspParams.KeyContainerName = "XML_DSIG_RSA_KEY";
|
|||
|
|
|||
|
// Initialise from .
|
|||
|
RsaKey = new RSACryptoServiceProvider(cspParams);
|
|||
|
RsaKey.PersistKeyInCsp = false;
|
|||
|
RsaKey.FromXmlString(reader.ReadOuterXml());
|
|||
|
|
|||
|
// Load .Net templates
|
|||
|
if (XmlDirs != null)
|
|||
|
{
|
|||
|
foreach (string r in XmlDirs)
|
|||
|
doFile(r, ".xml", SignNetTranslation, ExcludeXmlDirs);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
catch (Exception e)
|
|||
|
{
|
|||
|
Console.WriteLine(e.Message);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void SignNetTranslation(string filePath)
|
|||
|
{
|
|||
|
// Create a new XML document.
|
|||
|
XmlDocument xmlDoc = new XmlDocument();
|
|||
|
|
|||
|
// Load an XML file into the XmlDocument object.
|
|||
|
xmlDoc.PreserveWhitespace = true;
|
|||
|
xmlDoc.Load(filePath);
|
|||
|
|
|||
|
// Sign the XML document.
|
|||
|
SignXml(xmlDoc, RsaKey);
|
|||
|
|
|||
|
Console.WriteLine("XML file signed.");
|
|||
|
|
|||
|
// Save the document.
|
|||
|
xmlDoc.Save(filePath);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Sign an XML file.
|
|||
|
// This document cannot be verified unless the verifying
|
|||
|
// code has the key with which it was signed.
|
|||
|
private void SignXml(XmlDocument xmlDoc, RSA Key)
|
|||
|
{
|
|||
|
// Check arguments.
|
|||
|
if (xmlDoc == null)
|
|||
|
throw new ArgumentException("xmlDoc");
|
|||
|
if (Key == null)
|
|||
|
throw new ArgumentException("Key");
|
|||
|
|
|||
|
// Add the namespace.
|
|||
|
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
|
|||
|
nsmgr.AddNamespace("ss", "http://www.w3.org/2000/09/xmldsig#");
|
|||
|
|
|||
|
// Remove any existing signature(s)
|
|||
|
XmlNode root = xmlDoc.DocumentElement;
|
|||
|
XmlNodeList nodeList = root.SelectNodes("/*/ss:Signature", nsmgr);
|
|||
|
for (int i = nodeList.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
nodeList[i].ParentNode.RemoveChild(nodeList[i]);
|
|||
|
}
|
|||
|
// Create a SignedXml object.
|
|||
|
SignedXml signedXml = new SignedXml(xmlDoc);
|
|||
|
|
|||
|
|
|||
|
// Add the key to the SignedXml document.
|
|||
|
signedXml.SigningKey = Key;
|
|||
|
|
|||
|
// Create a reference to be signed.
|
|||
|
Reference reference = new Reference();
|
|||
|
reference.Uri = "";
|
|||
|
|
|||
|
// Add an enveloped transformation to the reference.
|
|||
|
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
|
|||
|
reference.AddTransform(env);
|
|||
|
|
|||
|
// Add the reference to the SignedXml object.
|
|||
|
signedXml.AddReference(reference);
|
|||
|
|
|||
|
// Compute the signature.
|
|||
|
signedXml.ComputeSignature();
|
|||
|
|
|||
|
// Get the XML representation of the signature and save
|
|||
|
// it to an XmlElement object.
|
|||
|
XmlElement xmlDigitalSignature = signedXml.GetXml();
|
|||
|
|
|||
|
// Append the element to the XML document.
|
|||
|
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// Call processFile on all files below f that have the given extension
|
|||
|
private void doFile(string root, string ext, FileProcessor processFile, IList<string> excludes)
|
|||
|
{
|
|||
|
string canonicalPath = Path.GetFullPath(root);
|
|||
|
// If this is a directory, walk each file/dir in that directory
|
|||
|
if (!excludes.Contains(canonicalPath.ToLower()))
|
|||
|
{
|
|||
|
if (Directory.Exists(canonicalPath))
|
|||
|
{
|
|||
|
string[] files = Directory.GetFileSystemEntries(canonicalPath);
|
|||
|
for (int i = 0; i < files.Length; i++)
|
|||
|
doFile(Path.Combine(canonicalPath, files[i]), ext, processFile, excludes);
|
|||
|
}
|
|||
|
else if ((Path.GetFileName(canonicalPath).Length > ext.Length) && canonicalPath.Substring(canonicalPath.Length - ext.Length).Equals(ext))
|
|||
|
{
|
|||
|
if (Verbose >= 2) Console.WriteLine(" " + canonicalPath);
|
|||
|
try
|
|||
|
{
|
|||
|
processFile(canonicalPath);
|
|||
|
}
|
|||
|
catch (Exception e)
|
|||
|
{
|
|||
|
Console.Error.WriteLine("\nCannot process file: " + canonicalPath);
|
|||
|
Console.Error.WriteLine("exception: " + e);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|