public PrimarySignatureTests(SigningTestFixture fixture)
 {
     _testFixture           = fixture ?? throw new ArgumentNullException(nameof(fixture));
     _trustedTestCert       = _testFixture.TrustedTestCertificate;
     _trustProviders        = _testFixture.TrustProviders;
     _signingSpecifications = _testFixture.SigningSpecifications;
 }
        private static Task ShiftSignatureMetadata(SigningSpecifications spec, BinaryReader reader, BinaryWriter writer, int centralDirectoryIndex, int fileHeaderIndex)
        {
            // Read metadata
            var metadata = SignedPackageArchiveIOUtility.ReadSignedArchiveMetadata(reader);

            // Update central directory records by excluding the signature entry
            SignedPackageArchiveIOUtility.UpdateSignedPackageArchiveMetadata(reader, metadata);

            // Calculate new central directory record metadata with the the signature record and entry shifted
            var shiftedCdr = ShiftMetadata(spec, metadata, newSignatureFileEntryIndex: fileHeaderIndex, newSignatureCentralDirectoryRecordIndex: centralDirectoryIndex);

            // Order records by shifted ofset (new offset = old offset + change in offset).
            // This is the order they will appear in the new shifted package, but not necesarily the same order they were in the old package
            shiftedCdr.Sort((x, y) => (x.OffsetToFileHeader + x.ChangeInOffset).CompareTo(y.OffsetToFileHeader + y.ChangeInOffset));

            // Write data from start of file to first file entry
            reader.BaseStream.Seek(offset: 0, origin: SeekOrigin.Begin);
            SignedPackageArchiveIOUtility.ReadAndWriteUntilPosition(reader, writer, metadata.StartOfFileHeaders);

            // Write all file entries in the new order
            foreach (var entry in shiftedCdr)
            {
                // We need to read each entry from their position in the old package and write them sequencially to the new package
                // The order in which they will appear in the new shited package is defined by the sorting done before starting to write
                reader.BaseStream.Seek(offset: entry.OffsetToFileHeader, origin: SeekOrigin.Begin);
                SignedPackageArchiveIOUtility.ReadAndWriteUntilPosition(reader, writer, entry.OffsetToFileHeader + entry.FileEntryTotalSize);
            }

            // Write all central directory records with updated offsets
            // We first need to sort them in the order they will appear in the new shifted package
            shiftedCdr.Sort((x, y) => x.IndexInHeaders.CompareTo(y.IndexInHeaders));
            foreach (var entry in shiftedCdr)
            {
                reader.BaseStream.Seek(offset: entry.Position, origin: SeekOrigin.Begin);
                // Read and write from the start of the central directory record until the relative offset of local file header (42 from the start of central directory record, incluing signature length)
                SignedPackageArchiveIOUtility.ReadAndWriteUntilPosition(reader, writer, reader.BaseStream.Position + 42);

                var relativeOffsetOfLocalFileHeader = (uint)(reader.ReadUInt32() + entry.ChangeInOffset);
                writer.Write(relativeOffsetOfLocalFileHeader);

                // We already read and hash the whole header, skip only filenameLength + extraFieldLength + fileCommentLength (46 is the size of the header without those lengths)
                SignedPackageArchiveIOUtility.ReadAndWriteUntilPosition(reader, writer, reader.BaseStream.Position + entry.HeaderSize - CentralDirectoryFileHeaderSizeWithoutSignature);
            }

            // Write everything after central directory records
            reader.BaseStream.Seek(offset: metadata.EndOfCentralDirectory, origin: SeekOrigin.Begin);
            SignedPackageArchiveIOUtility.ReadAndWriteUntilPosition(reader, writer, reader.BaseStream.Length);

            return(Task.FromResult(0));
        }
        private static List <CentralDirectoryHeaderMetadata> ShiftMetadata(
            SigningSpecifications spec,
            SignedPackageArchiveMetadata metadata,
            int newSignatureFileEntryIndex,
            int newSignatureCentralDirectoryRecordIndex)
        {
            var shiftedCdr = new List <CentralDirectoryHeaderMetadata>(metadata.CentralDirectoryHeaders);

            // Sort Central Directory records in the order the file entries appear  in the original archive
            shiftedCdr.Sort((x, y) => x.OffsetToFileHeader.CompareTo(y.OffsetToFileHeader));

            // Shift Central Directory records to the desired position.
            // Because we sorted in the file entry order this will shift
            // the file entries
            ShiftSignatureToIndex(spec, shiftedCdr, newSignatureFileEntryIndex);

            // Calculate the change in offsets for the shifted file entries
            var lastEntryEnd = 0L;

            foreach (var cdr in shiftedCdr)
            {
                cdr.ChangeInOffset = lastEntryEnd - cdr.OffsetToFileHeader;

                lastEntryEnd = cdr.OffsetToFileHeader + cdr.FileEntryTotalSize + cdr.ChangeInOffset;
            }

            // Now we sort the central directory records in the order thecentral directory records appear in the original archive
            shiftedCdr.Sort((x, y) => x.Position.CompareTo(y.Position));

            // Shift Central Directory records to the desired position.
            // Because we sorted in the central directory records order this will shift
            // the central directory records
            ShiftSignatureToIndex(spec, shiftedCdr, newSignatureCentralDirectoryRecordIndex);

            // Calculate the new indexes for each central directory record
            var lastIndex = 0;

            foreach (var cdr in shiftedCdr)
            {
                cdr.IndexInHeaders = lastIndex;
                lastIndex++;
            }

            return(shiftedCdr);
        }
        /// <summary>
        /// unsigns a package for test purposes.
        /// This does not timestamp a signature and can be used outside corp network.
        /// </summary>
        public static async Task ShiftSignatureMetadataAsync(SigningSpecifications spec, string signedPackagePath, string dir, int centralDirectoryIndex, int fileHeaderIndex)
        {
            var testLogger            = new TestLogger();
            var testSignatureProvider = new X509SignatureProvider(timestampProvider: null);

            // Create a temp path
            var copiedSignedPackagePath = Path.Combine(dir, Guid.NewGuid().ToString());

            using (var signedReadStream = File.OpenRead(signedPackagePath))
                using (var signedPackage = new BinaryReader(signedReadStream))
                    using (var shiftedWriteStream = File.OpenWrite(copiedSignedPackagePath))
                        using (var shiftedPackage = new BinaryWriter(shiftedWriteStream))
                        {
                            await ShiftSignatureMetadata(spec, signedPackage, shiftedPackage, centralDirectoryIndex, fileHeaderIndex);
                        }

            // Overwrite the original package with the shifted one
            File.Copy(copiedSignedPackagePath, signedPackagePath, overwrite: true);
        }
        private static void ShiftSignatureToIndex(
            SigningSpecifications spec,
            List <CentralDirectoryHeaderMetadata> cdr,
            int index)
        {
            // Check for the signature object in the entries.
            // We have to do a manual check because we have no context
            // of the order in which the central directory records list is sorted.
            var recordIndex = 0;

            for (; recordIndex < cdr.Count; recordIndex++)
            {
                if (cdr[recordIndex].IsPackageSignatureFile)
                {
                    break;
                }
            }
            // Remove the signature object and add it to the new index
            var signatureCD = cdr[recordIndex];

            cdr.RemoveAt(recordIndex);
            cdr.Insert(index, signatureCD);
        }
        protected Common.HashAlgorithmName ValidateAndParseHashAlgorithm(string value, string name, SigningSpecifications spec)
        {
            var hashAlgorithm = Common.HashAlgorithmName.SHA256;

            if (!string.IsNullOrEmpty(value))
            {
                hashAlgorithm = CryptoHashUtility.GetHashAlgorithmName(value);

                if (!spec.AllowedHashAlgorithms.Contains(hashAlgorithm))
                {
                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                              NuGetMSSignCommand.MSSignCommandInvalidArgumentException,
                                                              name));
                }
            }

            if (hashAlgorithm == Common.HashAlgorithmName.Unknown)
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                          NuGetMSSignCommand.MSSignCommandInvalidArgumentException,
                                                          name));
            }

            return(hashAlgorithm);
        }
        public static int GetSignatureCentralDirectoryIndex(SignedPackageArchiveMetadata metadata, SigningSpecifications signingSpecification)
        {
            var centralDirectoryRecords      = metadata.CentralDirectoryHeaders;
            var centralDirectoryRecordsCount = centralDirectoryRecords.Count;

            for (var centralDirectoryRecordIndex = 0; centralDirectoryRecordIndex < centralDirectoryRecordsCount; centralDirectoryRecordIndex++)
            {
                var record = centralDirectoryRecords[centralDirectoryRecordIndex];

                if (record.IsPackageSignatureFile)
                {
                    return(centralDirectoryRecordIndex);
                }
            }

            return(-1);
        }
        /// <summary>
        /// Parses a command line argument's value to a supported hash algorithm and validates it is supported in the given specification
        /// </summary>
        /// <param name="optionValue">Value entered by the user in the given command line argument</param>
        /// <param name="optionName">Name of the command line argument</param>
        /// <param name="spec">Signing specification to validate parsed hash algorithm</param>
        /// <returns>Supported hash algorithm</returns>
        internal static HashAlgorithmName ParseAndValidateHashAlgorithm(string optionValue, string optionName, SigningSpecifications spec)
        {
            HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA256;

            if (!string.IsNullOrEmpty(optionValue))
            {
                hashAlgorithm = CryptoHashUtility.GetHashAlgorithmName(optionValue);
            }

            if (hashAlgorithm == HashAlgorithmName.Unknown || !spec.AllowedHashAlgorithms.Contains(hashAlgorithm))
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                          Strings.Err_InvalidValue,
                                                          optionName, string.Join(",", spec.AllowedHashAlgorithms)));
            }

            return(hashAlgorithm);
        }
