Пример #1
0
        /// <summary>
        /// Build up a table of checksum to <see cref="FileName"/> instance map. This will report errors if it
        /// is unable to read any of the files off of disk.
        /// </summary>
        private ContentMap BuildContentMap(TextWriter textWriter, ref bool allGood)
        {
            var contentMap = new ContentMap();

            foreach (var fileName in _batchData.FileNames)
            {
                try
                {
                    var checksum = _contentUtil.GetChecksum(fileName.FullPath);
                    contentMap.Add(fileName, checksum);
                }
                catch (Exception ex)
                {
                    if (!File.Exists(fileName.FullPath))
                    {
                        textWriter.WriteLine($"Did not find {fileName} at {fileName.FullPath}");
                    }
                    else
                    {
                        textWriter.WriteLine($"Unable to read content of {fileName.FullPath}: {ex.Message}");
                    }
                    allGood = false;
                }
            }

            return(contentMap);
        }
Пример #2
0
        /// <summary>
        /// Build up the <see cref="ZipData"/> instance for a given zip container. This will also report any consistency
        /// errors found when examining the zip archive.
        /// </summary>
        private ZipData BuildZipData(FileName zipFileName, ContentMap contentMap, TextWriter textWriter, ref bool allGood)
        {
            Debug.Assert(zipFileName.IsZipContainer);

            var nestedExternalBinaries = new List <string>();
            var nestedParts            = new List <ZipPart>();

            using (var package = Package.Open(zipFileName.FullPath, FileMode.Open, FileAccess.Read))
            {
                foreach (var part in package.GetParts())
                {
                    var relativeName = GetPartRelativeFileName(part);
                    var name         = Path.GetFileName(relativeName);
                    if (!IsZipContainer(name) && !IsAssembly(name))
                    {
                        continue;
                    }

                    if (_batchData.ExternalFileNames.Contains(name))
                    {
                        nestedExternalBinaries.Add(name);
                        continue;
                    }

                    if (!_batchData.FileNames.Any(x => FilePathComparer.Equals(x.Name, name)))
                    {
                        allGood = false;
                        textWriter.WriteLine($"signtool : error : Zip Container '{zipFileName}' has part '{relativeName}' which is not listed in the sign or external list");
                        continue;
                    }

                    // This represents a binary that we need to sign.  Ensure the content in the VSIX is the same as the
                    // content in the binaries directory by doing a checksum match.
                    using (var stream = part.GetStream())
                    {
                        string checksum = _contentUtil.GetChecksum(stream);
                        if (!contentMap.TryGetFileName(checksum, out var checksumName))
                        {
                            allGood = false;
                            textWriter.WriteLine($"signtool : error : {zipFileName} has part {relativeName} which does not match the content in the binaries directory");
                            continue;
                        }

                        if (!FilePathComparer.Equals(checksumName.Name, name))
                        {
                            allGood = false;
                            textWriter.WriteLine($"signtool : error : {zipFileName} has part {relativeName} with a different name in the binaries directory: {checksumName}");
                            continue;
                        }

                        nestedParts.Add(new ZipPart(relativeName, checksumName, checksum));
                    }
                }
            }

            return(new ZipData(zipFileName, nestedParts.ToImmutableArray(), nestedExternalBinaries.ToImmutableArray()));
        }
Пример #3
0
        private Dictionary <FileName, ZipData> BuildAllZipData(ContentMap contentMap, TextWriter textWriter, ref bool allGood)
        {
            var zipDataMap = new Dictionary <FileName, ZipData>();

            foreach (var zipName in _batchData.FileNames.Where(x => x.IsZipContainer))
            {
                var data = BuildZipData(zipName, contentMap, textWriter, ref allGood);
                zipDataMap[zipName] = data;
            }

            return(zipDataMap);
        }
