/// <summary>
        /// Verify the signatures of a set of files.
        /// </summary>
        /// <param name="files">A set of files to verify.</param>
        /// <returns>An IEnumerable containing the verification results of each file.</returns>
        public IEnumerable <SignatureVerificationResult> VerifyFiles(IEnumerable <string> files)
        {
            foreach (string file in files)
            {
                // If the file is excluded add a default result
                if (Exclusions.IsExcluded(file, parent: null, containerPath: null))
                {
                    var result = SignatureVerificationResult.ExcludedFileResult(file, parent: null);
                    Results.Add(result);
                }
                else
                {
                    FileVerifier fileVerifier          = GetFileVerifier(file);
                    SignatureVerificationResult result = fileVerifier.VerifySignature(file, parent: null);

                    if ((Options & SignatureVerificationOptions.GenerateExclusion) == SignatureVerificationOptions.GenerateExclusion)
                    {
                        result.ExclusionEntry = String.Join(";", String.Join("|", file, String.Empty), String.Empty, String.Empty);
                        Log.WriteMessage(LogVerbosity.Diagnostic, SignCheckResources.DiagGenerateExclusion, result.Filename, result.ExclusionEntry);
                    }

                    Results.Add(result);
                }
            }

            return(Results);
        }
Example #2
0
        /// <summary>
        /// Verify the signature of a single file.
        /// </summary>
        /// <param name="path">The path of the file on disk to verify.</param>
        /// <param name="parent">The name of parent container, e.g. an MSI or VSIX. Can be null when there is no parent container.</param>
        /// <param name="containerPath">The path of the file in the container. This may differ from the path on disk as containers are flattened. It's
        /// primarily intended to help with exclusions and report more readable names.</param>
        /// <returns>The verification result.</returns>
        public SignatureVerificationResult VerifyFile(string path, string parent, string containerPath)
        {
            Log.WriteMessage(LogVerbosity.Detailed, String.Format(SignCheckResources.ProcessingFile, Path.GetFileName(path), String.IsNullOrEmpty(parent) ? SignCheckResources.NA : parent));

            SignatureVerificationResult svr;

            if (Exclusions.IsExcluded(path, parent, containerPath))
            {
                svr = SignatureVerificationResult.ExcludedFileResult(path, parent);
            }
            else
            {
                FileVerifier fileVerifier = GetFileVerifier(path);
                svr = fileVerifier.VerifySignature(path, parent);
            }

            if (GenerateExclusion)
            {
                svr.ExclusionEntry = String.Join(";", String.Join("|", path, containerPath), parent, String.Empty);
                Log.WriteMessage(LogVerbosity.Diagnostic, SignCheckResources.DiagGenerateExclusion, svr.Filename, svr.ExclusionEntry);
            }

            // Include the full path for top-level files
            if (String.IsNullOrEmpty(parent))
            {
                svr.AddDetail(DetailKeys.File, SignCheckResources.DetailFullName, svr.FullPath);
            }

            return(svr);
        }
        /// <summary>
        /// Adds a new FileVerifier to the manager that can be used to validate a file based on
        /// </summary>
        /// <param name="fileVerifier">The FileVerifier to add.</param>
        public static void AddFileVerifier(FileVerifier fileVerifier)
        {
            if (fileVerifier == null)
            {
                throw new ArgumentNullException("fileVerifier");
            }

            // Let the dictionary throw if we have a duplicate file extension
            _fileVerifiers.Add(fileVerifier.FileExtension, fileVerifier);
        }
Example #4
0
        /// <summary>
        /// Verify the signatures of a set of files.
        /// </summary>
        /// <param name="files">A set of files to verify.</param>
        /// <returns>An IEnumerable containing the verification results of each file.</returns>
        public IEnumerable <SignatureVerificationResult> VerifyFiles(IEnumerable <string> files)
        {
            foreach (string file in files)
            {
                FileVerifier fileVerifier = GetFileVerifier(file);
                Results.Add(fileVerifier.VerifySignature(file, parent: null));
            }

            return(Results);
        }
        /// <summary>
        /// Retrieves a FileVerifier for the specified file. If the file's extension is unknown
        /// a FileVerifier can be assigned based on the file's header.
        /// </summary>
        /// <param name="path">The path of the file.</param>
        /// <returns>A FileVerifier that can verify the file or null if verifier could be found.</returns>
        public static FileVerifier GetFileVerifier(string path)
        {
            string       extension    = Path.GetExtension(path);
            FileVerifier fileVerifier = GetFileVerifierByExtension(extension);

            if (fileVerifier == null)
            {
                fileVerifier = GetFileVerifierByHeader(path);

                if (fileVerifier == null)
                {
                    return(_unsupportedFileVerifier);
                }
            }

            return(fileVerifier);
        }
