]>
Commit | Line | Data |
---|---|---|
c680a8e1 RS |
1 | // Copyright 2011 The Go Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file. | |
4 | ||
5 | package packet | |
6 | ||
7 | import ( | |
8 | "golang.org/x/crypto/openpgp/errors" | |
9 | "io" | |
10 | ) | |
11 | ||
12 | // Reader reads packets from an io.Reader and allows packets to be 'unread' so | |
13 | // that they result from the next call to Next. | |
14 | type Reader struct { | |
15 | q []Packet | |
16 | readers []io.Reader | |
17 | } | |
18 | ||
19 | // New io.Readers are pushed when a compressed or encrypted packet is processed | |
20 | // and recursively treated as a new source of packets. However, a carefully | |
21 | // crafted packet can trigger an infinite recursive sequence of packets. See | |
22 | // http://mumble.net/~campbell/misc/pgp-quine | |
23 | // https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402 | |
24 | // This constant limits the number of recursive packets that may be pushed. | |
25 | const maxReaders = 32 | |
26 | ||
27 | // Next returns the most recently unread Packet, or reads another packet from | |
28 | // the top-most io.Reader. Unknown packet types are skipped. | |
29 | func (r *Reader) Next() (p Packet, err error) { | |
30 | if len(r.q) > 0 { | |
31 | p = r.q[len(r.q)-1] | |
32 | r.q = r.q[:len(r.q)-1] | |
33 | return | |
34 | } | |
35 | ||
36 | for len(r.readers) > 0 { | |
37 | p, err = Read(r.readers[len(r.readers)-1]) | |
38 | if err == nil { | |
39 | return | |
40 | } | |
41 | if err == io.EOF { | |
42 | r.readers = r.readers[:len(r.readers)-1] | |
43 | continue | |
44 | } | |
45 | if _, ok := err.(errors.UnknownPacketTypeError); !ok { | |
46 | return nil, err | |
47 | } | |
48 | } | |
49 | ||
50 | return nil, io.EOF | |
51 | } | |
52 | ||
53 | // Push causes the Reader to start reading from a new io.Reader. When an EOF | |
54 | // error is seen from the new io.Reader, it is popped and the Reader continues | |
55 | // to read from the next most recent io.Reader. Push returns a StructuralError | |
56 | // if pushing the reader would exceed the maximum recursion level, otherwise it | |
57 | // returns nil. | |
58 | func (r *Reader) Push(reader io.Reader) (err error) { | |
59 | if len(r.readers) >= maxReaders { | |
60 | return errors.StructuralError("too many layers of packets") | |
61 | } | |
62 | r.readers = append(r.readers, reader) | |
63 | return nil | |
64 | } | |
65 | ||
66 | // Unread causes the given Packet to be returned from the next call to Next. | |
67 | func (r *Reader) Unread(p Packet) { | |
68 | r.q = append(r.q, p) | |
69 | } | |
70 | ||
71 | func NewReader(r io.Reader) *Reader { | |
72 | return &Reader{ | |
73 | q: nil, | |
74 | readers: []io.Reader{r}, | |
75 | } | |
76 | } |