Пример #9
0
        /// <summary>
        /// Parses a command line argument's value to a supported hash algorithm and validates it is supported in the given specification
        /// </summary>
        /// <param name="argumentValue">Value entered by the user in the given command line argument</param>
        /// <param name="argumentName">Name of the command line argument</param>
        /// <param name="spec">Signing specification to validate parsed hash algorithm</param>
        /// <returns>Supported hash algorithm</returns>
        public static HashAlgorithmName ParseAndValidateHashAlgorithmFromArgument(string argumentValue, string argumentName, SigningSpecifications spec)
        {
            var hashAlgorithm = HashAlgorithmName.SHA256;

            if (!string.IsNullOrEmpty(argumentValue))
            {
                hashAlgorithm = CryptoHashUtility.GetHashAlgorithmName(argumentValue);
            }

            if (hashAlgorithm == HashAlgorithmName.Unknown || !spec.AllowedHashAlgorithms.Contains(hashAlgorithm))
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                          NuGetCommand.CommandInvalidArgumentException,
                                                          argumentName));
            }

            return(hashAlgorithm);
        }
Пример #10
0
 public SignerTests(SigningTestFixture fixture)
 {
     _testFixture           = fixture ?? throw new ArgumentNullException(nameof(fixture));
     _trustProviders        = _testFixture.TrustProviders;
     _signingSpecifications = _testFixture.SigningSpecifications;
 }