Example #6
0
        /// <summary>
        /// Verify the signature of a single file.
        /// </summary>
        /// <param name="path">The path of the file on disk to verify.</param>
        /// <param name="parent">The name of parent container, e.g. an MSI or VSIX. Can be null when there is no parent container.</param>
        /// <param name="containerPath">The path of the file in the container. This may differ from the path on disk as containers are flattened. It's
        /// primarily intended to help with exclusions and report more readable names.</param>
        /// <returns>The verification result.</returns>
        public SignatureVerificationResult VerifyFile(string path, string parent, string virtualPath, string containerPath)
        {
            Log.WriteMessage(LogVerbosity.Detailed, String.Format(SignCheckResources.ProcessingFile, Path.GetFileName(path), String.IsNullOrEmpty(parent) ? SignCheckResources.NA : parent));

            FileVerifier fileVerifier       = GetFileVerifier(path);
            SignatureVerificationResult svr = fileVerifier.VerifySignature(path, parent, virtualPath);

            svr.IsDoNotSign = Exclusions.IsDoNotSign(path, parent, virtualPath, containerPath);

            if ((svr.IsDoNotSign) && (svr.IsSigned))
            {
                // Report errors if a DO-NOT-SIGN file is signed.
                svr.AddDetail(DetailKeys.Error, SignCheckResources.DetailDoNotSignFileSigned, svr.Filename);
            }

            if ((!svr.IsDoNotSign) && (!svr.IsSigned))
            {
                svr.IsExcluded = Exclusions.IsExcluded(path, parent, svr.VirtualPath, containerPath);

                if ((svr.IsExcluded))
                {
                    svr.AddDetail(DetailKeys.File, SignCheckResources.DetailExcluded);
                }
            }

            if (GenerateExclusion)
            {
                svr.ExclusionEntry = String.Join(";", String.Join("|", path, containerPath), parent, String.Empty);
                Log.WriteMessage(LogVerbosity.Diagnostic, SignCheckResources.DiagGenerateExclusion, svr.Filename, svr.ExclusionEntry);
            }

            // Include the full path for top-level files
            if (String.IsNullOrEmpty(parent))
            {
                svr.AddDetail(DetailKeys.File, SignCheckResources.DetailFullName, svr.FullPath);
            }

            if (!String.IsNullOrEmpty(virtualPath))
            {
                svr.AddDetail(DetailKeys.File, SignCheckResources.DetailVirtualPath, svr.VirtualPath);
            }

            return(svr);
        }
Example #7
0
        /// <summary>
        /// Retrieve a FileVerifier from the SignatureVerificationManager. The retrieval is based on the file extension. If there are no
        /// applicable verifiers, the verifier is assigned based on the file's header.
        /// </summary>
        /// <param name="path">The path of the file for which to retrieve a FileVerifier.</param>
        /// <returns>A FileVerifier that can be used to verify the signature of the specified file.</returns>
        protected FileVerifier GetFileVerifier(string path)
        {
            string       extension    = Path.GetExtension(path);
            FileVerifier fileVerifier = SignatureVerificationManager.GetFileVerifierByExtension(extension);

            if (fileVerifier == null)
            {
                fileVerifier = SignatureVerificationManager.GetFileVerifierByHeader(path);

                if (fileVerifier == null)
                {
                    return(SignatureVerificationManager.UnsupportedFileVerifier);
                }
                else
                {
                    Log.WriteMessage(LogVerbosity.Detailed, SignCheckResources.DetailIdentifyByHeaderAsType, fileVerifier.FileExtension);
                }
            }

            return(fileVerifier);
        }
Example #8
0
        /// <summary>
        /// Verify the signature of a single file.
        /// </summary>
        /// <param name="path">The path of the file on disk to verify.</param>
        /// <param name="parent">The name of parent container, e.g. an MSI or VSIX. Can be null when there is no parent container.</param>
        /// <param name="containerPath">The path of the file in the container. This may differ from the path on disk as containers are flattened. It's
        /// primarily intended to help with exclusions and report more readable names.</param>
        /// <returns>The verification result.</returns>
        public SignatureVerificationResult VerifyFile(string path, string parent, string containerPath)
        {
            Log.WriteMessage(LogVerbosity.Detailed, String.Format(SignCheckResources.ProcessingFile, Path.GetFileName(path), String.IsNullOrEmpty(parent) ? SignCheckResources.NA : parent));

            string       extension    = Path.GetExtension(path);
            FileVerifier fileVerifier = GetFileVerifier(path);

            SignatureVerificationResult svr;

            svr = fileVerifier.VerifySignature(path, parent);

            CheckAndUpdateExclusions(ref svr, path, parent, containerPath);

            // Include the full path for top-level files
            if (String.IsNullOrEmpty(parent))
            {
                svr.AddDetail(DetailKeys.File, SignCheckResources.DetailFullName, svr.FullPath);
            }

            return(svr);
        }
