main
Raw Download raw file
  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	"crypto"
  9	"encoding/binary"
 10	"io"
 11	"strconv"
 12
 13	"github.com/ProtonMail/go-crypto/openpgp/errors"
 14	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
 15)
 16
 17// OnePassSignature represents a one-pass signature packet. See RFC 4880,
 18// section 5.4.
 19type OnePassSignature struct {
 20	Version        int
 21	SigType        SignatureType
 22	Hash           crypto.Hash
 23	PubKeyAlgo     PublicKeyAlgorithm
 24	KeyId          uint64
 25	IsLast         bool
 26	Salt           []byte // v6 only
 27	KeyFingerprint []byte // v6 only
 28}
 29
 30func (ops *OnePassSignature) parse(r io.Reader) (err error) {
 31	var buf [8]byte
 32	// Read: version | signature type | hash algorithm | public-key algorithm
 33	_, err = readFull(r, buf[:4])
 34	if err != nil {
 35		return
 36	}
 37	if buf[0] != 3 && buf[0] != 6 {
 38		return errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
 39	}
 40	ops.Version = int(buf[0])
 41
 42	var ok bool
 43	ops.Hash, ok = algorithm.HashIdToHashWithSha1(buf[2])
 44	if !ok {
 45		return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
 46	}
 47
 48	ops.SigType = SignatureType(buf[1])
 49	ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
 50
 51	if ops.Version == 6 {
 52		// Only for v6, a variable-length field containing the salt
 53		_, err = readFull(r, buf[:1])
 54		if err != nil {
 55			return
 56		}
 57		saltLength := int(buf[0])
 58		var expectedSaltLength int
 59		expectedSaltLength, err = SaltLengthForHash(ops.Hash)
 60		if err != nil {
 61			return
 62		}
 63		if saltLength != expectedSaltLength {
 64			err = errors.StructuralError("unexpected salt size for the given hash algorithm")
 65			return
 66		}
 67		salt := make([]byte, expectedSaltLength)
 68		_, err = readFull(r, salt)
 69		if err != nil {
 70			return
 71		}
 72		ops.Salt = salt
 73
 74		// Only for v6 packets, 32 octets of the fingerprint of the signing key.
 75		fingerprint := make([]byte, 32)
 76		_, err = readFull(r, fingerprint)
 77		if err != nil {
 78			return
 79		}
 80		ops.KeyFingerprint = fingerprint
 81		ops.KeyId = binary.BigEndian.Uint64(ops.KeyFingerprint[:8])
 82	} else {
 83		_, err = readFull(r, buf[:8])
 84		if err != nil {
 85			return
 86		}
 87		ops.KeyId = binary.BigEndian.Uint64(buf[:8])
 88	}
 89
 90	_, err = readFull(r, buf[:1])
 91	if err != nil {
 92		return
 93	}
 94	ops.IsLast = buf[0] != 0
 95	return
 96}
 97
 98// Serialize marshals the given OnePassSignature to w.
 99func (ops *OnePassSignature) Serialize(w io.Writer) error {
100	//v3 length 1+1+1+1+8+1 =
101	packetLength := 13
102	if ops.Version == 6 {
103		// v6 length 1+1+1+1+1+len(salt)+32+1 =
104		packetLength = 38 + len(ops.Salt)
105	}
106
107	if err := serializeHeader(w, packetTypeOnePassSignature, packetLength); err != nil {
108		return err
109	}
110
111	var buf [8]byte
112	buf[0] = byte(ops.Version)
113	buf[1] = uint8(ops.SigType)
114	var ok bool
115	buf[2], ok = algorithm.HashToHashIdWithSha1(ops.Hash)
116	if !ok {
117		return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
118	}
119	buf[3] = uint8(ops.PubKeyAlgo)
120
121	_, err := w.Write(buf[:4])
122	if err != nil {
123		return err
124	}
125
126	if ops.Version == 6 {
127		// write salt for v6 signatures
128		_, err := w.Write([]byte{uint8(len(ops.Salt))})
129		if err != nil {
130			return err
131		}
132		_, err = w.Write(ops.Salt)
133		if err != nil {
134			return err
135		}
136
137		// write fingerprint v6 signatures
138		_, err = w.Write(ops.KeyFingerprint)
139		if err != nil {
140			return err
141		}
142	} else {
143		binary.BigEndian.PutUint64(buf[:8], ops.KeyId)
144		_, err := w.Write(buf[:8])
145		if err != nil {
146			return err
147		}
148	}
149
150	isLast := []byte{byte(0)}
151	if ops.IsLast {
152		isLast[0] = 1
153	}
154
155	_, err = w.Write(isLast)
156	return err
157}