From f21d5256f0d69653cdcc6591074791c04ee3e4c0 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Tue, 19 Sep 2023 22:41:31 +0200 Subject: [PATCH] pgp: improve handling of GnuPG home dir There have been reports about the new logic breaking certain GnuPG shims (#1294). As this behavior is only really required when SDK users are making use of the GnuPG using SOPS as an SDK. Prefer any runtime configuration when no custom GnuPG home is configured on the key source, instead of providing an absolute `--homedir` to `gpg`. Signed-off-by: Hidde Beydals --- pgp/keysource.go | 51 ++++++++++++++++++++++--------------------- pgp/keysource_test.go | 36 +++++++++++++++--------------- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/pgp/keysource.go b/pgp/keysource.go index b6c77bde0..ffeb0b1a2 100644 --- a/pgp/keysource.go +++ b/pgp/keysource.go @@ -318,7 +318,7 @@ func (key *MasterKey) encryptWithGnuPG(dataKey []byte) error { fingerprint, "--no-encrypt-to", } - err, stdout, stderr := gpgExec(key.gnuPGHome(), args, bytes.NewReader(dataKey)) + err, stdout, stderr := gpgExec(key.gnuPGHomeDir, args, bytes.NewReader(dataKey)) if err != nil { return fmt.Errorf("failed to encrypt sops data key with pgp: %s", strings.TrimSpace(stderr.String())) } @@ -407,7 +407,7 @@ func (key *MasterKey) decryptWithGnuPG() ([]byte, error) { args := []string{ "-d", } - err, stdout, stderr := gpgExec(key.gnuPGHome(), args, strings.NewReader(key.EncryptedKey)) + err, stdout, stderr := gpgExec(key.gnuPGHomeDir, args, strings.NewReader(key.EncryptedKey)) if err != nil { return nil, fmt.Errorf("failed to decrypt sops data key with pgp: %s", strings.TrimSpace(stderr.String())) @@ -436,27 +436,6 @@ func (key MasterKey) ToMap() map[string]interface{} { return out } -// gnuPGHome determines the GnuPG home directory for the MasterKey, and returns -// its path. In order of preference: -// 1. MasterKey.gnuPGHomeDir -// 2. $GNUPGHOME -// 3. user.Current().HomeDir/.gnupg -// 4. $HOME/.gnupg -func (key *MasterKey) gnuPGHome() string { - if key.gnuPGHomeDir == "" { - dir := os.Getenv("GNUPGHOME") - if dir == "" { - usr, err := user.Current() - if err != nil { - return filepath.Join(os.Getenv("HOME"), ".gnupg") - } - return filepath.Join(usr.HomeDir, ".gnupg") - } - return dir - } - return key.gnuPGHomeDir -} - // retrievePubKey attempts to retrieve the public key from the public keyring // by Fingerprint. func (key *MasterKey) retrievePubKey() (openpgp.Entity, error) { @@ -479,7 +458,7 @@ func (key *MasterKey) retrievePubKey() (openpgp.Entity, error) { func (key *MasterKey) getPubRing() (openpgp.EntityList, error) { path := key.pubRing if path == "" { - path = filepath.Join(key.gnuPGHome(), defaultPubRing) + path = filepath.Join(gnuPGHome(key.gnuPGHomeDir), defaultPubRing) } return loadRing(path) } @@ -490,7 +469,7 @@ func (key *MasterKey) getPubRing() (openpgp.EntityList, error) { func (key *MasterKey) getSecRing() (openpgp.EntityList, error) { path := key.secRing if path == "" { - path = filepath.Join(key.gnuPGHome(), defaultSecRing) + path = filepath.Join(gnuPGHome(key.gnuPGHomeDir), defaultSecRing) } if _, err := os.Lstat(path); err != nil { if !os.IsNotExist(err) { @@ -609,6 +588,28 @@ func gpgBinary() string { return binary } +// gnuPGHome determines the GnuPG home directory, and returns its path. +// In order of preference: +// 1. customPath +// 2. $GNUPGHOME +// 3. user.Current().HomeDir/.gnupg +// 4. $HOME/.gnupg +func gnuPGHome(customPath string) string { + if customPath != "" { + return customPath + } + + dir := os.Getenv("GNUPGHOME") + if dir == "" { + usr, err := user.Current() + if err != nil { + return filepath.Join(os.Getenv("HOME"), ".gnupg") + } + return filepath.Join(usr.HomeDir, ".gnupg") + } + return dir +} + // shortenFingerprint returns the short ID of the given fingerprint. // This is mostly used for compatability reasons, as older versions of GnuPG // do not always like long IDs. diff --git a/pgp/keysource_test.go b/pgp/keysource_test.go index 58cb32040..187a75b1d 100644 --- a/pgp/keysource_test.go +++ b/pgp/keysource_test.go @@ -271,7 +271,7 @@ func TestMasterKey_encryptWithGnuPG(t *testing.T) { args := []string{ "-d", } - err, stdout, stderr := gpgExec(key.gnuPGHome(), args, strings.NewReader(key.EncryptedKey)) + err, stdout, stderr := gpgExec(key.gnuPGHomeDir, args, strings.NewReader(key.EncryptedKey)) assert.NoError(t, err, stderr.String()) assert.Equal(t, data, stdout.Bytes()) }) @@ -529,24 +529,6 @@ func TestMasterKey_ToMap(t *testing.T) { }, key.ToMap()) } -func TestMasterKey_gnuPGHome(t *testing.T) { - key := &MasterKey{} - - usr, err := user.Current() - if err == nil { - assert.Equal(t, filepath.Join(usr.HomeDir, ".gnupg"), key.gnuPGHome()) - } else { - assert.Equal(t, filepath.Join(os.Getenv("HOME"), ".gnupg"), key.gnuPGHome()) - } - - gnupgHome := "/overwrite/home" - t.Setenv("GNUPGHOME", gnupgHome) - assert.Equal(t, gnupgHome, key.gnuPGHome()) - - key.gnuPGHomeDir = "/home/dir/overwrite" - assert.Equal(t, key.gnuPGHomeDir, key.gnuPGHome()) -} - func TestMasterKey_retrievePubKey(t *testing.T) { t.Run("existing fingerprint", func(t *testing.T) { key := NewMasterKeyFromFingerprint(mockFingerprint) @@ -671,6 +653,22 @@ func Test_gpgBinary(t *testing.T) { assert.Equal(t, overwrite, gpgBinary()) } +func Test_gnuPGHome(t *testing.T) { + usr, err := user.Current() + if err == nil { + assert.Equal(t, filepath.Join(usr.HomeDir, ".gnupg"), gnuPGHome("")) + } else { + assert.Equal(t, filepath.Join(os.Getenv("HOME"), ".gnupg"), gnuPGHome("")) + } + + gnupgHome := "/overwrite/home" + t.Setenv("GNUPGHOME", gnupgHome) + assert.Equal(t, gnupgHome, gnuPGHome("")) + + customP := "/home/dir/overwrite" + assert.Equal(t, customP, gnuPGHome(customP)) +} + func Test_shortenFingerprint(t *testing.T) { shortId := shortenFingerprint(mockFingerprint) assert.Equal(t, "9732075EA221A7EA", shortId)