private void InvokeCloseAction(Native.WINTRUST_DATA winTrustData) { Guid action = Native.ActionGenericVerifyV2; winTrustData.StateAction = Native.StateAction.WTD_STATEACTION_CLOSE; Native.WinVerifyTrustWrapper(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); if (winTrustData.pFile != IntPtr.Zero) { Marshal.DestroyStructure(winTrustData.pFile, typeof(Native.WINTRUST_FILE_INFO)); Marshal.FreeHGlobal(winTrustData.pFile); } if (winTrustData.pSignatureSettings != IntPtr.Zero) { var signatureSettings = Marshal.PtrToStructure <Native.WINTRUST_SIGNATURE_SETTINGS>(winTrustData.pSignatureSettings); if (signatureSettings.pCryptoPolicy != IntPtr.Zero) { Marshal.DestroyStructure(signatureSettings.pCryptoPolicy, typeof(Native.CERT_STRONG_SIGN_PARA)); Marshal.FreeHGlobal(signatureSettings.pCryptoPolicy); } Marshal.DestroyStructure(winTrustData.pSignatureSettings, typeof(Native.WINTRUST_SIGNATURE_SETTINGS)); Marshal.FreeHGlobal(winTrustData.pSignatureSettings); } }
private bool InvokeVerifyAction( BinaryAnalyzerContext context, string filePath, out Native.WINTRUST_DATA winTrustData, out string algorithmsText) { Guid action; CryptoError cryptoError; var badAlgorithms = new List <Tuple <string, string> >(); var goodAlgorithms = new List <Tuple <string, string> >(); algorithmsText = null; action = Native.ActionGenericVerifyV2; uint signatureCount = 1; // First, we retrieve the signature count winTrustData = InitializeWinTrustDataStruct(filePath, WinTrustDataKind.SignatureCount); Native.WinVerifyTrustWrapper(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 hashAlgorithm, hashEncryptionAlgorithm; winTrustData = InitializeWinTrustDataStruct(filePath, WinTrustDataKind.EnforcePolicy, i); cryptoError = (CryptoError)Native.WinVerifyTrustWrapper(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); switch (cryptoError) { // The SignSecurely check mostly validates signing algorithm strength. The // error conditions are expected in some scan contexts, for example, an // isolated build environment which hasn't been configured to trust the // signing root. Providing a more complex signing validation would require // BinSkim to be significantly more configurable to provide information on // the scan environment as well as the scan targets. case CryptoError.CERT_E_UNTRUSTEDROOT: case CryptoError.CERT_E_CHAINING: 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. if (GetSignerHashAlgorithms(context, winTrustData, out hashAlgorithm, out hashEncryptionAlgorithm)) { goodAlgorithms.Add(new Tuple <string, string>(hashAlgorithm, hashEncryptionAlgorithm)); } 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.WinVerifyTrustWrapper(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData); if (GetSignerHashAlgorithms(context, winTrustData, out hashAlgorithm, out hashEncryptionAlgorithm)) { badAlgorithms.Add(new Tuple <string, string>(hashAlgorithm, hashEncryptionAlgorithm)); } 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(FailureLevel.Error, context, null, nameof(RuleResources.BA2022_Error_DidNotVerify), context.TargetUri.GetFileName(), cryptoError.ToString(), cryptoErrorDescription)); InvokeCloseAction(winTrustData); return(false); } } } algorithmsText = BuildAlgorithmsText(badAlgorithms, goodAlgorithms); if (goodAlgorithms.Count == 0) { // '{0}' was signed exclusively with algorithms that WinTrustVerify has flagged as insecure. {1} context.Logger.Log(this, RuleUtilities.BuildResult(FailureLevel.Error, context, null, nameof(RuleResources.BA2022_Error_BadSigningAlgorithm), context.TargetUri.GetFileName(), algorithmsText)); } return(goodAlgorithms.Count > 0); }