public static bool IsZip64(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); if (endOfCentralDirectoryRecord.NumberOfThisDisk != endOfCentralDirectoryRecord.NumberOfTheDiskWithTheStartOfTheCentralDirectory) { return(false); } var offset = endOfCentralDirectoryRecord.OffsetFromStart - Zip64EndOfCentralDirectoryLocator.SizeInBytes; if (offset >= 0) { reader.BaseStream.Seek(offset, SeekOrigin.Begin); if (Zip64EndOfCentralDirectoryLocator.Exists(reader)) { return(true); } } reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); CentralDirectoryHeader centralDirectoryHeader; while (CentralDirectoryHeader.TryRead(reader, out centralDirectoryHeader)) { if (HasZip64ExtendedInformationExtraField(centralDirectoryHeader)) { return(true); } if (centralDirectoryHeader.DiskNumberStart != endOfCentralDirectoryRecord.NumberOfThisDisk) { continue; } var savedPosition = reader.BaseStream.Position; reader.BaseStream.Position = centralDirectoryHeader.RelativeOffsetOfLocalHeader; LocalFileHeader localFileHeader; if (LocalFileHeader.TryRead(reader, out localFileHeader) && HasZip64ExtendedInformationExtraField(localFileHeader)) { return(true); } reader.BaseStream.Position = savedPosition; } return(false); }
/// <summary> /// Read ZIP's offsets and positions of offsets. /// </summary> /// <param name="reader">binary reader to zip archive</param> /// <returns>metadata with offsets and positions for entries</returns> public static SignedPackageArchiveMetadata ReadSignedArchiveMetadata(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } var metadata = new SignedPackageArchiveMetadata() { StartOfFileHeaders = reader.BaseStream.Length }; var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); metadata.EndOfCentralDirectoryRecordPosition = endOfCentralDirectoryRecord.OffsetFromStart; reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); // Read central directory records var centralDirectoryRecords = new List <CentralDirectoryHeaderMetadata>(); CentralDirectoryHeader header; while (CentralDirectoryHeader.TryRead(reader, out header)) { if (header.RelativeOffsetOfLocalHeader < metadata.StartOfFileHeaders) { metadata.StartOfFileHeaders = header.RelativeOffsetOfLocalHeader; } var isPackageSignatureFile = SignedPackageArchiveUtility.IsPackageSignatureFileEntry( header.FileName, header.GeneralPurposeBitFlag); var centralDirectoryMetadata = new CentralDirectoryHeaderMetadata() { IsPackageSignatureFile = isPackageSignatureFile, HeaderSize = header.GetSizeInBytes(), OffsetToFileHeader = header.RelativeOffsetOfLocalHeader, Position = header.OffsetFromStart }; centralDirectoryRecords.Add(centralDirectoryMetadata); } if (centralDirectoryRecords.Count == 0) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } var lastCentralDirectoryRecord = centralDirectoryRecords.Last(); metadata.EndOfCentralDirectory = lastCentralDirectoryRecord.Position + lastCentralDirectoryRecord.HeaderSize; metadata.CentralDirectoryHeaders = centralDirectoryRecords; UpdateSignedPackageArchiveMetadata(reader, metadata); return(metadata); }
/// <summary> /// Utility method to know if a zip archive is signed. /// </summary> /// <param name="reader">Binary reader pointing to a zip archive.</param> /// <returns>true if the given archive is signed</returns> public static bool IsSigned(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } try { var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); // Look for signature central directory record reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); CentralDirectoryHeader centralDirectoryHeader; while (CentralDirectoryHeader.TryRead(reader, out centralDirectoryHeader)) { if (IsPackageSignatureFileEntry( centralDirectoryHeader.FileName, centralDirectoryHeader.GeneralPurposeBitFlag)) { // Go to local file header reader.BaseStream.Seek(centralDirectoryHeader.RelativeOffsetOfLocalHeader, SeekOrigin.Begin); // Make sure local file header exists LocalFileHeader localFileHeader; if (!LocalFileHeader.TryRead(reader, out localFileHeader)) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } return(IsPackageSignatureFileEntry( localFileHeader.FileName, localFileHeader.GeneralPurposeBitFlag)); } } } // Ignore any exception. If something is thrown it means the archive is either not valid or not signed catch { } return(false); }
private static UnsignedPackageArchiveMetadata ReadUnsignedArchiveMetadata(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); var endOfCentralDirectoryRecordPosition = endOfCentralDirectoryRecord.OffsetFromStart; reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); var centralDirectoryRecords = new List <CentralDirectoryHeaderMetadata>(); CentralDirectoryHeader header; while (CentralDirectoryHeader.TryRead(reader, out header)) { var centralDirectoryMetadata = new CentralDirectoryHeaderMetadata() { Position = header.OffsetFromStart, OffsetToLocalFileHeader = header.RelativeOffsetOfLocalHeader, HeaderSize = header.GetSizeInBytes(), }; centralDirectoryRecords.Add(centralDirectoryMetadata); } if (centralDirectoryRecords.Count == 0) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } var lastCentralDirectoryRecord = centralDirectoryRecords.Last(); var endOfCentralDirectoryPosition = lastCentralDirectoryRecord.Position + lastCentralDirectoryRecord.HeaderSize; var endOfLocalFileHeadersPosition = centralDirectoryRecords.Min(record => record.Position); UpdateLocalFileHeadersTotalSize(centralDirectoryRecords, endOfLocalFileHeadersPosition); return(new UnsignedPackageArchiveMetadata(endOfLocalFileHeadersPosition, endOfCentralDirectoryPosition)); }
/// <summary> /// Utility method to know if a zip archive is signed. /// </summary> /// <param name="reader">Binary reader pointing to a zip archive.</param> /// <returns>true if the given archive is signed</returns> private static bool IsSigned(BinaryReader reader) { try { var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); // Look for signature central directory record reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); CentralDirectoryHeader header; while (CentralDirectoryHeader.TryRead(reader, out header)) { var isUtf8 = IsUtf8(header.GeneralPurposeBitFlag); var fileName = GetString(header.FileName, isUtf8); if (string.Equals(fileName, _signingSpecification.SignaturePath, StringComparison.Ordinal)) { // Go to local file header reader.BaseStream.Seek(header.RelativeOffsetOfLocalHeader, SeekOrigin.Begin); // Make sure file header exists there var fileHeaderSignature = reader.ReadUInt32(); if (fileHeaderSignature != LocalFileHeader.Signature) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } return(true); } } } // Ignore any exception. If something is thrown it means the archive is either not valid or not signed catch { } return(false); }
/// <summary> /// Read ZIP's offsets and positions of offsets. /// </summary> /// <param name="reader">binary reader to zip archive</param> /// <returns>metadata with offsets and positions for entries</returns> public static SignedPackageArchiveMetadata ReadSignedArchiveMetadata(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } var metadata = new SignedPackageArchiveMetadata() { StartOfLocalFileHeaders = reader.BaseStream.Length }; var endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord.Read(reader); var endOfCentralDirectoryRecordPosition = endOfCentralDirectoryRecord.OffsetFromStart; reader.BaseStream.Seek(endOfCentralDirectoryRecord.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); var centralDirectoryRecords = new List <CentralDirectoryHeaderMetadata>(); var packageSignatureFileMetadataIndex = -1; var index = 0; while (CentralDirectoryHeader.TryRead(reader, out var header)) { metadata.StartOfLocalFileHeaders = Math.Min(metadata.StartOfLocalFileHeaders, header.RelativeOffsetOfLocalHeader); var isPackageSignatureFile = SignedPackageArchiveUtility.IsPackageSignatureFileEntry( header.FileName, header.GeneralPurposeBitFlag); if (isPackageSignatureFile) { if (packageSignatureFileMetadataIndex != -1) { throw new SignatureException(NuGetLogCode.NU3005, Strings.MultiplePackageSignatureFiles); } packageSignatureFileMetadataIndex = index; } var centralDirectoryMetadata = new CentralDirectoryHeaderMetadata() { Position = header.OffsetFromStart, OffsetToLocalFileHeader = header.RelativeOffsetOfLocalHeader, IsPackageSignatureFile = isPackageSignatureFile, HeaderSize = header.GetSizeInBytes(), IndexInHeaders = index }; centralDirectoryRecords.Add(centralDirectoryMetadata); ++index; } if (centralDirectoryRecords.Count == 0) { throw new InvalidDataException(Strings.ErrorInvalidPackageArchive); } if (packageSignatureFileMetadataIndex == -1) { throw new SignatureException(NuGetLogCode.NU3005, Strings.NoPackageSignatureFile); } var lastCentralDirectoryRecord = centralDirectoryRecords.Last(); var endOfCentralDirectoryPosition = lastCentralDirectoryRecord.Position + lastCentralDirectoryRecord.HeaderSize; var endOfLocalFileHeadersPosition = GetEndOfLocalFileHeadersPosition(reader, centralDirectoryRecords); metadata.EndOfCentralDirectory = lastCentralDirectoryRecord.Position + lastCentralDirectoryRecord.HeaderSize; metadata.CentralDirectoryHeaders = centralDirectoryRecords; metadata.EndOfLocalFileHeaders = endOfLocalFileHeadersPosition; metadata.SignatureCentralDirectoryHeaderIndex = packageSignatureFileMetadataIndex; AssertSignatureEntryMetadata(reader, metadata); return(metadata); }