Пример #4
0
        /// <summary>
        /// Build up a table of checksum to <see cref="FileName"/> instance map. This will report errors if it
        /// is unable to read any of the files off of disk.
        /// </summary>
        private ContentMap BuildContentMap(TextWriter textWriter, ref bool allGood)
        {
            var contentMap = new ContentMap();

            foreach (var fileName in _batchData.FileNames)
            {
                try
                {
                    if (string.IsNullOrEmpty(fileName.SHA256Hash))
                    {
                        var checksum = _contentUtil.GetChecksum(fileName.FullPath);
                        contentMap.Add(fileName, checksum);
                    }
                    else
                    {
                        if (File.Exists(fileName.FullPath))
                        {
                            contentMap.Add(fileName, fileName.SHA256Hash);
                        }
                        else
                        {
                            throw new FileNotFoundException();
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (!File.Exists(fileName.FullPath))
                    {
                        textWriter.WriteLine($"signtool : error : Did not find {fileName} at {fileName.FullPath}");
                    }
                    else
                    {
                        textWriter.WriteLine($"signtool : error : Unable to read content of {fileName.FullPath}: {ex.Message}");
                    }
                    allGood = false;
                }
            }

            return(contentMap);
        }
Пример #5
0
        private bool GenerateOrchestrationManifest(TextWriter textWriter, BatchSignInput batchData, ContentMap contentMap, string outputPath)
        {
            textWriter.WriteLine($"Generating orchestration file manifest into {outputPath}");
            OrchestratedFileJson fileJsonWithInfo = new OrchestratedFileJson
            {
                ExcludeList = _batchData.ExternalFileNames.ToArray() ?? Array.Empty <string>()
            };

            var distinctSigningCombos = batchData.FileSignInfoMap.Values.GroupBy(v => new { v.Certificate, v.StrongName });

            List <OrchestratedFileSignData> newList = new List <OrchestratedFileSignData>();

            foreach (var combinationToSign in distinctSigningCombos)
            {
                var filesInThisGroup = combinationToSign.Select(c => new FileSignDataEntry()
                {
                    FilePath         = c.FileName.RelativePath,
                    SHA256Hash       = contentMap.GetChecksum(c.FileName),
                    PublishToFeedUrl = batchData.PublishUri
                });
                newList.Add(new OrchestratedFileSignData()
                {
                    Certificate = combinationToSign.Key.Certificate,
                    StrongName  = combinationToSign.Key.StrongName,
                    FileList    = filesInThisGroup.ToArray()
                });
            }
            fileJsonWithInfo.SignList = newList.ToArray();
            fileJsonWithInfo.Kind     = "orchestration";

            using (StreamWriter file = File.CreateText(outputPath))
            {
                file.Write(JsonConvert.SerializeObject(fileJsonWithInfo, Formatting.Indented));
            }

            return(true);
        }
Пример #6
0
        /// <summary>
        /// Actually sign all of the described files.
        /// </summary>
        private bool SignFiles(ContentMap contentMap, Dictionary <FileName, ZipData> zipDataMap, TextWriter textWriter)
        {
            // Generate the list of signed files in a deterministic order. Makes it easier to track down
            // bugs if repeated runs use the same ordering.
            var toSignList = _batchData.FileNames.ToList();
            var round      = 0;
            var signedSet  = new HashSet <FileName>();

            void signFiles(IEnumerable <FileName> files)
            {
                textWriter.WriteLine($"Signing Round {round}");
                foreach (var name in files)
                {
                    textWriter.WriteLine($"\t{name}");
                }
                _signTool.Sign(round, files.Select(x => _batchData.FileSignInfoMap[x]).Where(x => !x.IsEmpty), textWriter);
            }

            void repackFiles(IEnumerable <FileName> files)
            {
                var any = false;

                foreach (var file in files)
                {
                    if (file.IsZipContainer)
                    {
                        if (!any)
                        {
                            textWriter.WriteLine("Repacking");
                            any = true;
                        }

                        textWriter.WriteLine($"\t{file}");
                        Repack(zipDataMap[file]);
                    }
                }
            }

            // Is this file ready to be signed? That is are all of the items that it depends on already
            // signed?
            bool isReadyToSign(FileName fileName)
            {
                if (!fileName.IsZipContainer)
                {
                    return(true);
                }

                var zipData = zipDataMap[fileName];

                return(zipData.NestedParts.All(x => signedSet.Contains(x.FileName)));
            }

            // Extract the next set of files that should be signed. This is the set of files for which all of the
            // dependencies have been signed.
            List <FileName> extractNextGroup()
            {
                var list = new List <FileName>();
                var i    = 0;

                while (i < toSignList.Count)
                {
                    var current = toSignList[i];
                    if (isReadyToSign(current))
                    {
                        list.Add(current);
                        toSignList.RemoveAt(i);
                    }
                    else
                    {
                        i++;
                    }
                }

                return(list);
            }

            try
            {
                while (toSignList.Count > 0)
                {
                    var list = extractNextGroup();
                    if (list.Count == 0)
                    {
                        throw new Exception("No progress made on signing which indicates a bug");
                    }

                    repackFiles(list);
                    signFiles(list);
                    round++;
                    list.ForEach(x => signedSet.Add(x));
                }

                return(true);
            }
            catch (Exception ex)
            {
                textWriter.WriteLine($"Signing failed: {ex.Message}");
                return(false);
            }
        }