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 }