private CryptoError GetCertInfo(IntPtr hWVTStateData, out Native.CERT_INFO certInfo, out string failedApiName) { certInfo = new Native.CERT_INFO(); failedApiName = "WTHelperProvDataFromStateData"; IntPtr providerData = Native.WTHelperProvDataFromStateData(hWVTStateData); if (providerData == IntPtr.Zero) { return((CryptoError)Marshal.GetLastWin32Error()); } failedApiName = "WTHelperGetProvSignerFromChain"; IntPtr providerSigner = Native.WTHelperGetProvSignerFromChain(providerData, 0, false, 0); if (providerSigner == IntPtr.Zero) { return((CryptoError)Marshal.GetLastWin32Error()); } var cryptProviderSigner = (Native.CRYPT_PROVIDER_SGNR)Marshal.PtrToStructure(providerSigner, typeof(Native.CRYPT_PROVIDER_SGNR)); var cryptoError = (CryptoError)cryptProviderSigner.dwError; if (cryptProviderSigner.pChainContext != IntPtr.Zero) { var chainContext = (Native.CERT_CHAIN_CONTEXT)Marshal.PtrToStructure(cryptProviderSigner.pChainContext, typeof(Native.CERT_CHAIN_CONTEXT)); IntPtr[] simpleChains = new IntPtr[chainContext.cChain]; Marshal.Copy(chainContext.rgpChain, simpleChains, 0, simpleChains.Length); var certChain = (Native.CERT_SIMPLE_CHAIN)Marshal.PtrToStructure(simpleChains[0], typeof(Native.CERT_SIMPLE_CHAIN)); IntPtr[] chainElements = new IntPtr[certChain.cElement]; Marshal.Copy(certChain.rgpElement, chainElements, 0, chainElements.Length); var certElement = (Native.CERT_CHAIN_ELEMENT)Marshal.PtrToStructure(chainElements[0], typeof(Native.CERT_CHAIN_ELEMENT)); var certContext = (Native.CERT_CONTEXT)Marshal.PtrToStructure(certElement.pCertContext, typeof(Native.CERT_CONTEXT)); certInfo = (Native.CERT_INFO)Marshal.PtrToStructure(certContext.pCertInfo, typeof(Native.CERT_INFO)); } if (cryptoError == CryptoError.ERROR_SUCCESS) { failedApiName = null; } return(cryptoError); }
private string RetrieveSignatureAlgorithmAndCertInfo( BinaryAnalyzerContext context, Native.WINTRUST_DATA winTrustData, out Native.CERT_INFO certInfo) { string failedApiName; CryptoError cryptoError; cryptoError = GetCertInfo(winTrustData.hWVTStateData, out certInfo, out failedApiName); if (cryptoError != CryptoError.ERROR_SUCCESS) { // '{0}' signing could not be completely verified because // '{1}' failed with error code: '{2}'. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2022_Error_WinTrustVerifyApiError), failedApiName, cryptoError.ToString())); return(null); } return(GetAlgorithmName(certInfo.SignatureAlgorithm.pszObjId)); }
private bool InvokeVerifyAction( BinaryAnalyzerContext context, string filePath, out Native.WINTRUST_DATA winTrustData, out string algorithmNames) { Guid action; CryptoError cryptoError; HashSet<string> badAlgorithms = new HashSet<string>(); HashSet<string> goodAlgorithms = new HashSet<string>(); var certInfo = new Native.CERT_INFO(); algorithmNames = null; action = Native.ActionGenericVerifyV2; uint signatureCount = 1; // First, we retrieve the signature count winTrustData = InitializeWinTrustDataStruct(filePath, WinTrustDataKind.SignatureCount); Native.WinVerifyTrust(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); if (winTrustData.pSignatureSettings != IntPtr.Zero) { var signatureSettings = Marshal.PtrToStructure<Native.WINTRUST_SIGNATURE_SETTINGS>(winTrustData.pSignatureSettings); signatureCount = signatureSettings.cSecondarySigs + 1; // Total count primary + cSecondary } InvokeCloseAction(winTrustData); // First, we will invoke the basic verification on all returned // signatures. Note that currently this code path does not reach across // the network to perform its function. We could optionally // enable this (which would require altering the code that initializes // our WINTRUST_DATA instance). for (uint i = 0; i < signatureCount; i++) { string algorithmName; winTrustData = InitializeWinTrustDataStruct(filePath, WinTrustDataKind.EnforcePolicy, i); cryptoError = (CryptoError)Native.WinVerifyTrust(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); switch (cryptoError) { case CryptoError.ERROR_SUCCESS: { // Hash that represents the subject is trusted. // Trusted publisher with no verification errors. // No publisher or time stamp errors. // This verification excludes root chain info. algorithmName = RetrieveSignatureAlgorithmAndCertInfo(context, winTrustData, out certInfo); goodAlgorithms.Add(algorithmName); InvokeCloseAction(winTrustData); break; } case CryptoError.NTE_BAD_ALGID: { InvokeCloseAction(winTrustData); // We cannot retrieve algorithm id and cert info for images that fail // the stringent WinTrustVerify security check. We therefore start // a new call chain with looser validation criteria. winTrustData = InitializeWinTrustDataStruct(filePath, WinTrustDataKind.Normal); Native.WinVerifyTrust(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); algorithmName = RetrieveSignatureAlgorithmAndCertInfo(context, winTrustData, out certInfo); badAlgorithms.Add(algorithmName); InvokeCloseAction(winTrustData); break; } case CryptoError.TRUST_E_NOSIGNATURE: { Notes.LogNotApplicableToSpecifiedTarget(context, MetadataConditions.ImageIsNotSigned); return false; } default: { string cryptoErrorDescription = cryptoError.GetErrorDescription(); // '{0}' signing was flagged as insecure by WinTrustVerify with error code: '{1}' ({2}) context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2022_Error_DidNotVerify), context.TargetUri.GetFileName(), cryptoError.ToString(), cryptoErrorDescription)); InvokeCloseAction(winTrustData); return false; } } } if (goodAlgorithms.Count == 0) { // '{0}' was signed using '{1}', algorithm(s) that WinTrustVerify has flagged as insecure. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2022_Error_BadSigningAlgorithm), context.TargetUri.GetFileName(), string.Join(",", badAlgorithms.ToArray()))); } else { algorithmNames = string.Join(",", goodAlgorithms.ToArray()); } return goodAlgorithms.Count > 0; }
private CryptoError GetCertInfo(IntPtr hWVTStateData, out Native.CERT_INFO certInfo, out string failedApiName) { certInfo = new Native.CERT_INFO(); failedApiName = "WTHelperProvDataFromStateData"; IntPtr providerData = Native.WTHelperProvDataFromStateData(hWVTStateData); if (providerData == IntPtr.Zero) { return (CryptoError)Marshal.GetLastWin32Error(); } failedApiName = "WTHelperGetProvSignerFromChain"; IntPtr providerSigner = Native.WTHelperGetProvSignerFromChain(providerData, 0, false, 0); if (providerSigner == IntPtr.Zero) { return (CryptoError)Marshal.GetLastWin32Error(); } var cryptProviderSigner = (Native.CRYPT_PROVIDER_SGNR)Marshal.PtrToStructure(providerSigner, typeof(Native.CRYPT_PROVIDER_SGNR)); var cryptoError = (CryptoError)cryptProviderSigner.dwError; if (cryptProviderSigner.pChainContext != IntPtr.Zero) { var chainContext = (Native.CERT_CHAIN_CONTEXT)Marshal.PtrToStructure(cryptProviderSigner.pChainContext, typeof(Native.CERT_CHAIN_CONTEXT)); IntPtr[] simpleChains = new IntPtr[chainContext.cChain]; Marshal.Copy(chainContext.rgpChain, simpleChains, 0, simpleChains.Length); var certChain = (Native.CERT_SIMPLE_CHAIN)Marshal.PtrToStructure(simpleChains[0], typeof(Native.CERT_SIMPLE_CHAIN)); IntPtr[] chainElements = new IntPtr[certChain.cElement]; Marshal.Copy(certChain.rgpElement, chainElements, 0, chainElements.Length); var certElement = (Native.CERT_CHAIN_ELEMENT)Marshal.PtrToStructure(chainElements[0], typeof(Native.CERT_CHAIN_ELEMENT)); var certContext = (Native.CERT_CONTEXT)Marshal.PtrToStructure(certElement.pCertContext, typeof(Native.CERT_CONTEXT)); certInfo = (Native.CERT_INFO)Marshal.PtrToStructure(certContext.pCertInfo, typeof(Native.CERT_INFO)); } if (cryptoError == CryptoError.ERROR_SUCCESS) { failedApiName = null; } return cryptoError; }
private bool InvokeVerifyAction( BinaryAnalyzerContext context, string filePath, out Native.WINTRUST_DATA winTrustData, out string algorithmName) { Guid action; bool continueProcessing; CryptoError cryptoError; continueProcessing = false; var certInfo = new Native.CERT_INFO(); winTrustData = InitializeWinTrustDataStruct(filePath, enforcePolicy: true); algorithmName = null; // First, we will invoke the basic verification. Note that currently this code path // does not reach across the network to perform its function. We could optionally // enable this (which would require altering the code that initializes our // WINTRUST_DATA instance). action = Native.ActionGenericVerifyV2; cryptoError = (CryptoError)Native.WinVerifyTrust(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); InvokeCloseAction(winTrustData); // We cannot retrieve algorithm id and cert info for images that fail // the stringent WinTrustVerify security check. We therefore start // a new call chain with looser validation criteria. winTrustData = InitializeWinTrustDataStruct(filePath, enforcePolicy: false); Native.WinVerifyTrust(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); switch (cryptoError) { case CryptoError.ERROR_SUCCESS: { // Hash that represents the subject is trusted. // Trusted publisher with no verification errors. // No publisher or time stamp errors. // This verification excludes root chain info. algorithmName = RetrieveSignatureAlgorithmAndCertInfo(context, winTrustData, out certInfo); continueProcessing = true; break; } case CryptoError.NTE_BAD_ALGID: { algorithmName = RetrieveSignatureAlgorithmAndCertInfo(context, winTrustData, out certInfo); if (algorithmName != null) // If null, we have already logged an error { // '{0}' was signed using '{1}', an algorithm that WinTrustVerify has flagged as insecure. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2022_Error_BadSigningAlgorithm), algorithmName)); } break; } case CryptoError.TRUST_E_NOSIGNATURE: { Notes.LogNotApplicableToSpecifiedTarget(context, MetadataConditions.ImageIsNotSigned); break; } default: { string cryptoErrorDescription = cryptoError.GetErrorDescription(); // '{0}' signing was flagged as insecure by WinTrustVerify with error code: '{1}' ({2}) context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2022_Error_DidNotVerify), cryptoError.ToString(), cryptoErrorDescription)); break; } } return(continueProcessing); }
private bool InvokeVerifyAction( BinaryAnalyzerContext context, string filePath, out Native.WINTRUST_DATA winTrustData, out string algorithmNames) { Guid action; CryptoError cryptoError; HashSet <string> badAlgorithms = new HashSet <string>(); HashSet <string> goodAlgorithms = new HashSet <string>(); var certInfo = new Native.CERT_INFO(); algorithmNames = null; action = Native.ActionGenericVerifyV2; uint signatureCount = 1; // First, we retrieve the signature count winTrustData = InitializeWinTrustDataStruct(filePath, WinTrustDataKind.SignatureCount); Native.WinVerifyTrust(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); if (winTrustData.pSignatureSettings != IntPtr.Zero) { var signatureSettings = Marshal.PtrToStructure <Native.WINTRUST_SIGNATURE_SETTINGS>(winTrustData.pSignatureSettings); signatureCount = signatureSettings.cSecondarySigs + 1; // Total count primary + cSecondary } InvokeCloseAction(winTrustData); // First, we will invoke the basic verification on all returned // signatures. Note that currently this code path does not reach across // the network to perform its function. We could optionally // enable this (which would require altering the code that initializes // our WINTRUST_DATA instance). for (uint i = 0; i < signatureCount; i++) { string algorithmName; winTrustData = InitializeWinTrustDataStruct(filePath, WinTrustDataKind.EnforcePolicy, i); cryptoError = (CryptoError)Native.WinVerifyTrust(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); switch (cryptoError) { case CryptoError.ERROR_SUCCESS: { // Hash that represents the subject is trusted. // Trusted publisher with no verification errors. // No publisher or time stamp errors. // This verification excludes root chain info. algorithmName = RetrieveSignatureAlgorithmAndCertInfo(context, winTrustData, out certInfo); goodAlgorithms.Add(algorithmName); InvokeCloseAction(winTrustData); break; } case CryptoError.NTE_BAD_ALGID: { InvokeCloseAction(winTrustData); // We cannot retrieve algorithm id and cert info for images that fail // the stringent WinTrustVerify security check. We therefore start // a new call chain with looser validation criteria. winTrustData = InitializeWinTrustDataStruct(filePath, WinTrustDataKind.Normal); Native.WinVerifyTrust(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); algorithmName = RetrieveSignatureAlgorithmAndCertInfo(context, winTrustData, out certInfo); badAlgorithms.Add(algorithmName); InvokeCloseAction(winTrustData); break; } case CryptoError.TRUST_E_NOSIGNATURE: { Notes.LogNotApplicableToSpecifiedTarget(context, MetadataConditions.ImageIsNotSigned); return(false); } default: { string cryptoErrorDescription = cryptoError.GetErrorDescription(); // '{0}' signing was flagged as insecure by WinTrustVerify with error code: '{1}' ({2}) context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2022_Error_DidNotVerify), context.TargetUri.GetFileName(), cryptoError.ToString(), cryptoErrorDescription)); InvokeCloseAction(winTrustData); return(false); } } } if (goodAlgorithms.Count == 0) { // '{0}' was signed using '{1}', algorithm(s) that WinTrustVerify has flagged as insecure. context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2022_Error_BadSigningAlgorithm), context.TargetUri.GetFileName(), string.Join(",", badAlgorithms.ToArray()))); } else { algorithmNames = string.Join(",", goodAlgorithms.ToArray()); } return(goodAlgorithms.Count > 0); }