| // Copyright 2012 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package packet |
| |
| import ( |
| "bytes" |
| "io" |
| |
| "golang.org/x/crypto/openpgp/errors" |
| ) |
| |
| // OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is |
| // useful for splitting and storing the original packet contents separately, |
| // handling unsupported packet types or accessing parts of the packet not yet |
| // implemented by this package. |
| type OpaquePacket struct { |
| // Packet type |
| Tag uint8 |
| // Reason why the packet was parsed opaquely |
| Reason error |
| // Binary contents of the packet data |
| Contents []byte |
| } |
| |
| func (op *OpaquePacket) parse(r io.Reader) (err error) { |
| op.Contents, err = io.ReadAll(r) |
| return |
| } |
| |
| // Serialize marshals the packet to a writer in its original form, including |
| // the packet header. |
| func (op *OpaquePacket) Serialize(w io.Writer) (err error) { |
| err = serializeHeader(w, packetType(op.Tag), len(op.Contents)) |
| if err == nil { |
| _, err = w.Write(op.Contents) |
| } |
| return |
| } |
| |
| // Parse attempts to parse the opaque contents into a structure supported by |
| // this package. If the packet is not known then the result will be another |
| // OpaquePacket. |
| func (op *OpaquePacket) Parse() (p Packet, err error) { |
| hdr := bytes.NewBuffer(nil) |
| err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents)) |
| if err != nil { |
| op.Reason = err |
| return op, err |
| } |
| p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents))) |
| if err != nil { |
| op.Reason = err |
| p = op |
| } |
| return |
| } |
| |
| // OpaqueReader reads OpaquePackets from an io.Reader. |
| type OpaqueReader struct { |
| r io.Reader |
| } |
| |
| func NewOpaqueReader(r io.Reader) *OpaqueReader { |
| return &OpaqueReader{r: r} |
| } |
| |
| // Read the next OpaquePacket. |
| func (or *OpaqueReader) Next() (op *OpaquePacket, err error) { |
| tag, _, contents, err := readHeader(or.r) |
| if err != nil { |
| return |
| } |
| op = &OpaquePacket{Tag: uint8(tag), Reason: err} |
| err = op.parse(contents) |
| if err != nil { |
| consumeAll(contents) |
| } |
| return |
| } |
| |
| // OpaqueSubpacket represents an unparsed OpenPGP subpacket, |
| // as found in signature and user attribute packets. |
| type OpaqueSubpacket struct { |
| SubType uint8 |
| Contents []byte |
| } |
| |
| // OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from |
| // their byte representation. |
| func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) { |
| var ( |
| subHeaderLen int |
| subPacket *OpaqueSubpacket |
| ) |
| for len(contents) > 0 { |
| subHeaderLen, subPacket, err = nextSubpacket(contents) |
| if err != nil { |
| break |
| } |
| result = append(result, subPacket) |
| contents = contents[subHeaderLen+len(subPacket.Contents):] |
| } |
| return |
| } |
| |
| func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) { |
| // RFC 4880, section 5.2.3.1 |
| var subLen uint32 |
| if len(contents) < 1 { |
| goto Truncated |
| } |
| subPacket = &OpaqueSubpacket{} |
| switch { |
| case contents[0] < 192: |
| subHeaderLen = 2 // 1 length byte, 1 subtype byte |
| if len(contents) < subHeaderLen { |
| goto Truncated |
| } |
| subLen = uint32(contents[0]) |
| contents = contents[1:] |
| case contents[0] < 255: |
| subHeaderLen = 3 // 2 length bytes, 1 subtype |
| if len(contents) < subHeaderLen { |
| goto Truncated |
| } |
| subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192 |
| contents = contents[2:] |
| default: |
| subHeaderLen = 6 // 5 length bytes, 1 subtype |
| if len(contents) < subHeaderLen { |
| goto Truncated |
| } |
| subLen = uint32(contents[1])<<24 | |
| uint32(contents[2])<<16 | |
| uint32(contents[3])<<8 | |
| uint32(contents[4]) |
| contents = contents[5:] |
| } |
| if subLen > uint32(len(contents)) || subLen == 0 { |
| goto Truncated |
| } |
| subPacket.SubType = contents[0] |
| subPacket.Contents = contents[1:subLen] |
| return |
| Truncated: |
| err = errors.StructuralError("subpacket truncated") |
| return |
| } |
| |
| func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) { |
| buf := make([]byte, 6) |
| n := serializeSubpacketLength(buf, len(osp.Contents)+1) |
| buf[n] = osp.SubType |
| if _, err = w.Write(buf[:n+1]); err != nil { |
| return |
| } |
| _, err = w.Write(osp.Contents) |
| return |
| } |