in src/BinSkim.Rules/PERules/BA2022.SignSecurely.cs [69:187]
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 = this.InitializeWinTrustDataStruct(filePath, WinTrustDataKind.SignatureCount);
Native.WinVerifyTrustWrapper(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData);
if (winTrustData.pSignatureSettings != IntPtr.Zero)
{
Native.WINTRUST_SIGNATURE_SETTINGS signatureSettings = Marshal.PtrToStructure<Native.WINTRUST_SIGNATURE_SETTINGS>(winTrustData.pSignatureSettings);
signatureCount = signatureSettings.cSecondarySigs + 1; // Total count primary + cSecondary
}
this.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 = this.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 (this.GetSignerHashAlgorithms(context, winTrustData, out hashAlgorithm, out hashEncryptionAlgorithm))
{
goodAlgorithms.Add(new Tuple<string, string>(hashAlgorithm, hashEncryptionAlgorithm));
}
this.InvokeCloseAction(winTrustData);
break;
}
case CryptoError.NTE_BAD_ALGID:
{
this.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 = this.InitializeWinTrustDataStruct(filePath, WinTrustDataKind.Normal);
Native.WinVerifyTrustWrapper(Native.INVALID_HANDLE_VALUE, ref action, ref winTrustData);
if (this.GetSignerHashAlgorithms(context, winTrustData, out hashAlgorithm, out hashEncryptionAlgorithm))
{
badAlgorithms.Add(new Tuple<string, string>(hashAlgorithm, hashEncryptionAlgorithm));
}
this.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));
this.InvokeCloseAction(winTrustData);
return false;
}
}
}
algorithmsText = this.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;
}