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); }
/// <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); }
public SignerTests(SigningTestFixture fixture) { _testFixture = fixture ?? throw new ArgumentNullException(nameof(fixture)); _trustProviders = _testFixture.TrustProviders; _signingSpecifications = _testFixture.SigningSpecifications; }
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); }