// 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); }
// 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); } } }