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
|
// Note: Consider the API unstable until the code supports at least three different image formats or transports.
package signature
import (
"bytes"
"errors"
"fmt"
"io"
"strings"
// This code is used only to parse the data in an explicitly-untrusted
// code path, where cryptography is not relevant. For now, continue to
// use this frozen deprecated implementation. When mechanism_openpgp.go
// migrates to another implementation, this should migrate as well.
//lint:ignore SA1019 See above
"golang.org/x/crypto/openpgp" //nolint:staticcheck
)
// SigningMechanism abstracts a way to sign binary blobs and verify their signatures.
// Each mechanism should eventually be closed by calling Close().
type SigningMechanism interface {
// Close removes resources associated with the mechanism, if any.
Close() error
// SupportsSigning returns nil if the mechanism supports signing, or a SigningNotSupportedError.
SupportsSigning() error
// Sign creates a (non-detached) signature of input using keyIdentity.
// Fails with a SigningNotSupportedError if the mechanism does not support signing.
Sign(input []byte, keyIdentity string) ([]byte, error)
// Verify parses unverifiedSignature and returns the content and the signer's identity
Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error)
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
// along with a short identifier of the key used for signing.
// WARNING: The short key identifier (which corresponds to "Key ID" for OpenPGP keys)
// is NOT the same as a "key identity" used in other calls to this interface, and
// the values may have no recognizable relationship if the public key is not available.
UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error)
}
// signingMechanismWithPassphrase is an internal extension of SigningMechanism.
type signingMechanismWithPassphrase interface {
SigningMechanism
// Sign creates a (non-detached) signature of input using keyIdentity and passphrase.
// Fails with a SigningNotSupportedError if the mechanism does not support signing.
SignWithPassphrase(input []byte, keyIdentity string, passphrase string) ([]byte, error)
}
// SigningNotSupportedError is returned when trying to sign using a mechanism which does not support that.
type SigningNotSupportedError string
func (err SigningNotSupportedError) Error() string {
return string(err)
}
// NewGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism for the user’s default
// GPG configuration ($GNUPGHOME / ~/.gnupg)
// The caller must call .Close() on the returned SigningMechanism.
func NewGPGSigningMechanism() (SigningMechanism, error) {
return newGPGSigningMechanismInDirectory("")
}
// NewEphemeralGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism which
// recognizes _only_ public keys from the supplied blob, and returns the identities
// of these keys.
// The caller must call .Close() on the returned SigningMechanism.
func NewEphemeralGPGSigningMechanism(blob []byte) (SigningMechanism, []string, error) {
return newEphemeralGPGSigningMechanism([][]byte{blob})
}
// gpgUntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
// along with a short identifier of the key used for signing.
// WARNING: The short key identifier (which corresponds to "Key ID" for OpenPGP keys)
// is NOT the same as a "key identity" used in other calls to this interface, and
// the values may have no recognizable relationship if the public key is not available.
func gpgUntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) {
// This uses the Golang-native OpenPGP implementation instead of gpgme because we are not doing any cryptography.
md, err := openpgp.ReadMessage(bytes.NewReader(untrustedSignature), openpgp.EntityList{}, nil, nil)
if err != nil {
return nil, "", err
}
if !md.IsSigned {
return nil, "", errors.New("The input is not a signature")
}
content, err := io.ReadAll(md.UnverifiedBody)
if err != nil {
// Coverage: An error during reading the body can happen only if
// 1) the message is encrypted, which is not our case (and we don’t give ReadMessage the key
// to decrypt the contents anyway), or
// 2) the message is signed AND we give ReadMessage a corresponding public key, which we don’t.
return nil, "", err
}
// Uppercase the key ID for minimal consistency with the gpgme-returned fingerprints
// (but note that key ID is a suffix of the fingerprint only for V4 keys, not V3)!
return content, strings.ToUpper(fmt.Sprintf("%016X", md.SignedByKeyId)), nil
}
|