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>