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;