예제 #1
0
        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);
            }
        }
예제 #2
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            // Uses Windows Certificate Interop
            BinaryParsers.PlatformSpecificHelpers.ThrowIfNotOnWindows();
            PEBinary target = context.PEBinary();

            Native.WINTRUST_DATA winTrustData;
            string algorithmName, filePath;

            filePath = target.PE.FileName;

            winTrustData = new Native.WINTRUST_DATA();

            if (InvokeVerifyAction(context, filePath, out winTrustData, out algorithmName))
            {
                // '{0}' appears to be signed securely by a trusted publisher with no
                // verification or time stamp errors. Revocation checking was performed
                // on the entire certificate chain, excluding the root certificate.
                // The following digitial signature algorithms were detected: {1}
                context.Logger.Log(this,
                                   RuleUtilities.BuildResult(ResultKind.Pass, context, null,
                                                             nameof(RuleResources.BA2022_Pass),
                                                             context.TargetUri.GetFileName(),
                                                             algorithmName));
            }
        }
예제 #3
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            Native.WINTRUST_DATA winTrustData;
            string algorithmName, filePath;

            filePath = context.PE.FileName;

            winTrustData = new Native.WINTRUST_DATA();

            try
            {
                if (InvokeVerifyAction(context, filePath, out winTrustData, out algorithmName))
                {
                    // '{0}' appears to be signed securely by a trusted publisher with
                    // no verification or time stamp errors. Revocation checking was
                    // performed on the entire certificate chain, excluding the root
                    // certificate. The image was signed with '{1}', a
                    // cryptographically strong algorithm.
                    context.Logger.Log(this,
                                       RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                                                                 nameof(RuleResources.BA2022_Pass),
                                                                 algorithmName));
                }
            }
            finally
            {
                if (winTrustData.hWVTStateData != IntPtr.Zero)
                {
                    InvokeCloseAction(winTrustData);
                }
            }
        }
예제 #4
0
        private bool GetSignerHashAlgorithms(
            BinaryAnalyzerContext context,
            Native.WINTRUST_DATA winTrustData,
            out string hashAlgorithm,
            out string hashEncryptionAlgorithm)
        {
            string      failedApiName;
            CryptoError cryptoError;

            cryptoError = GetSignerHashAlgorithms(
                winTrustData.hWVTStateData,
                out hashAlgorithm,
                out hashEncryptionAlgorithm,
                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(FailureLevel.Error, context, null,
                                                                   nameof(RuleResources.BA2022_Error_WinTrustVerifyApiError),
                                                                   context.TargetUri.GetFileName(),
                                                                   failedApiName,
                                                                   cryptoError.ToString()));
                return(false);
            }

            return(true);
        }
예제 #5
0
        private CryptoError WinVerifyTrustHelper(IntPtr handle, ref Native.WINTRUST_DATA winTrustData)
        {
            Guid        action;
            CryptoError cryptoError;

            action      = Native.ActionGenericVerifyV2;
            cryptoError = (CryptoError)Native.WinVerifyTrust(handle, ref action, ref winTrustData);

            return(cryptoError);
        }
예제 #6
0
        private Native.WINTRUST_DATA InitializeWinTrustDataStruct(string filePath, bool enforcePolicy)
        {
            // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa382384(v=vs.85).aspx
            // which was used to drive data initialization, API use and comments in this code.

            var winTrustData = new Native.WINTRUST_DATA();

            winTrustData.cbStruct = (uint)Marshal.SizeOf(typeof(Native.WINTRUST_DATA));

            var fileInfo = new Native.WINTRUST_FILE_INFO();

            fileInfo.cbStruct      = (uint)Marshal.SizeOf(typeof(Native.WINTRUST_FILE_INFO));
            fileInfo.pcwszFilePath = filePath;

            winTrustData.pFile = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Native.WINTRUST_FILE_INFO)));
            Marshal.StructureToPtr(fileInfo, winTrustData.pFile, false);

            winTrustData.pPolicyCallbackData = IntPtr.Zero;                                                  // Use default code signing EKU
            winTrustData.pSIPClientData      = IntPtr.Zero;                                                  // No data to pass to SIP
            winTrustData.UIChoice            = Native.UIChoice.WTD_UI_NONE;                                  // Disable all UI on execution
            winTrustData.UIContext           = 0;
            winTrustData.UIContext           = Native.UIContext.WTD_UICONTEXT_EXECUTE;                       // File is intended to be executed
            winTrustData.UnionChoice         = Native.UnionChoice.WTD_CHOICE_FILE;                           // We're verifying a file
            winTrustData.RevocationChecks    = Native.RevocationChecks.WTD_REVOKE_WHOLECHAIN;                // Revocation checking on whole chain.
            winTrustData.dwProvFlags         = Native.ProviderFlags.WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; // Don't reach across the network
            winTrustData.dwProvFlags        |= Native.ProviderFlags.WTD_CACHE_ONLY_URL_RETRIEVAL;

            winTrustData.pwszURLReference = null;                                                     // Reserved for future use

            winTrustData.StateAction   = Native.StateAction.WTD_STATEACTION_VERIFY;
            winTrustData.hWVTStateData = IntPtr.Zero; // This value set by API call

            if (enforcePolicy)
            {
                var signatureSettings = new Native.WINTRUST_SIGNATURE_SETTINGS();
                signatureSettings.cbStruct           = (uint)Marshal.SizeOf(typeof(Native.WINTRUST_SIGNATURE_SETTINGS));
                signatureSettings.dwIndex            = 0;
                signatureSettings.dwFlags            = Native.SignatureSettingsFlags.WSS_VERIFY_SPECIFIC;
                signatureSettings.cSecondarySigs     = 0;
                signatureSettings.dwVerifiedSigIndex = 0;

                var policy = new Native.CERT_STRONG_SIGN_PARA();
                policy.cbStruct     = (uint)Marshal.SizeOf(typeof(Native.CERT_STRONG_SIGN_PARA));
                policy.dwInfoChoice = Native.InfoChoice.CERT_STRONG_SIGN_OID_INFO_CHOICE;
                policy.pszOID       = Native.szOID_CERT_STRONG_SIGN_OS_1;

                signatureSettings.pCryptoPolicy = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Native.CERT_STRONG_SIGN_PARA)));
                Marshal.StructureToPtr(policy, signatureSettings.pCryptoPolicy, false);

                winTrustData.pSignatureSettings = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Native.WINTRUST_SIGNATURE_SETTINGS)));
                Marshal.StructureToPtr(signatureSettings, winTrustData.pSignatureSettings, false);
            }

            return(winTrustData);
        }