Example #9
0
        /// <summary>
        /// Verify the signatures of a set of files.
        /// </summary>
        /// <param name="files">A set of files to verify.</param>
        /// <returns>An IEnumerable containing the verification results of each file.</returns>
        public IEnumerable <SignatureVerificationResult> VerifyFiles(IEnumerable <string> files)
        {
            foreach (string file in files)
            {
                FileVerifier fileVerifier = GetFileVerifier(file);
                SignatureVerificationResult result;
                result = fileVerifier.VerifySignature(file, parent: null);

                if ((Options & SignatureVerificationOptions.GenerateExclusion) == SignatureVerificationOptions.GenerateExclusion)
                {
                    result.ExclusionEntry = String.Join(";", String.Join("|", file, String.Empty), String.Empty, String.Empty);
                    Log.WriteMessage(LogVerbosity.Diagnostic, SignCheckResources.DiagGenerateExclusion, result.Filename, result.ExclusionEntry);
                }

                result.IsDoNotSign = Exclusions.IsDoNotSign(file, parent: null, containerPath: null);

                if ((result.IsDoNotSign) && (result.IsSigned))
                {
                    // Report errors if a DO-NOT-SIGN file is signed.
                    result.AddDetail(DetailKeys.Error, SignCheckResources.DetailDoNotSignFileSigned, result.Filename);
                }

                if ((!result.IsDoNotSign) && (!result.IsSigned))
                {
                    result.IsExcluded = Exclusions.IsExcluded(file, parent: null, containerPath: null);

                    if ((result.IsExcluded))
                    {
                        result.AddDetail(DetailKeys.File, SignCheckResources.DetailExcluded);
                    }
                }

                Results.Add(result);
            }

            return(Results);
        }
        /// <summary>
        /// Retrieves a FileVerifier by looking at the header of the file to determine its type to assign an extension to it.
        /// </summary>
        /// <param name="path">The path of the file.</param>
        /// <returns>A FileVerifier that can verify the file or null if the verifier could not be found.</returns>
        public static FileVerifier GetFileVerifierByHeader(string path)
        {
            if (String.IsNullOrEmpty(path))
            {
                throw new ArgumentException(String.Format(SignCheckResources.ArgumentNullOrEmpty, "path"));
            }

            FileVerifier fileVerifier = null;

            using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
                using (var reader = new BinaryReader(stream))
                {
                    // Test for 4-byte magic numbers
                    if (stream.Length > 4)
                    {
                        uint magic4 = reader.ReadUInt32();
                        if (magic4 == FileHeaders.Zip)
                        {
                            using (ZipArchive zipArchive = ZipFile.OpenRead(path))
                            {
                                if (zipArchive.Entries.Any(z => String.Equals(Path.GetExtension(z.FullName), "nuspec", StringComparison.OrdinalIgnoreCase)))
                                {
                                    // NUPKGs use .zip format, but should have a .nuspec files inside
                                    fileVerifier = GetFileVerifierByExtension(".nupkg");
                                }
                                else if (zipArchive.Entries.Any(z => String.Equals(Path.GetExtension(z.FullName), "vsixmanifest", StringComparison.OrdinalIgnoreCase)))
                                {
                                    // If it's an SDK based VSIX there should be a vsixmanifest file
                                    fileVerifier = GetFileVerifierByExtension(".vsix");
                                }
                                else if (zipArchive.Entries.Any(z => String.Equals(z.FullName, "META-INF/MANIFEST.MF", StringComparison.OrdinalIgnoreCase)))
                                {
                                    // Zip file with META-INF/MANIFEST.MF file is likely a JAR
                                    fileVerifier = GetFileVerifierByExtension(".jar");
                                }
                                else
                                {
                                    fileVerifier = GetFileVerifierByExtension(".zip");
                                }
                            }
                        }
                        else if (magic4 == FileHeaders.Cab)
                        {
                            fileVerifier = GetFileVerifierByExtension(".cab");
                        }
                    }

                    reader.BaseStream.Seek(0, SeekOrigin.Begin);
                    if (stream.Length > 2)
                    {
                        UInt16 magic2 = reader.ReadUInt16();
                        if (magic2 == FileHeaders.Dos)
                        {
                            PortableExecutableHeader pe = new PortableExecutableHeader(path);

                            if ((pe.FileHeader.Characteristics & ImageFileCharacteristics.IMAGE_FILE_DLL) != 0)
                            {
                                fileVerifier = GetFileVerifierByExtension(".dll");
                            }
                            else if ((pe.FileHeader.Characteristics & ImageFileCharacteristics.IMAGE_FILE_EXECUTABLE_IMAGE) != 0)
                            {
                                fileVerifier = GetFileVerifierByExtension(".exe");
                            }
                        }
                    }
                }

            return(fileVerifier);
        }