Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions openpgp/packet/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,15 @@ func (l *spanReader) Read(p []byte) (n int, err error) {
return
}

// readerRemaining returns the number of bytes that can still be read from a
// length-delimited packet reader, or -1 if the amount is not known in advance.
func readerRemaining(r io.Reader) int64 {
if sr, ok := r.(*spanReader); ok {
return sr.n
}
return -1
}

// readHeader parses a packet header and returns an io.Reader which will return
// the contents of the packet. See RFC 4880, section 4.2.
func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) {
Expand Down
6 changes: 6 additions & 0 deletions openpgp/packet/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ func (sig *Signature) parse(r io.Reader) (err error) {
} else {
hashedSubpacketsLength = int(buf[3])<<8 | int(buf[4])
}
if remaining := readerRemaining(r); remaining >= 0 && int64(hashedSubpacketsLength) > remaining {
return errors.StructuralError("hashed subpacket data length is larger than the packet")
}
hashedSubpackets := make([]byte, hashedSubpacketsLength)
_, err = readFull(r, hashedSubpackets)
if err != nil {
Expand Down Expand Up @@ -269,6 +272,9 @@ func (sig *Signature) parse(r io.Reader) (err error) {
} else {
unhashedSubpacketsLength = uint32(buf[0])<<8 | uint32(buf[1])
}
if remaining := readerRemaining(r); remaining >= 0 && int64(unhashedSubpacketsLength) > remaining {
return errors.StructuralError("unhashed subpacket data length is larger than the packet")
}
unhashedSubpackets := make([]byte, unhashedSubpacketsLength)
_, err = readFull(r, unhashedSubpackets)
if err != nil {
Expand Down
31 changes: 31 additions & 0 deletions openpgp/packet/signature_security_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package packet

import (
"bytes"
"runtime"
"testing"
)

func TestV6SignatureHugeSubpacketLength(t *testing.T) {
body := []byte{
0x06, // version 6
0x00, // signature type
0x01, // pubkey algo
0x08, // hash algo
0x7f, 0xff, 0xff, 0xff, // hashed subpacket length (~2 GiB)
}
pkt := append([]byte{0xc0 | 2, byte(len(body))}, body...)

var before, after runtime.MemStats
runtime.GC()
runtime.ReadMemStats(&before)
_, err := Read(bytes.NewReader(pkt))
runtime.ReadMemStats(&after)

if err == nil {
t.Fatal("expected an error for oversized hashed subpacket length, got nil")
}
if allocated := after.TotalAlloc - before.TotalAlloc; allocated > 10<<20 {
t.Fatalf("Read allocated %d bytes for a tiny packet declaring a huge subpacket length", allocated)
}
}