1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
// Copyright (c) 2020-2024, Sylabs Inc. All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the LICENSE.md file
// distributed with the sources of this project regarding your rights to use or distribute this
// software.
package integrity
import (
"bytes"
"context"
"crypto"
"errors"
"io"
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/clearsign"
"github.com/ProtonMail/go-crypto/openpgp/packet"
)
var errClearsignedMsgNotFound = errors.New("clearsigned message not found")
type clearsignEncoder struct {
e *openpgp.Entity
config *packet.Config
}
// newClearsignEncoder returns an encoder that signs messages in clear-sign format using entity e,
// according to config.
func newClearsignEncoder(e *openpgp.Entity, config *packet.Config) *clearsignEncoder {
return &clearsignEncoder{
e: e,
config: config,
}
}
// signMessage signs the message from r in clear-sign format, and writes the result to w. On
// success, the hash function is returned.
func (en *clearsignEncoder) signMessage(_ context.Context, w io.Writer, r io.Reader) (crypto.Hash, error) {
plaintext, err := clearsign.Encode(w, en.e.PrivateKey, en.config)
if err != nil {
return 0, err
}
defer plaintext.Close()
_, err = io.Copy(plaintext, r)
return en.config.Hash(), err
}
type clearsignDecoder struct {
kr openpgp.KeyRing
}
// newClearsignDecoder returns a decoder that verifies messages in clear-sign format using key
// material from kr.
func newClearsignDecoder(kr openpgp.KeyRing) *clearsignDecoder {
return &clearsignDecoder{
kr: kr,
}
}
// verifyMessage reads a message from r, verifies its signature, and returns the message contents.
// On success, the signing entity is set in vr.
func (de *clearsignDecoder) verifyMessage(_ context.Context, r io.Reader, _ crypto.Hash, vr *VerifyResult) ([]byte, error) { //nolint:lll
data, err := io.ReadAll(r)
if err != nil {
return nil, err
}
// Decode clearsign block.
b, _ := clearsign.Decode(data)
if b == nil {
return nil, errClearsignedMsgNotFound
}
// Hash functions specified for OpenPGP in RFC4880, excluding those that are not currently
// recommended by NIST.
expectedHashes := []crypto.Hash{
crypto.SHA224,
crypto.SHA256,
crypto.SHA384,
crypto.SHA512,
}
// Check signature.
vr.e, err = openpgp.CheckDetachedSignatureAndHash(
de.kr,
bytes.NewReader(b.Bytes),
b.ArmoredSignature.Body,
expectedHashes,
nil,
)
if err != nil {
return nil, err
}
return b.Plaintext, err
}
// isClearsignSignature returns true if r contains a signature in clearsign format.
func isClearsignSignature(r io.Reader) bool {
b, err := io.ReadAll(r)
if err != nil {
return false
}
p, _ := clearsign.Decode(b)
return p != nil
}
|