main
Raw Download raw file
  1// Copyright 2012 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	"bytes"
  9	"io"
 10
 11	"github.com/ProtonMail/go-crypto/openpgp/errors"
 12)
 13
 14// OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is
 15// useful for splitting and storing the original packet contents separately,
 16// handling unsupported packet types or accessing parts of the packet not yet
 17// implemented by this package.
 18type OpaquePacket struct {
 19	// Packet type
 20	Tag uint8
 21	// Reason why the packet was parsed opaquely
 22	Reason error
 23	// Binary contents of the packet data
 24	Contents []byte
 25}
 26
 27func (op *OpaquePacket) parse(r io.Reader) (err error) {
 28	op.Contents, err = io.ReadAll(r)
 29	return
 30}
 31
 32// Serialize marshals the packet to a writer in its original form, including
 33// the packet header.
 34func (op *OpaquePacket) Serialize(w io.Writer) (err error) {
 35	err = serializeHeader(w, packetType(op.Tag), len(op.Contents))
 36	if err == nil {
 37		_, err = w.Write(op.Contents)
 38	}
 39	return
 40}
 41
 42// Parse attempts to parse the opaque contents into a structure supported by
 43// this package. If the packet is not known then the result will be another
 44// OpaquePacket.
 45func (op *OpaquePacket) Parse() (p Packet, err error) {
 46	hdr := bytes.NewBuffer(nil)
 47	err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents))
 48	if err != nil {
 49		op.Reason = err
 50		return op, err
 51	}
 52	p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents)))
 53	if err != nil {
 54		op.Reason = err
 55		p = op
 56	}
 57	return
 58}
 59
 60// OpaqueReader reads OpaquePackets from an io.Reader.
 61type OpaqueReader struct {
 62	r io.Reader
 63}
 64
 65func NewOpaqueReader(r io.Reader) *OpaqueReader {
 66	return &OpaqueReader{r: r}
 67}
 68
 69// Read the next OpaquePacket.
 70func (or *OpaqueReader) Next() (op *OpaquePacket, err error) {
 71	tag, _, contents, err := readHeader(or.r)
 72	if err != nil {
 73		return
 74	}
 75	op = &OpaquePacket{Tag: uint8(tag), Reason: err}
 76	err = op.parse(contents)
 77	if err != nil {
 78		consumeAll(contents)
 79	}
 80	return
 81}
 82
 83// OpaqueSubpacket represents an unparsed OpenPGP subpacket,
 84// as found in signature and user attribute packets.
 85type OpaqueSubpacket struct {
 86	SubType       uint8
 87	EncodedLength []byte // Store the original encoded length for signature verifications.
 88	Contents      []byte
 89}
 90
 91// OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from
 92// their byte representation.
 93func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) {
 94	var (
 95		subHeaderLen int
 96		subPacket    *OpaqueSubpacket
 97	)
 98	for len(contents) > 0 {
 99		subHeaderLen, subPacket, err = nextSubpacket(contents)
100		if err != nil {
101			break
102		}
103		result = append(result, subPacket)
104		contents = contents[subHeaderLen+len(subPacket.Contents):]
105	}
106	return
107}
108
109func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) {
110	// RFC 4880, section 5.2.3.1
111	var subLen uint32
112	var encodedLength []byte
113	if len(contents) < 1 {
114		goto Truncated
115	}
116	subPacket = &OpaqueSubpacket{}
117	switch {
118	case contents[0] < 192:
119		subHeaderLen = 2 // 1 length byte, 1 subtype byte
120		if len(contents) < subHeaderLen {
121			goto Truncated
122		}
123		encodedLength = contents[0:1]
124		subLen = uint32(contents[0])
125		contents = contents[1:]
126	case contents[0] < 255:
127		subHeaderLen = 3 // 2 length bytes, 1 subtype
128		if len(contents) < subHeaderLen {
129			goto Truncated
130		}
131		encodedLength = contents[0:2]
132		subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192
133		contents = contents[2:]
134	default:
135		subHeaderLen = 6 // 5 length bytes, 1 subtype
136		if len(contents) < subHeaderLen {
137			goto Truncated
138		}
139		encodedLength = contents[0:5]
140		subLen = uint32(contents[1])<<24 |
141			uint32(contents[2])<<16 |
142			uint32(contents[3])<<8 |
143			uint32(contents[4])
144		contents = contents[5:]
145
146	}
147	if subLen > uint32(len(contents)) || subLen == 0 {
148		goto Truncated
149	}
150	subPacket.SubType = contents[0]
151	subPacket.EncodedLength = encodedLength
152	subPacket.Contents = contents[1:subLen]
153	return
154Truncated:
155	err = errors.StructuralError("subpacket truncated")
156	return
157}
158
159func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) {
160	buf := make([]byte, 6)
161	copy(buf, osp.EncodedLength)
162	n := len(osp.EncodedLength)
163
164	buf[n] = osp.SubType
165	if _, err = w.Write(buf[:n+1]); err != nil {
166		return
167	}
168	_, err = w.Write(osp.Contents)
169	return
170}