/// <summary> /// Utility method to verify that mp was signed by Microsoft /// </summary> /// <param name="filePath">Path to the file to check the signature on.</param> public static void VerifyFileSignedByMicrosoft(string filePath, Tracing trace, string expectedEKU = CODE_SIGNING_ENHANCED_KEY_USAGE) { // proceed with authenticode checks WinTrustData winTrustData = VerifyFileAuthenticodeSignatureHelper(filePath, trace); try { IntPtr pProviderData = UnsafeNativeMethods.WTHelperProvDataFromStateData(winTrustData.StateData); if (pProviderData == IntPtr.Zero) { throw new Win32Exception(string.Format(CultureInfo.CurrentCulture, "File {0} WTHelperProvDataFromStateData returned null.", filePath)); } IntPtr pSigner = UnsafeNativeMethods.WTHelperGetProvSignerFromChain(pProviderData, 0, false, 0); if (pSigner == IntPtr.Zero) { throw new Win32Exception(string.Format(CultureInfo.CurrentCulture, "File {0} WTHelperGetProvSignerFromChain returned null.", filePath)); } CRYPT_PROVIDER_SGNR provSigner = (CRYPT_PROVIDER_SGNR)Marshal.PtrToStructure(pSigner, typeof(CRYPT_PROVIDER_SGNR)); CERT_CHAIN_POLICY_PARA policyPara = new CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_PARA))); CERT_CHAIN_POLICY_STATUS policyStatus = new CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_STATUS))); if (!UnsafeNativeMethods.CertVerifyCertificateChainPolicy( new IntPtr(UnsafeNativeMethods.CERT_CHAIN_POLICY_MICROSOFT_ROOT), provSigner.pChainContext, ref policyPara, ref policyStatus)) { throw new Win32Exception(string.Format(CultureInfo.CurrentCulture, "File {0} CertVerifyCertificateChainPolicy wasn't able to check for the policy", filePath)); } //If using SHA-2 validation the root certificate is different from the older SHA-1 certificate if (policyStatus.dwError != 0) { policyPara.dwFlags = UnsafeNativeMethods.MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG; if (!UnsafeNativeMethods.CertVerifyCertificateChainPolicy( new IntPtr(UnsafeNativeMethods.CERT_CHAIN_POLICY_MICROSOFT_ROOT), provSigner.pChainContext, ref policyPara, ref policyStatus)) { throw new Win32Exception(string.Format(CultureInfo.CurrentCulture, "File {0} CertVerifyCertificateChainPolicy wasn't able to check for the policy", filePath)); } if (policyStatus.dwError != 0) { #if DEBUG { policyPara.dwFlags = UnsafeNativeMethods.MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG; if (!UnsafeNativeMethods.CertVerifyCertificateChainPolicy( new IntPtr(UnsafeNativeMethods.CERT_CHAIN_POLICY_MICROSOFT_ROOT), provSigner.pChainContext, ref policyPara, ref policyStatus)) { throw new Win32Exception(string.Format(CultureInfo.CurrentCulture, "File {0} CertVerifyCertificateChainPolicy wasn't able to check for the policy", filePath)); } if (policyStatus.dwError != 0) { trace.Error("policyStatus: " + policyStatus.ToString()); trace.Error("policyStatus.pvExtraPolicyStatus: " + policyStatus.pvExtraPolicyStatus); trace.Error(String.Format("Error occurred while calling WinVerifyTrust: {0}", string.Format(CultureInfo.CurrentCulture, "File {0} does not have a valid MS or ms-test signature.", filePath))); // throw new VerificationException(string.Format(CultureInfo.CurrentCulture, "File {0} does not have a valid MS or ms-test signature.", filePath)); } } #else throw new VerificationException(string.Format(CultureInfo.CurrentCulture, "File {0} does not have a valid MS signature.", filePath)); #endif } } trace.Info(String.Format("File {0} has a valid MS or ms-test signature.", filePath)); // Get the certificate used to sign the file IntPtr pProviderCertificate = UnsafeNativeMethods.WTHelperGetProvCertFromChain(pSigner, 0); if (pProviderCertificate == IntPtr.Zero) { throw new Win32Exception(string.Format(CultureInfo.CurrentCulture, "WTHelperGetProvCertFromChain returned null.")); } CRYPT_PROVIDER_CERT provCert = (CRYPT_PROVIDER_CERT)Marshal.PtrToStructure(pProviderCertificate, typeof(CRYPT_PROVIDER_CERT)); // Check for our EKU in the certificate using (X509Certificate2 x509Cert = new X509Certificate2(provCert.pCert)) { if (((X509EnhancedKeyUsageExtension)x509Cert.Extensions[EXTENDED_KEY_USAGE]).EnhancedKeyUsages[expectedEKU] == null) { // throw new exception throw new VerificationException(string.Format(CultureInfo.CurrentCulture, "Authenticode signature for file {0} is not signed with a certificate containing the EKU {1}.", filePath, expectedEKU)); } trace.Info(String.Format("Authenticode signature for file {0} is signed with a certificate containing the EKU {1}.", filePath, expectedEKU)); } } finally { // dispose winTrustData object winTrustData.Dispose(); } }
internal static extern bool CertVerifyCertificateChainPolicy( IntPtr pszPolicyOID, IntPtr pChainContext, ref CERT_CHAIN_POLICY_PARA pPolicyPara, [In, Out] ref CERT_CHAIN_POLICY_STATUS pPolicyStatus);