main
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
5package packet
6
7import (
8 "io"
9
10 "github.com/ProtonMail/go-crypto/openpgp/errors"
11)
12
13type PacketReader interface {
14 Next() (p Packet, err error)
15 Push(reader io.Reader) (err error)
16 Unread(p Packet)
17}
18
19// Reader reads packets from an io.Reader and allows packets to be 'unread' so
20// that they result from the next call to Next.
21type Reader struct {
22 q []Packet
23 readers []io.Reader
24}
25
26// New io.Readers are pushed when a compressed or encrypted packet is processed
27// and recursively treated as a new source of packets. However, a carefully
28// crafted packet can trigger an infinite recursive sequence of packets. See
29// http://mumble.net/~campbell/misc/pgp-quine
30// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402
31// This constant limits the number of recursive packets that may be pushed.
32const maxReaders = 32
33
34// Next returns the most recently unread Packet, or reads another packet from
35// the top-most io.Reader. Unknown/unsupported/Marker packet types are skipped.
36func (r *Reader) Next() (p Packet, err error) {
37 for {
38 p, err := r.read()
39 if err == io.EOF {
40 break
41 } else if err != nil {
42 if _, ok := err.(errors.UnknownPacketTypeError); ok {
43 continue
44 }
45 if _, ok := err.(errors.UnsupportedError); ok {
46 switch p.(type) {
47 case *SymmetricallyEncrypted, *AEADEncrypted, *Compressed, *LiteralData:
48 return nil, err
49 }
50 continue
51 }
52 return nil, err
53 } else {
54 //A marker packet MUST be ignored when received
55 switch p.(type) {
56 case *Marker:
57 continue
58 }
59 return p, nil
60 }
61 }
62 return nil, io.EOF
63}
64
65// Next returns the most recently unread Packet, or reads another packet from
66// the top-most io.Reader. Unknown/Marker packet types are skipped while unsupported
67// packets are returned as UnsupportedPacket type.
68func (r *Reader) NextWithUnsupported() (p Packet, err error) {
69 for {
70 p, err = r.read()
71 if err == io.EOF {
72 break
73 } else if err != nil {
74 if _, ok := err.(errors.UnknownPacketTypeError); ok {
75 continue
76 }
77 if casteErr, ok := err.(errors.UnsupportedError); ok {
78 return &UnsupportedPacket{
79 IncompletePacket: p,
80 Error: casteErr,
81 }, nil
82 }
83 return
84 } else {
85 //A marker packet MUST be ignored when received
86 switch p.(type) {
87 case *Marker:
88 continue
89 }
90 return
91 }
92 }
93 return nil, io.EOF
94}
95
96func (r *Reader) read() (p Packet, err error) {
97 if len(r.q) > 0 {
98 p = r.q[len(r.q)-1]
99 r.q = r.q[:len(r.q)-1]
100 return
101 }
102 for len(r.readers) > 0 {
103 p, err = Read(r.readers[len(r.readers)-1])
104 if err == io.EOF {
105 r.readers = r.readers[:len(r.readers)-1]
106 continue
107 }
108 return p, err
109 }
110 return nil, io.EOF
111}
112
113// Push causes the Reader to start reading from a new io.Reader. When an EOF
114// error is seen from the new io.Reader, it is popped and the Reader continues
115// to read from the next most recent io.Reader. Push returns a StructuralError
116// if pushing the reader would exceed the maximum recursion level, otherwise it
117// returns nil.
118func (r *Reader) Push(reader io.Reader) (err error) {
119 if len(r.readers) >= maxReaders {
120 return errors.StructuralError("too many layers of packets")
121 }
122 r.readers = append(r.readers, reader)
123 return nil
124}
125
126// Unread causes the given Packet to be returned from the next call to Next.
127func (r *Reader) Unread(p Packet) {
128 r.q = append(r.q, p)
129}
130
131func NewReader(r io.Reader) *Reader {
132 return &Reader{
133 q: nil,
134 readers: []io.Reader{r},
135 }
136}
137
138// CheckReader is similar to Reader but additionally
139// uses the pushdown automata to verify the read packet sequence.
140type CheckReader struct {
141 Reader
142 verifier *SequenceVerifier
143 fullyRead bool
144}
145
146// Next returns the most recently unread Packet, or reads another packet from
147// the top-most io.Reader. Unknown packet types are skipped.
148// If the read packet sequence does not conform to the packet composition
149// rules in rfc4880, it returns an error.
150func (r *CheckReader) Next() (p Packet, err error) {
151 if r.fullyRead {
152 return nil, io.EOF
153 }
154 if len(r.q) > 0 {
155 p = r.q[len(r.q)-1]
156 r.q = r.q[:len(r.q)-1]
157 return
158 }
159 var errMsg error
160 for len(r.readers) > 0 {
161 p, errMsg, err = ReadWithCheck(r.readers[len(r.readers)-1], r.verifier)
162 if errMsg != nil {
163 err = errMsg
164 return
165 }
166 if err == nil {
167 return
168 }
169 if err == io.EOF {
170 r.readers = r.readers[:len(r.readers)-1]
171 continue
172 }
173 //A marker packet MUST be ignored when received
174 switch p.(type) {
175 case *Marker:
176 continue
177 }
178 if _, ok := err.(errors.UnknownPacketTypeError); ok {
179 continue
180 }
181 if _, ok := err.(errors.UnsupportedError); ok {
182 switch p.(type) {
183 case *SymmetricallyEncrypted, *AEADEncrypted, *Compressed, *LiteralData:
184 return nil, err
185 }
186 continue
187 }
188 return nil, err
189 }
190 if errMsg = r.verifier.Next(EOSSymbol); errMsg != nil {
191 return nil, errMsg
192 }
193 if errMsg = r.verifier.AssertValid(); errMsg != nil {
194 return nil, errMsg
195 }
196 r.fullyRead = true
197 return nil, io.EOF
198}
199
200func NewCheckReader(r io.Reader) *CheckReader {
201 return &CheckReader{
202 Reader: Reader{
203 q: nil,
204 readers: []io.Reader{r},
205 },
206 verifier: NewSequenceVerifier(),
207 fullyRead: false,
208 }
209}