Пример #11
0
        private HashAlgorithmName ValidateAndParseHashAlgorithm(string value, string name, SigningSpecifications spec)
        {
            var hashAlgorithm = HashAlgorithmName.SHA256;

            if (!string.IsNullOrEmpty(value))
            {
                if (!spec.AllowedHashAlgorithms.Contains(value, StringComparer.OrdinalIgnoreCase))
                {
                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                              NuGetCommand.SignCommandInvalidArgumentException,
                                                              name));
                }

                hashAlgorithm = CryptoHashUtility.GetHashAlgorithmName(value);
            }

            if (hashAlgorithm == HashAlgorithmName.Unknown)
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                          NuGetCommand.SignCommandInvalidArgumentException,
                                                          name));
            }

            return(hashAlgorithm);
        }
        public static int GetSignatureCentralDirectoryIndex(SignedPackageArchiveMetadata metadata, SigningSpecifications signingSpecification)
        {
            var centralDirectoryRecords      = metadata.CentralDirectoryHeaders;
            var centralDirectoryRecordsCount = centralDirectoryRecords.Count;

            for (var centralDirectoryRecordIndex = 0; centralDirectoryRecordIndex < centralDirectoryRecordsCount; centralDirectoryRecordIndex++)
            {
                var record = centralDirectoryRecords[centralDirectoryRecordIndex];

                if (StringComparer.Ordinal.Equals(record.Filename, signingSpecification.SignaturePath))
                {
                    return(centralDirectoryRecordIndex);
                }
            }

            return(-1);
        }