File: Verification\PortableExecutableVerifier.cs
Web Access
Project: src\src\SignCheck\Microsoft.SignCheck\Microsoft.DotNet.SignCheckLibrary.csproj (Microsoft.DotNet.SignCheckLibrary)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.IO;
using Microsoft.SignCheck.Interop.PortableExecutable;
using Microsoft.SignCheck.Logging;
using Microsoft.DotNet.StrongName;
 
namespace Microsoft.SignCheck.Verification
{
    /// <summary>
    /// A generic verifier for portable executables (EXEs and DLLs).
    /// </summary>
    public class PortableExecutableVerifier : AuthentiCodeVerifier
    {
        protected PortableExecutableHeader PEHeader
        {
            get;
            private set;
        }
 
        public PortableExecutableVerifier(Log log, Exclusions exclusions, SignatureVerificationOptions options, string fileExtension) :
            base(log, exclusions, options, fileExtension)
        {
            FinalizeResult = false;            
        }
 
        /// <summary>
        /// Verify whether the portable executable contains an AuthentiCode signature and optionally check the
        /// StrongName signature if it is enabled and the file represents a managed code executable.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="parent"></param>
        /// <returns></returns>
        public override SignatureVerificationResult VerifySignature(string path, string parent, string virtualPath)
        {
            // Defer to the base implementation to check the AuthentiCode signature.
            SignatureVerificationResult svr = base.VerifySignature(path, parent, virtualPath);
            PEHeader = new PortableExecutableHeader(svr.FullPath);
 
            if (VerifyStrongNameSignature)
            {
                VerifyStrongName(svr);
 
                svr.IsIgnoreStrongName = Exclusions.IsIgnoreStrongName(Path.GetFileName(svr.VirtualPath), parent, svr.VirtualPath, null);
                if (svr.IsIgnoreStrongName)
                {
                    svr.AddDetail(DetailKeys.StrongName, $"Ignoring strong-name result because file is IGNORE-STRONG-NAME.");
                }
            }
 
            svr.IsSigned = svr.IsAuthentiCodeSigned & (svr.IsStrongNameSigned || !VerifyStrongNameSignature || svr.IsNativeImage || svr.IsIgnoreStrongName);
            svr.AddDetail(DetailKeys.File, SignCheckResources.DetailSigned, svr.IsSigned);
 
            return svr;
        }
 
        private void VerifyStrongName(SignatureVerificationResult svr)
        {
            if (PEHeader.IsManagedCode && PEHeader.IsILImage)
            {
                VerifyManagedStrongName(svr);
            }
            else
            {
                // NGEN/CrossGen don't preserve StrongName signatures.
                svr.IsNativeImage = true;
                svr.AddDetail(DetailKeys.StrongName, SignCheckResources.DetailNativeImage);
            }
        }
 
        private void VerifyManagedStrongName(SignatureVerificationResult svr)
        {
            svr.IsStrongNameSigned = StrongNameHelper.IsSigned(svr.FullPath);
            svr.AddDetail(DetailKeys.StrongName, SignCheckResources.DetailSignedStrongName, svr.IsStrongNameSigned);
 
            if (svr.IsStrongNameSigned)
            {
                if (StrongNameHelper.GetStrongNameTokenFromAssembly(svr.FullPath, out string tokenStr) == 0)
                {
                    svr.AddDetail(DetailKeys.StrongName, SignCheckResources.DetailPublicKeyToken, tokenStr);
                }
                else
                {
                    svr.AddDetail(DetailKeys.Error, SignCheckResources.ErrorInvalidOrMissingStrongNamePublicKeyToken);
                }
            }
        }
    }
}