// can be used with sha1 or sha2 // logic is copied from the "isolation library" in NDP\iso_whid\ds\security\cryptoapi\pkisign\msaxlapi\mansign.cpp private void VerifyLicenseNew(CmiManifestVerifyFlags verifyFlags, bool oldFormat) { XmlNamespaceManager nsm = new XmlNamespaceManager(_manifestDom.NameTable); nsm.AddNamespace("asm", AssemblyNamespaceUri); nsm.AddNamespace("asm2", AssemblyV2NamespaceUri); nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); nsm.AddNamespace("msrel", MSRelNamespaceUri); nsm.AddNamespace("r", LicenseNamespaceUri); nsm.AddNamespace("as", AuthenticodeNamespaceUri); // We are done if no license. XmlElement licenseNode = _manifestDom.SelectSingleNode("asm:assembly/ds:Signature/ds:KeyInfo/msrel:RelData/r:license", nsm) as XmlElement; if (licenseNode == null) { return; } // Make sure this license is for this manifest. VerifyAssemblyIdentity(nsm); // Found a license, so instantiate signer info property. _authenticodeSignerInfo = new CmiAuthenticodeSignerInfo(Win32.TRUST_E_FAIL); // Find the license's signature XmlElement signatureNode = licenseNode.SelectSingleNode("//r:issuer/ds:Signature", nsm) as XmlElement; if (signatureNode == null) { throw new CryptographicException(Win32.TRUST_E_NOSIGNATURE); } // Make sure it is indeed an Authenticode signature, and it is an enveloped signature. // Then make sure the transforms are valid. VerifySignatureForm(signatureNode, "AuthenticodeSignature", nsm); // Now read the enveloped license signature. XmlDocument licenseDom = new XmlDocument(); licenseDom.LoadXml(licenseNode.OuterXml); signatureNode = licenseDom.SelectSingleNode("//r:issuer/ds:Signature", nsm) as XmlElement; ManifestSignedXml2 signedXml = new ManifestSignedXml2(licenseDom); signedXml.LoadXml(signatureNode); if (_useSha256) { signedXml.SignedInfo.SignatureMethod = Sha256SignatureMethodUri; } // Check the signature if (!signedXml.CheckSignature()) { _authenticodeSignerInfo = null; throw new CryptographicException(Win32.TRUST_E_CERT_SIGNATURE); } X509Certificate2 signingCertificate = GetSigningCertificate(signedXml, nsm); // First make sure certificate is not explicitly disallowed. X509Store store = new X509Store(StoreName.Disallowed, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); X509Certificate2Collection storedCertificates = null; try { storedCertificates = (X509Certificate2Collection)store.Certificates; if (storedCertificates == null) { _authenticodeSignerInfo.ErrorCode = Win32.TRUST_E_FAIL; throw new CryptographicException(Win32.TRUST_E_FAIL); } if (storedCertificates.Contains(signingCertificate)) { _authenticodeSignerInfo.ErrorCode = Win32.TRUST_E_EXPLICIT_DISTRUST; throw new CryptographicException(Win32.TRUST_E_EXPLICIT_DISTRUST); } } finally { store.Close(); } // prepare information for the TrustManager to display string hash; string description; string url; if (!GetManifestInformation(licenseNode, nsm, out hash, out description, out url)) { _authenticodeSignerInfo.ErrorCode = Win32.TRUST_E_SUBJECT_FORM_UNKNOWN; throw new CryptographicException(Win32.TRUST_E_SUBJECT_FORM_UNKNOWN); } _authenticodeSignerInfo.Hash = hash; _authenticodeSignerInfo.Description = description; _authenticodeSignerInfo.DescriptionUrl = url; // read the timestamp from the manifest DateTime verificationTime; bool isTimestamped = VerifySignatureTimestamp(signatureNode, nsm, out verificationTime); bool isLifetimeSigning = false; if (isTimestamped) { isLifetimeSigning = ((verifyFlags & CmiManifestVerifyFlags.LifetimeSigning) == CmiManifestVerifyFlags.LifetimeSigning); if (!isLifetimeSigning) { isLifetimeSigning = GetLifetimeSigning(signingCertificate); } } // Retrieve the Authenticode policy settings from registry. uint policies = GetAuthenticodePolicies(); X509Chain chain = new X509Chain(); // use the current user profile chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; if ((CmiManifestVerifyFlags.RevocationCheckEndCertOnly & verifyFlags) == CmiManifestVerifyFlags.RevocationCheckEndCertOnly) { chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EndCertificateOnly; } else if ((CmiManifestVerifyFlags.RevocationCheckEntireChain & verifyFlags) == CmiManifestVerifyFlags.RevocationCheckEntireChain) { chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; } else if (((CmiManifestVerifyFlags.RevocationNoCheck & verifyFlags) == CmiManifestVerifyFlags.RevocationNoCheck) || ((Win32.WTPF_IGNOREREVOKATION & policies) == Win32.WTPF_IGNOREREVOKATION)) { chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; } chain.ChainPolicy.VerificationTime = verificationTime; // local time if (isTimestamped && isLifetimeSigning) { chain.ChainPolicy.ApplicationPolicy.Add(new Oid(Win32.szOID_KP_LIFETIME_SIGNING)); } chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0); chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; // don't ignore anything bool chainIsValid = chain.Build(signingCertificate); if (!chainIsValid) { #if DEBUG X509ChainStatus[] statuses = chain.ChainStatus; foreach (X509ChainStatus status in statuses) { System.Diagnostics.Debug.WriteLine("flag = " + status.Status + " " + status.StatusInformation); } #endif AuthenticodeSignerInfo.ErrorCode = Win32.TRUST_E_SUBJECT_NOT_TRUSTED; throw new CryptographicException(Win32.TRUST_E_SUBJECT_NOT_TRUSTED); } // package information for the trust manager _authenticodeSignerInfo.SignerChain = chain; store = new X509Store(StoreName.TrustedPublisher, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); try { storedCertificates = (X509Certificate2Collection)store.Certificates; if (storedCertificates == null) { _authenticodeSignerInfo.ErrorCode = Win32.TRUST_E_FAIL; throw new CryptographicException(Win32.TRUST_E_FAIL); } if (!storedCertificates.Contains(signingCertificate)) { AuthenticodeSignerInfo.ErrorCode = Win32.TRUST_E_SUBJECT_NOT_TRUSTED; throw new CryptographicException(Win32.TRUST_E_SUBJECT_NOT_TRUSTED); } } finally { store.Close(); } // Verify Certificate publisher name XmlElement subjectNode = licenseNode.SelectSingleNode("r:grant/as:AuthenticodePublisher/as:X509SubjectName", nsm) as XmlElement; if (subjectNode == null || String.Compare(signingCertificate.Subject, subjectNode.InnerText, StringComparison.Ordinal) != 0) { AuthenticodeSignerInfo.ErrorCode = Win32.TRUST_E_CERT_SIGNATURE; throw new CryptographicException(Win32.TRUST_E_CERT_SIGNATURE); } if (!oldFormat) // Make sure we have the intended Authenticode signer. VerifyPublisherIdentity(nsm); }
private X509Certificate2 GetSigningCertificate(ManifestSignedXml2 signedXml, XmlNamespaceManager nsm) { X509Certificate2 signingCertificate = null; KeyInfo keyInfo = signedXml.KeyInfo; KeyInfoX509Data kiX509 = null; RSAKeyValue keyValue = null; foreach (KeyInfoClause kic in keyInfo) { if (keyValue == null) { keyValue = kic as RSAKeyValue; if (keyValue == null) { break; } } if (kiX509 == null) { kiX509 = kic as KeyInfoX509Data; } if (keyValue != null && kiX509 != null) { break; } } if (keyValue == null || kiX509 == null) { // no X509Certificate KeyInfoClause _authenticodeSignerInfo.ErrorCode = Win32.TRUST_E_SUBJECT_FORM_UNKNOWN; throw new CryptographicException(Win32.TRUST_E_SUBJECT_FORM_UNKNOWN); } // get public key from signing keyInfo byte[] signingPublicKey = null; RSACryptoServiceProvider rsaProvider = keyValue.Key as RSACryptoServiceProvider; if (rsaProvider != null) { signingPublicKey = rsaProvider.ExportCspBlob(false); } if (signingPublicKey == null) { _authenticodeSignerInfo.ErrorCode = Win32.TRUST_E_CERT_SIGNATURE; throw new CryptographicException(Win32.TRUST_E_CERT_SIGNATURE); } // enumerate all certificates in x509Data searching for the one whose public key is used in <RSAKeyValue> foreach (X509Certificate2 certificate in kiX509.Certificates) { if (certificate == null) { continue; } bool certificateAuthority = false; foreach (X509Extension extention in certificate.Extensions) { X509BasicConstraintsExtension basicExtention = extention as X509BasicConstraintsExtension; if (basicExtention != null) { certificateAuthority = basicExtention.CertificateAuthority; if (certificateAuthority) { break; } } } if (certificateAuthority) { // Ignore certs that have "Subject Type=CA" in basic contraints continue; } RSACryptoServiceProvider p = (RSACryptoServiceProvider)certificate.PublicKey.Key; byte[] certificatePublicKey = p.ExportCspBlob(false); bool noMatch = false; if (signingPublicKey.Length == certificatePublicKey.Length) { for (int i = 0; i < signingPublicKey.Length; i++) { if (signingPublicKey[i] != certificatePublicKey[i]) { noMatch = true; break; } } if (!noMatch) { signingCertificate = certificate; break; } } } if (signingCertificate == null) { _authenticodeSignerInfo.ErrorCode = Win32.TRUST_E_CERT_SIGNATURE; throw new CryptographicException(Win32.TRUST_E_CERT_SIGNATURE); } return signingCertificate; }
// throw cryptographic exception for any verification errors. internal void Verify(CmiManifestVerifyFlags verifyFlags) { // Reset signer infos. _strongNameSignerInfo = null; _authenticodeSignerInfo = null; XmlNamespaceManager nsm = new XmlNamespaceManager(_manifestDom.NameTable); nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); XmlElement signatureNode = _manifestDom.SelectSingleNode("//ds:Signature", nsm) as XmlElement; if (signatureNode == null) { throw new CryptographicException(Win32.TRUST_E_NOSIGNATURE); } // Make sure it is indeed SN signature, and it is an enveloped signature. bool oldFormat = VerifySignatureForm(signatureNode, "StrongNameSignature", nsm); // It is the DSig we want, now make sure the public key matches the token. string publicKeyToken = VerifyPublicKeyToken(); // OK. We found the SN signature with matching public key token, so // instantiate the SN signer info property. _strongNameSignerInfo = new CmiStrongNameSignerInfo(Win32.TRUST_E_FAIL, publicKeyToken); // Now verify the SN signature, and Authenticode license if available. ManifestSignedXml2 signedXml = new ManifestSignedXml2(_manifestDom, true); signedXml.LoadXml(signatureNode); if (_useSha256) { signedXml.SignedInfo.SignatureMethod = Sha256SignatureMethodUri; } AsymmetricAlgorithm key = null; bool dsigValid = signedXml.CheckSignatureReturningKey(out key); _strongNameSignerInfo.PublicKey = key; if (!dsigValid) { _strongNameSignerInfo.ErrorCode = Win32.TRUST_E_BAD_DIGEST; throw new CryptographicException(Win32.TRUST_E_BAD_DIGEST); } // Verify license as well if requested. if ((verifyFlags & CmiManifestVerifyFlags.StrongNameOnly) != CmiManifestVerifyFlags.StrongNameOnly) { if (_useSha256) { VerifyLicenseNew(verifyFlags, oldFormat); } else { VerifyLicense(verifyFlags, oldFormat); } } }
private static void StrongNameSignManifestDom(XmlDocument manifestDom, XmlDocument licenseDom, CmiManifestSigner2 signer, bool useSha256) { RSA snKey = signer.StrongNameKey as RSA; // Make sure it is RSA, as this is the only one Fusion will support. if (snKey == null) { throw new NotSupportedException(); } // Setup namespace manager. XmlNamespaceManager nsm = new XmlNamespaceManager(manifestDom.NameTable); nsm.AddNamespace("asm", AssemblyNamespaceUri); // Get to root element. XmlElement signatureParent = manifestDom.SelectSingleNode("asm:assembly", nsm) as XmlElement; if (signatureParent == null) { throw new CryptographicException(Win32.TRUST_E_SUBJECT_FORM_UNKNOWN); } if (signer.StrongNameKey.GetType() != typeof(RSACryptoServiceProvider)) { throw new NotSupportedException(); } // Setup up XMLDSIG engine. ManifestSignedXml2 signedXml = new ManifestSignedXml2(signatureParent); signedXml.SigningKey = GetFixedRSACryptoServiceProvider(signer.StrongNameKey as RSACryptoServiceProvider, useSha256); signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; if (signer.UseSha256) signedXml.SignedInfo.SignatureMethod = Sha256SignatureMethodUri; // Add the key information. signedXml.KeyInfo.AddClause(new RSAKeyValue(snKey)); if (licenseDom != null) { signedXml.KeyInfo.AddClause(new KeyInfoNode(licenseDom.DocumentElement)); } signedXml.KeyInfo.Id = "StrongNameKeyInfo"; // Add the enveloped reference. Reference enveloped = new Reference(); enveloped.Uri = ""; if (signer.UseSha256) enveloped.DigestMethod = Sha256DigestMethod; // Add an enveloped then Exc-C14N transform. enveloped.AddTransform(new XmlDsigEnvelopedSignatureTransform()); enveloped.AddTransform(new XmlDsigExcC14NTransform()); signedXml.AddReference(enveloped); #if (false) // DSIE: New format does not sign KeyInfo. // Add the key info reference. Reference strongNameKeyInfo = new Reference(); strongNameKeyInfo.Uri = "#StrongNameKeyInfo"; strongNameKeyInfo.AddTransform(new XmlDsigExcC14NTransform()); signedXml.AddReference(strongNameKeyInfo); #endif // Compute the signature. signedXml.ComputeSignature(); // Get the XML representation XmlElement xmlDigitalSignature = signedXml.GetXml(); xmlDigitalSignature.SetAttribute("Id", "StrongNameSignature"); // Insert the signature now. signatureParent.AppendChild(xmlDigitalSignature); }
private static void AuthenticodeSignLicenseDom(XmlDocument licenseDom, CmiManifestSigner2 signer, string timeStampUrl, bool useSha256) { // Make sure it is RSA, as this is the only one Fusion will support. if (signer.Certificate.PublicKey.Key.GetType() != typeof(RSACryptoServiceProvider)) { throw new NotSupportedException(); } if (signer.Certificate.PrivateKey.GetType() != typeof(RSACryptoServiceProvider)) { throw new NotSupportedException(); } // Setup up XMLDSIG engine. ManifestSignedXml2 signedXml = new ManifestSignedXml2(licenseDom); signedXml.SigningKey = GetFixedRSACryptoServiceProvider(signer.Certificate.PrivateKey as RSACryptoServiceProvider, useSha256); signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; if (signer.UseSha256) signedXml.SignedInfo.SignatureMethod = Sha256SignatureMethodUri; // Add the key information. signedXml.KeyInfo.AddClause(new RSAKeyValue(GetFixedRSACryptoServiceProvider(signer.Certificate.PrivateKey as RSACryptoServiceProvider, useSha256) as RSA)); signedXml.KeyInfo.AddClause(new KeyInfoX509Data(signer.Certificate, signer.IncludeOption)); // Add the enveloped reference. Reference reference = new Reference(); reference.Uri = ""; if (signer.UseSha256) reference.DigestMethod = Sha256DigestMethod; // Add an enveloped and an Exc-C14N transform. reference.AddTransform(new XmlDsigEnvelopedSignatureTransform()); #if (false) // BUGBUG: LTA transform complaining about issuer node not found. reference.AddTransform(new XmlLicenseTransform()); #endif reference.AddTransform(new XmlDsigExcC14NTransform()); // Add the reference. signedXml.AddReference(reference); // Compute the signature. signedXml.ComputeSignature(); // Get the XML representation XmlElement xmlDigitalSignature = signedXml.GetXml(); xmlDigitalSignature.SetAttribute("Id", "AuthenticodeSignature"); // Insert the signature node under the issuer element. XmlNamespaceManager nsm = new XmlNamespaceManager(licenseDom.NameTable); nsm.AddNamespace("r", LicenseNamespaceUri); XmlElement issuerNode = licenseDom.SelectSingleNode("r:license/r:issuer", nsm) as XmlElement; issuerNode.AppendChild(licenseDom.ImportNode(xmlDigitalSignature, true)); // Time stamp it if requested. if (timeStampUrl != null && timeStampUrl.Length != 0) { TimestampSignedLicenseDom(licenseDom, timeStampUrl); } // Wrap it inside a RelData element. licenseDom.DocumentElement.ParentNode.InnerXml = "<msrel:RelData xmlns:msrel=\"" + MSRelNamespaceUri + "\">" + licenseDom.OuterXml + "</msrel:RelData>"; }
private static void StrongNameSignManifestDom(XmlDocument manifestDom, XmlDocument licenseDom, CmiManifestSigner2 signer, bool useSha256) { RSA snKey = signer.StrongNameKey as RSA; // Make sure it is RSA, as this is the only one Fusion will support. if (snKey == null) { throw new NotSupportedException(); } // Setup namespace manager. XmlNamespaceManager nsm = new XmlNamespaceManager(manifestDom.NameTable); nsm.AddNamespace("asm", AssemblyNamespaceUri); // Get to root element. XmlElement signatureParent = manifestDom.SelectSingleNode("asm:assembly", nsm) as XmlElement; if (signatureParent == null) { throw new CryptographicException(Win32.TRUST_E_SUBJECT_FORM_UNKNOWN); } if (!(signer.StrongNameKey is RSA)) { throw new NotSupportedException(); } // Setup up XMLDSIG engine. ManifestSignedXml2 signedXml = new ManifestSignedXml2(signatureParent); if (signer.StrongNameKey is RSACryptoServiceProvider) { signedXml.SigningKey = GetFixedRSACryptoServiceProvider(signer.StrongNameKey as RSACryptoServiceProvider, useSha256); } else { signedXml.SigningKey = signer.StrongNameKey; } signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; if (signer.UseSha256) { signedXml.SignedInfo.SignatureMethod = Sha256SignatureMethodUri; } else { signedXml.SignedInfo.SignatureMethod = Sha1SignatureMethodUri; } // Add the key information. signedXml.KeyInfo.AddClause(new RSAKeyValue(snKey)); if (licenseDom != null) { signedXml.KeyInfo.AddClause(new KeyInfoNode(licenseDom.DocumentElement)); } signedXml.KeyInfo.Id = "StrongNameKeyInfo"; // Add the enveloped reference. Reference enveloped = new Reference(); enveloped.Uri = ""; if (signer.UseSha256) { enveloped.DigestMethod = Sha256DigestMethod; } else { enveloped.DigestMethod = Sha1DigestMethod; } // Add an enveloped then Exc-C14N transform. enveloped.AddTransform(new XmlDsigEnvelopedSignatureTransform()); enveloped.AddTransform(new XmlDsigExcC14NTransform()); signedXml.AddReference(enveloped); #if (false) // DSIE: New format does not sign KeyInfo. // Add the key info reference. Reference strongNameKeyInfo = new Reference(); strongNameKeyInfo.Uri = "#StrongNameKeyInfo"; strongNameKeyInfo.AddTransform(new XmlDsigExcC14NTransform()); signedXml.AddReference(strongNameKeyInfo); #endif // Compute the signature. signedXml.ComputeSignature(); // Get the XML representation XmlElement xmlDigitalSignature = signedXml.GetXml(); xmlDigitalSignature.SetAttribute("Id", "StrongNameSignature"); // Insert the signature now. signatureParent.AppendChild(xmlDigitalSignature); }
private static void AuthenticodeSignLicenseDom(XmlDocument licenseDom, CmiManifestSigner2 signer, string timeStampUrl, bool useSha256) { // Make sure it is RSA, as this is the only one Fusion will support. RSA rsaPrivateKey = CngLightup.GetRSAPrivateKey(signer.Certificate); if (rsaPrivateKey == null) { throw new NotSupportedException(); } // Setup up XMLDSIG engine. ManifestSignedXml2 signedXml = new ManifestSignedXml2(licenseDom); // only needs to change the provider type when RSACryptoServiceProvider is used var rsaCsp = rsaPrivateKey is RSACryptoServiceProvider? GetFixedRSACryptoServiceProvider(rsaPrivateKey as RSACryptoServiceProvider, useSha256) : rsaPrivateKey; signedXml.SigningKey = rsaCsp; signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; if (signer.UseSha256) { signedXml.SignedInfo.SignatureMethod = Sha256SignatureMethodUri; } else { signedXml.SignedInfo.SignatureMethod = Sha1SignatureMethodUri; } // Add the key information. signedXml.KeyInfo.AddClause(new RSAKeyValue(rsaCsp)); signedXml.KeyInfo.AddClause(new KeyInfoX509Data(signer.Certificate, signer.IncludeOption)); // Add the enveloped reference. Reference reference = new Reference(); reference.Uri = ""; if (signer.UseSha256) { reference.DigestMethod = Sha256DigestMethod; } else { reference.DigestMethod = Sha1DigestMethod; } // Add an enveloped and an Exc-C14N transform. reference.AddTransform(new XmlDsigEnvelopedSignatureTransform()); #if (false) // BUGBUG: LTA transform complaining about issuer node not found. reference.AddTransform(new XmlLicenseTransform()); #endif reference.AddTransform(new XmlDsigExcC14NTransform()); // Add the reference. signedXml.AddReference(reference); // Compute the signature. signedXml.ComputeSignature(); // Get the XML representation XmlElement xmlDigitalSignature = signedXml.GetXml(); xmlDigitalSignature.SetAttribute("Id", "AuthenticodeSignature"); // Insert the signature node under the issuer element. XmlNamespaceManager nsm = new XmlNamespaceManager(licenseDom.NameTable); nsm.AddNamespace("r", LicenseNamespaceUri); XmlElement issuerNode = licenseDom.SelectSingleNode("r:license/r:issuer", nsm) as XmlElement; issuerNode.AppendChild(licenseDom.ImportNode(xmlDigitalSignature, true)); // Time stamp it if requested. if (timeStampUrl != null && timeStampUrl.Length != 0) { TimestampSignedLicenseDom(licenseDom, timeStampUrl); } // Wrap it inside a RelData element. licenseDom.DocumentElement.ParentNode.InnerXml = "<msrel:RelData xmlns:msrel=\"" + MSRelNamespaceUri + "\">" + licenseDom.OuterXml + "</msrel:RelData>"; }