Sign XSharper script with a certificate
<xsharper>
<versionInfo title="Sign-Cert" value="Sign XSH script with a given certificate" version="0.0.0.1" />
<usage options="ifNoArguments default" />
<param name="data" value="Script file" description="script.xsh" required="true" />
<param name="certSubject" value="Certificate subject" required="true" />
<param />
<param value="Parameters:" />
<param />
<param switch="machine" count="none" value="Use machine certificate store" default="0" unspecified="1" />
<reference name="System.Security" />
<?h using System;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
?>
<code><![CDATA[
X509Store store = new X509Store("My", c.GetBool("machine")?StoreLocation.LocalMachine:StoreLocation.CurrentUser);
try
{
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
X509Certificate2Collection coll=store.Certificates.Find(X509FindType.FindBySubjectName, c.GetStr("certSubject"), false);
if (coll.Count==0)
{
c.Error.WriteLine("Certificate not found");
return -2;
}
if (coll.Count!=1)
{
c.Error.WriteLine("Too many certificates found");
return -2;
}
X509Certificate2 cert=coll[0];
if (cert.PrivateKey==null)
{
c.Error.WriteLine("Certificate does not have a private key");
return -2;
}
PrintInfo(cert);
X509ChainPolicy pol = new X509ChainPolicy();
pol.RevocationMode = X509RevocationMode.NoCheck;
pol.VerificationFlags = X509VerificationFlags.IgnoreEndRevocationUnknown | X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown | X509VerificationFlags.IgnoreRootRevocationUnknown;
pol.ApplicationPolicy.Add(new Oid("1.3.6.1.5.5.7.3.3"));
X509Chain chain = new X509Chain(true);
chain.ChainPolicy = pol;
if (!chain.Build(cert))
c.Error.WriteLine("Warning: Certificate is not trusted for CodeSigning");
string filename=(string)c["data"];
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(filename);
SignedXml signer= new SignedXml(doc);
var el=doc.GetElementsByTagName("Signature");
if (el!=null && el.Count!=0 && el[0]!=null && el[0] is XmlElement)
el[0].ParentNode.RemoveChild(el[0]);
signer.KeyInfo = new KeyInfo();
signer.KeyInfo.AddClause(new KeyInfoX509Data(cert,X509IncludeOption.ExcludeRoot));
signer.SigningKey = cert.PrivateKey;
signer.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NWithCommentsTransformUrl;
XmlDsigExcC14NWithCommentsTransform canMethod = (XmlDsigExcC14NWithCommentsTransform)signer.SignedInfo.CanonicalizationMethodObject;
canMethod.InclusiveNamespacesPrefixList = "Sign";
Reference orderRef = new Reference("");
orderRef.AddTransform(new XmlDsigEnvelopedSignatureTransform());
signer.AddReference(orderRef);
signer.ComputeSignature();
doc.DocumentElement.AppendChild(signer.GetXml());
doc.Save(filename);
c.Print("Script '${=Path.GetFullPath($data)}' has been signed & saved successfully");
return 0;
}
finally {
store.Close();
}
]]>
<sub id="PrintInfo">
<param name="cert" required="true" />
<print tr="trim multiline expand" outTo="^info">
==== Certificate info ===
Subject: ${=$cert.Subject}
Expiration: ${=$cert.GetExpirationDateString()}
Issuer: ${=$cert.Subject}
Serial: ${=$cert.SerialNumber}
Thumbprint: ${=$cert.Thumbprint}
</print>
</sub>
</code>
</xsharper>