예제 #7
0
        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));
        }
예제 #8
0
        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);
        }
예제 #9
0
        public override void Analyze(BinaryAnalyzerContext context)
        {
            Native.WINTRUST_DATA winTrustData;
            string algorithmName, filePath;

            filePath = context.PE.FileName;

            winTrustData = new Native.WINTRUST_DATA();

            if (InvokeVerifyAction(context, filePath, out winTrustData, out algorithmName))
            {
                // '{0}' appears to be signed securely by a trusted publisher with
                // no verification or time stamp errors. Revocation checking was
                // performed on the entire certificate chain, excluding the root
                // certificate. The image was signed with '{1}',
                // cryptographically strong algorithm(s).
                context.Logger.Log(this,
                    RuleUtilities.BuildResult(ResultLevel.Pass, context, null,
                        nameof(RuleResources.BA2022_Pass),
                        context.TargetUri.GetFileName(),
                        algorithmName));
            }
        }
예제 #10
0
        private Native.WINTRUST_DATA InitializeWinTrustDataStruct(string filePath, WinTrustDataKind kind, uint signatureIndex = 0)
        {
            // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa382384(v=vs.85).aspx
            // which was used to drive data initialization, API use and comments in this code.

            var winTrustData = new Native.WINTRUST_DATA();
            winTrustData.cbStruct = (uint)Marshal.SizeOf(typeof(Native.WINTRUST_DATA));

            var fileInfo = new Native.WINTRUST_FILE_INFO();
            fileInfo.cbStruct = (uint)Marshal.SizeOf(typeof(Native.WINTRUST_FILE_INFO));
            fileInfo.pcwszFilePath = filePath;

            winTrustData.pFile = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Native.WINTRUST_FILE_INFO)));
            Marshal.StructureToPtr(fileInfo, winTrustData.pFile, false);

            winTrustData.pPolicyCallbackData = IntPtr.Zero;                                           // Use default code signing EKU
            winTrustData.pSIPClientData = IntPtr.Zero;                                                // No data to pass to SIP
            winTrustData.UIChoice = Native.UIChoice.WTD_UI_NONE;                                      // Disable all UI on execution
            winTrustData.UIContext = 0;
            winTrustData.UIContext = Native.UIContext.WTD_UICONTEXT_EXECUTE;                          // File is intended to be executed
            winTrustData.UnionChoice = Native.UnionChoice.WTD_CHOICE_FILE;                            // We're verifying a file
            winTrustData.RevocationChecks = Native.RevocationChecks.WTD_REVOKE_WHOLECHAIN;            // Revocation checking on whole chain.
            winTrustData.dwProvFlags = Native.ProviderFlags.WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;  // Don't reach across the network
            winTrustData.dwProvFlags |= Native.ProviderFlags.WTD_CACHE_ONLY_URL_RETRIEVAL;

            winTrustData.pwszURLReference = null;                                                     // Reserved for future use

            winTrustData.StateAction = Native.StateAction.WTD_STATEACTION_VERIFY;
            winTrustData.hWVTStateData = IntPtr.Zero; // This value set by API call

            if (kind != WinTrustDataKind.Normal)
            {
                Native.SignatureSettingsFlags flags = Native.SignatureSettingsFlags.WSS_GET_SECONDARY_SIG_COUNT;

                if (kind == WinTrustDataKind.EnforcePolicy)
                {
                    flags = Native.SignatureSettingsFlags.WSS_VERIFY_SPECIFIC;
                }

                var signatureSettings = new Native.WINTRUST_SIGNATURE_SETTINGS();
                signatureSettings.cbStruct = (uint)Marshal.SizeOf(typeof(Native.WINTRUST_SIGNATURE_SETTINGS));
                signatureSettings.dwIndex = signatureIndex;
                signatureSettings.dwFlags = flags;
                signatureSettings.cSecondarySigs = 0;
                signatureSettings.dwVerifiedSigIndex = 0;

                var policy = new Native.CERT_STRONG_SIGN_PARA();
                policy.cbStruct = (uint)Marshal.SizeOf(typeof(Native.CERT_STRONG_SIGN_PARA));
                policy.dwInfoChoice = Native.InfoChoice.CERT_STRONG_SIGN_OID_INFO_CHOICE;
                policy.pszOID = Native.szOID_CERT_STRONG_SIGN_OS_1;

                signatureSettings.pCryptoPolicy = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Native.CERT_STRONG_SIGN_PARA)));
                Marshal.StructureToPtr(policy, signatureSettings.pCryptoPolicy, false);

                winTrustData.pSignatureSettings = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Native.WINTRUST_SIGNATURE_SETTINGS)));
                Marshal.StructureToPtr(signatureSettings, winTrustData.pSignatureSettings, false);
            }

            return winTrustData;
        }
예제 #11
0
        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);
        }
예제 #12
0
        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);
        }