github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/environs/simplestreams/decode.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package simplestreams
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io"
    10  
    11  	"golang.org/x/crypto/openpgp"
    12  	"golang.org/x/crypto/openpgp/clearsign"
    13  )
    14  
    15  // PGPPGPSignatureCheckFn can be overridden by tests to allow signatures from
    16  // non-trusted sources to be verified.
    17  var PGPSignatureCheckFn = func(keyring openpgp.KeyRing, signed, signature io.Reader) (*openpgp.Entity, error) {
    18  	return openpgp.CheckDetachedSignature(keyring, signed, signature)
    19  }
    20  
    21  // DecodeCheckSignature parses the inline signed PGP text, checks the signature,
    22  // and returns plain text if the signature matches.
    23  func DecodeCheckSignature(r io.Reader, armoredPublicKey string) ([]byte, error) {
    24  	data, err := io.ReadAll(r)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	b, _ := clearsign.Decode(data)
    29  	if b == nil {
    30  		return nil, &NotPGPSignedError{}
    31  	}
    32  	keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(armoredPublicKey))
    33  	if err != nil {
    34  		return nil, fmt.Errorf("failed to parse public key: %v", err)
    35  	}
    36  
    37  	_, err = PGPSignatureCheckFn(keyring, bytes.NewBuffer(b.Bytes), b.ArmoredSignature.Body)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	return b.Plaintext, nil
    42  }
    43  
    44  // NotPGPSignedError is used when PGP text does not contain an inline signature.
    45  type NotPGPSignedError struct{}
    46  
    47  func (*NotPGPSignedError) Error() string {
    48  	return "no PGP signature embedded in plain text data"
    49  }