Skip to content

Commit

Permalink
Use shorter SSH control path (gopasspw#1899)
Browse files Browse the repository at this point in the history
Fixes gopasspw#1896

RELEASE_NOTES=[BUGFIX] Fix SSH control path

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
  • Loading branch information
dominikschulz committed Apr 5, 2021
1 parent 274c552 commit 1751d6b
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 4 deletions.
1 change: 1 addition & 0 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* *gopass fails with 'gpg failed to sign the data fatal: failed to write commit object'* - If git is not able to interface with GPG, commits will fail because gopass configures git to sign commits by default. Have a look a [this question](https://stackoverflow.com/questions/39494631/gpg-failed-to-sign-the-data-fatal-failed-to-write-commit-object-git-2-10-0) for more information.
* *Can gopass be used with Terraform?* - Yes, there is a gopass-based [Terraform provider](https://github.com/camptocamp/terraform-provider-pass) available.
* *How can I fix ´"gpg: decryption failed: No secret key"` errors?* - Set the ´auto-expand-secmem` option in your gpg-agent.conf, if your version of GnuPG supports it.
* *I'm getting `Path too long for Unix domain socket` errors, usually on MacOS*. This can be fixed by setting `export TMPDIR=/tmp` (or any other suiteable location with a path shorter than 80 characters).

## API Stability

Expand Down
9 changes: 7 additions & 2 deletions internal/backend/crypto/gpg/cli/gpg.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/gopasspw/gopass/internal/backend/crypto/gpg"
"github.com/gopasspw/gopass/pkg/debug"
"github.com/gopasspw/gopass/pkg/fsutil"
lru "github.com/hashicorp/golang-lru"
)

Expand Down Expand Up @@ -51,10 +50,16 @@ func New(ctx context.Context, cfg Config) (*GPG, error) {
}
}

gcfg, err := gpgConfig()
if err != nil {
debug.Log("failed to read GPG config: %s", err)
}
_, throwKids := gcfg["throw-keyids"]

g := &GPG{
binary: "gpg",
args: append(defaultArgs, cfg.Args...),
throwKids: fsutil.FileContains(gpgConfigLoc(), "throw-keyids"),
throwKids: throwKids,
}

debug.Log("initializing LRU cache")
Expand Down
35 changes: 35 additions & 0 deletions internal/backend/crypto/gpg/cli/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cli

import (
"bufio"
"io"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -29,6 +31,39 @@ func gpgConfigLoc() string {
return filepath.Join(uhd, ".gnupg", "gpg.conf")
}

func gpgConfig() (map[string]string, error) {
fh, err := os.Open(gpgConfigLoc())
if err != nil {
return nil, err
}
defer fh.Close()

return parseGpgConfig(fh)
}

func parseGpgConfig(fh io.Reader) (map[string]string, error) {
val := make(map[string]string, 20)
scanner := bufio.NewScanner(fh)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
// ignore comments
if strings.HasPrefix(line, "#") {
continue
}
p := strings.SplitN(line, " ", 2)
if len(p) < 1 {
continue
}
val[p[0]] = ""
if len(p) < 2 {
continue
}
val[p[0]] = strings.TrimSpace(p[1])
}

return val, nil
}

// GPGOpts parses extra GPG options from the environment
func GPGOpts() []string {
for _, en := range []string{"GOPASS_GPG_OPTS", "PASSWORD_STORE_GPG_OPTS"} {
Expand Down
87 changes: 87 additions & 0 deletions internal/backend/crypto/gpg/cli/utils_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package cli

import (
"bytes"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGpgOpts(t *testing.T) {
Expand Down Expand Up @@ -33,3 +35,88 @@ func TestSplitPacket(t *testing.T) {
assert.Equal(t, out, splitPacket(in))
}
}

func TestGPGConfig(t *testing.T) {
in := `
#-----------------------------
# default key
#-----------------------------
# The default key to sign with. If this option is not used, the default key is
# the first key found in the secret keyring
#default-key 0xD8692123C4065DEA5E0F3AB5249B39D24F25E3F6
#-----------------------------
# behavior
#-----------------------------
# Disable inclusion of the version string in ASCII armored output
no-emit-version
# Disable comment string in clear text signatures and ASCII armored messages
no-comments
# Display long key IDs
keyid-format 0xlong
# List all keys (or the specified ones) along with their fingerprints
with-fingerprint
# Display the calculated validity of user IDs during key listings
list-options show-uid-validity
verify-options show-uid-validity
# Try to use the GnuPG-Agent. With this option, GnuPG first tries to connect to
# the agent before it asks for a passphrase.
use-agent
#-----------------------------
# keyserver
#-----------------------------
# This is the server that --recv-keys, --send-keys, and --search-keys will
# communicate with to receive keys from, send keys to, and search for keys on
keyserver hkps://hkps.pool.sks-keyservers.net
# Provide a certificate store to override the system default
# Get this from https://sks-keyservers.net/sks-keyservers.netCA.pem
#keyserver-options ca-cert-file=/usr/local/etc/ssl/certs/hkps.pool.sks-keyservers.net.pem
# Set the proxy to use for HTTP and HKP keyservers - default to the standard
# local Tor socks proxy
# It is encouraged to use Tor for improved anonymity. Preferably use either a
# dedicated SOCKSPort for GnuPG and/or enable IsolateDestPort and
# IsolateDestAddr
#keyserver-options http-proxy=socks5-hostname://127.0.0.1:9050
# Don't leak DNS, see https://trac.torproject.org/projects/tor/ticket/2846
#keyserver-options no-try-dns-srv
# When using --refresh-keys, if the key in question has a preferred keyserver
# URL, then disable use of that preferred keyserver to refresh the key from
keyserver-options no-honor-keyserver-url
# When searching for a key with --search-keys, include keys that are marked on
# the keyserver as revoked
keyserver-options include-revoked
#-----------------------------
# algorithm and ciphers
#-----------------------------
# list of personal digest preferences. When multiple digests are supported by
# all recipients, choose the strongest one
personal-cipher-preferences AES256 AES192 AES CAST5
# list of personal digest preferences. When multiple ciphers are supported by
# all recipients, choose the strongest one
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
# message digest algorithm used when signing a key
cert-digest-algo SHA512
# This preference list is used for new keys and becomes the default for
# "setpref" in the edit menu
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
default-recipient-self
# GPGConf disabled this option here at Di 26 Aug 2008 14:22:45 CEST
# keyserver pgpkeys.pca.dfn.de
default-cert-check-level 3
no-mangle-dos-filenames
no-secmem-warning
use-agent
#throw-keyids
default-key FEEDBEEF
utf8-strings
encrypt-to DEADBEEF
`
cfg, err := parseGpgConfig(bytes.NewReader([]byte(in)))
require.NoError(t, err)
assert.Equal(t, "SHA512", cfg["cert-digest-algo"])
_, found := cfg["throw-keyids"]
assert.False(t, found)
assert.Equal(t, "DEADBEEF", cfg["encrypt-to"])
}
8 changes: 7 additions & 1 deletion internal/backend/storage/fs/fsck.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/gopasspw/gopass/pkg/ctxutil"
"github.com/gopasspw/gopass/pkg/debug"
"github.com/gopasspw/gopass/pkg/fsutil"
"github.com/gopasspw/gopass/pkg/termio"
)

// Fsck checks the storage integrity
Expand Down Expand Up @@ -47,7 +48,12 @@ func (s *Store) Fsck(ctx context.Context) error {
}

debug.Log("checking root dir %q", s.path)
return s.fsckCheckDir(ctx, s.path)
if err := s.fsckCheckDir(ctx, s.path); err != nil {
return err
}

debug.Log("checking git config")
return s.InitConfig(ctx, termio.DetectName(ctx, nil), termio.DetectEmail(ctx, nil))
}

func (s *Store) fsckCheckFile(ctx context.Context, filename string) error {
Expand Down
5 changes: 4 additions & 1 deletion internal/backend/storage/gitfs/ssh_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import "os"
//
// Note: Setting GIT_SSH_COMMAND, possibly to an empty string, will take
// precedence over this setting.
//
// %C is a hash of %l%h%p%r and should avoid "path too long for unix domain socket"
// errors. If you still encounter this error set TMPDIR to a short path, e.g. /tmp.
func gitSSHCommand() string {
return "ssh -oControlMaster=auto -oControlPersist=600 -oControlPath=" + os.TempDir() + "/.gopass-ssh-${USER}-%r@%h:%p"
return "ssh -oControlMaster=auto -oControlPersist=600 -oControlPath=" + os.TempDir() + "/.ssh-%C"
}
3 changes: 3 additions & 0 deletions internal/store/leaf/fsck.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ func (s *Store) fsckCheckEntry(ctx context.Context, name string) error {
}

// check itemRecps matches storeRecps
// TODO we need to noramlize both slices before we can compare them,
// otherwise one might contain a short key id or a name while the other has
// the full key id
missing, extra := compareStringSlices(perItemStoreRecps, itemRecps)
if len(missing) > 0 {
out.Errorf(ctx, "Missing recipients on %s: %+v\nRun fsck with the --decrypt flag to re-encrypt it automatically, or edit this secret yourself.", name, missing)
Expand Down

0 comments on commit 1751d6b

Please sign in to comment.