diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs index 623696ceb..cd9c2ddc0 100644 --- a/crypto/src/bcpg/BcpgInputStream.cs +++ b/crypto/src/bcpg/BcpgInputStream.cs @@ -120,8 +120,7 @@ public Packet ReadPacket() bool newPacket = (hdr & 0x40) != 0; PacketTag tag = 0; - // TODO[pgp] Is the length field supposed to support full uint range? - int bodyLen; + uint bodyLen; bool partial = false; if (newPacket) @@ -145,7 +144,7 @@ public Packet ReadPacket() bodyLen = StreamUtilities.RequireUInt16BE(this); break; case 2: - bodyLen = (int)StreamUtilities.RequireUInt32BE(this); + bodyLen = StreamUtilities.RequireUInt32BE(this); break; case 3: bodyLen = 0; @@ -238,19 +237,20 @@ protected override void Dispose(bool disposing) /// /// A stream that overlays our input stream, allowing the user to only read a segment of it. - /// NB: dataLength will be negative if the segment length is in the upper range above 2**31. + /// If partial is true, dataLength should only be up to 2^30 bytes. + /// Otherwise it's a non-partial packet and can be larger. /// private class PartialInputStream : BaseInputStream { private BcpgInputStream m_in; private bool partial; - private int dataLength; + private uint dataLength; internal PartialInputStream( BcpgInputStream bcpgIn, bool partial, - int dataLength) + uint dataLength) { this.m_in = bcpgIn; this.partial = partial; @@ -284,12 +284,12 @@ public override int Read(byte[] buffer, int offset, int count) { if (dataLength != 0) { - int readLen = (dataLength > count || dataLength < 0) ? count : dataLength; + int readLen = (dataLength > count) ? count : (int)dataLength; int len = m_in.Read(buffer, offset, readLen); if (len < 1) throw new EndOfStreamException("Premature end of stream in PartialInputStream"); - dataLength -= len; + dataLength = (uint)(dataLength - len); return len; } } @@ -306,12 +306,12 @@ public override int Read(Span buffer) if (dataLength != 0) { int count = buffer.Length; - int readLen = (dataLength > count || dataLength < 0) ? count : dataLength; + int readLen = (dataLength > count) ? count : (int)dataLength; int len = m_in.Read(buffer[..readLen]); if (len < 1) throw new EndOfStreamException("Premature end of stream in PartialInputStream"); - dataLength -= len; + dataLength = (uint)(dataLength - len); return len; } } @@ -323,8 +323,10 @@ public override int Read(Span buffer) private bool ReadPartialDataLength() { - int bodyLen = StreamUtilities.ReadBodyLen(m_in, out var streamFlags); - if (bodyLen < 0) + uint? bodyLen = StreamUtilities.ReadBodyLen(m_in, out var streamFlags); + // If we can't read the body length, or it's too large, we can't continue + // reading the stream as a partial stream, because partials only support up to 2^30 + if (!bodyLen.HasValue || bodyLen > (1U << 30)) { partial = false; dataLength = 0; @@ -332,7 +334,7 @@ private bool ReadPartialDataLength() } partial = streamFlags.HasFlag(StreamUtilities.StreamFlags.Partial); - dataLength = bodyLen; + dataLength = bodyLen.Value; return true; } } diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs index 966a2bd82..11af5fb7c 100644 --- a/crypto/src/bcpg/SignatureSubpacketsReader.cs +++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs @@ -20,8 +20,8 @@ public SignatureSubpacketsParser(Stream input) public SignatureSubpacket ReadPacket() { - int bodyLen = StreamUtilities.ReadBodyLen(m_input, out var streamFlags); - if (bodyLen < 0) + uint? bodyLen = StreamUtilities.ReadBodyLen(m_input, out var streamFlags); + if (!bodyLen.HasValue) return null; if (streamFlags.HasFlag(StreamUtilities.StreamFlags.Partial)) @@ -29,12 +29,12 @@ public SignatureSubpacket ReadPacket() bool isLongLength = streamFlags.HasFlag(StreamUtilities.StreamFlags.LongLength); - if (bodyLen < 1) + if (bodyLen.Value < 1) throw new EndOfStreamException("out of range data found in signature sub packet"); int tag = StreamUtilities.RequireByte(m_input); - byte[] data = new byte[bodyLen - 1]; + byte[] data = new byte[bodyLen.Value - 1]; // // this may seem a bit strange but it turns out some applications miscode the length diff --git a/crypto/src/bcpg/StreamUtilities.cs b/crypto/src/bcpg/StreamUtilities.cs index 352a80906..a3436dcb9 100644 --- a/crypto/src/bcpg/StreamUtilities.cs +++ b/crypto/src/bcpg/StreamUtilities.cs @@ -16,39 +16,45 @@ internal enum StreamFlags Partial = 2, } - internal static int ReadBodyLen(Stream s, out StreamFlags flags) + internal static uint? ReadBodyLen(Stream s, out StreamFlags flags) { flags = StreamFlags.None; int b0 = s.ReadByte(); if (b0 < 0) - return -1; + return null; if (b0 < 192) - return b0; + return (uint)b0; if (b0 < 224) { int b1 = RequireByte(s); - return ((b0 - 192) << 8) + b1 + 192; + return (uint)(((b0 - 192) << 8) + b1 + 192); } if (b0 == 255) { flags |= StreamFlags.LongLength; - return (int)RequireUInt32BE(s); + return RequireUInt32BE(s); } - flags |= StreamFlags.Partial; - return 1 << (b0 & 0x1F); + if (b0 >= 224 && b0 < 255) + { + flags |= StreamFlags.Partial; + return (uint)1 << (b0 & 0x1F); + } + + // Invalid value + return null; } - internal static int RequireBodyLen(Stream s, out StreamFlags flags) + internal static uint RequireBodyLen(Stream s, out StreamFlags flags) { - int bodyLen = ReadBodyLen(s, out flags); - if (bodyLen < 0) + uint? bodyLen = ReadBodyLen(s, out flags); + if (!bodyLen.HasValue) throw new EndOfStreamException(); - return bodyLen; + return bodyLen.Value; } internal static byte RequireByte(Stream s) diff --git a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs index 1d3844ae5..181579ac8 100644 --- a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs +++ b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs @@ -19,8 +19,8 @@ public UserAttributeSubpacketsParser(Stream input) public virtual UserAttributeSubpacket ReadPacket() { - int bodyLen = StreamUtilities.ReadBodyLen(m_input, out var streamFlags); - if (bodyLen < 0) + uint? bodyLen = StreamUtilities.ReadBodyLen(m_input, out var streamFlags); + if (!bodyLen.HasValue) return null; if (streamFlags.HasFlag(StreamUtilities.StreamFlags.Partial)) @@ -29,7 +29,7 @@ public virtual UserAttributeSubpacket ReadPacket() bool isLongLength = streamFlags.HasFlag(StreamUtilities.StreamFlags.LongLength); int tag = StreamUtilities.RequireByte(m_input); - byte[] data = new byte[bodyLen - 1]; + byte[] data = new byte[bodyLen.Value - 1]; StreamUtilities.RequireBytes(m_input, data); UserAttributeSubpacketTag type = (UserAttributeSubpacketTag)tag;