/// <summary> /// Calculates the signature for this package. /// </summary> /// <param name="package"> /// The package for whcih to calculate the signature. /// </param> /// <param name="signer"> /// The signer to use. /// </param> /// <param name="compressedPayloadStream"> /// The compressed payload. /// </param> public void CalculateSignature(RpmPackage package, IPackageSigner signer, Stream compressedPayloadStream) { RpmSignature signature = new RpmSignature(package); using (MemoryStream headerStream = this.GetHeaderStream(package)) using (ConcatStream headerAndPayloadStream = new ConcatStream(leaveOpen: true, streams: new Stream[] { headerStream, compressedPayloadStream })) { SHA1 sha = SHA1.Create(); signature.Sha1Hash = sha.ComputeHash(headerStream); MD5 md5 = MD5.Create(); signature.MD5Hash = md5.ComputeHash(headerAndPayloadStream); // Verify the PGP signatures // 3 for the header headerStream.Position = 0; signature.HeaderPgpSignature = signer.Sign(headerStream); headerAndPayloadStream.Position = 0; signature.HeaderAndPayloadPgpSignature = signer.Sign(headerAndPayloadStream); // Verify the signature size (header + compressed payload) signature.HeaderAndPayloadSize = (int)headerAndPayloadStream.Length; } // Verify the payload size (header + uncompressed payload) using (Stream payloadStream = RpmPayloadReader.GetDecompressedPayloadStream(package, compressedPayloadStream)) { signature.UncompressedPayloadSize = (int)payloadStream.Length; } }
public bool Verify(PgpPublicKey pgpPublicKey) { // 1 Verify the header signature immutable block: make sure all records are marked as immutable var immutableRegionSize = this.ImmutableRegionSize; var immutableEntryCount = -immutableRegionSize / Marshal.SizeOf<IndexHeader>(); if (this.Package.Signature.Records.Count != immutableEntryCount) { return false; } // Store the header data and the header + payload data in substreams. This enables us to calculate hashes and // verify signatures using these data ranges. using (Stream headerStream = new SubStream( this.Package.Stream, this.Package.HeaderOffset, this.Package.PayloadOffset - this.Package.HeaderOffset, leaveParentOpen: true, readOnly: true)) using (Stream headerAndPayloadStream = new SubStream( this.Package.Stream, this.Package.HeaderOffset, this.Package.Stream.Length - this.Package.HeaderOffset, leaveParentOpen: true, readOnly: true)) { // Verify the SHA1 hash. This one covers the header block SHA1 sha = SHA1.Create(); var calculatedShaValue = sha.ComputeHash(headerStream); var actualShaValue = this.Sha1Hash; if (!calculatedShaValue.SequenceEqual(actualShaValue)) { return false; } // Verify the MD5 hash. This one covers the header and the payload block MD5 md5 = MD5.Create(); var calculatedMd5Value = md5.ComputeHash(headerAndPayloadStream); var actualMd5Value = this.MD5Hash; if (!calculatedMd5Value.SequenceEqual(actualMd5Value)) { return false; } // Verify the PGP signatures // 3 for the header var headerPgpSignature = this.HeaderPgpSignature; headerStream.Position = 0; if (!PgpSigner.VerifySignature(headerPgpSignature, pgpPublicKey, headerStream)) { return false; } var headerAndPayloadPgpSignature = this.HeaderAndPayloadPgpSignature; headerAndPayloadStream.Position = 0; if (!PgpSigner.VerifySignature(headerAndPayloadPgpSignature, pgpPublicKey, headerAndPayloadStream)) { return false; } } // Verify the signature size (header + compressed payload) var headerSize = this.HeaderAndPayloadSize; if (headerSize != this.Package.Stream.Length - this.Package.HeaderOffset) { return false; } // Verify the payload size (header + uncompressed payload) var expectedDecompressedPayloadSize = this.UncompressedPayloadSize; long actualDecompressedPayloadLength = 0; using (Stream payloadStream = RpmPayloadReader.GetDecompressedPayloadStream(this.Package)) { actualDecompressedPayloadLength = payloadStream.Length; } if (expectedDecompressedPayloadSize != actualDecompressedPayloadLength) { return false; } return true; }