Check for trailing garbage after the password
From the comment: // CheckTrailingGarbage tries to read one byte from stdin and exits with a // fatal error if the read returns any data. // This is meant to be called after reading the password, when there is no more // data expected. This helps to catch problems with third-party tools that // interface with gocryptfs.
This commit is contained in:
parent
2dd90ac19c
commit
8adfbf2dc3
@ -36,6 +36,7 @@ func initDir(args *argContainer) {
|
|||||||
tlog.Info.Printf("Choose a password for protecting your files.")
|
tlog.Info.Printf("Choose a password for protecting your files.")
|
||||||
}
|
}
|
||||||
password := readpassword.Twice(args.extpass)
|
password := readpassword.Twice(args.extpass)
|
||||||
|
readpassword.CheckTrailingGarbage()
|
||||||
creator := tlog.ProgramName + " " + GitVersion
|
creator := tlog.ProgramName + " " + GitVersion
|
||||||
err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv, args.raw64)
|
err = configfile.CreateConfFile(args.config, password, args.plaintextnames, args.scryptn, creator, args.aessiv, args.raw64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
|
|
||||||
@ -141,3 +143,33 @@ func readLineUnbuffered(r io.Reader) (l string) {
|
|||||||
l = l + string(b)
|
l = l + string(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckTrailingGarbage tries to read one byte from stdin and exits with a
|
||||||
|
// fatal error if the read returns any data.
|
||||||
|
// This is meant to be called after reading the password, when there is no more
|
||||||
|
// data expected. This helps to catch problems with third-party tools that
|
||||||
|
// interface with gocryptfs.
|
||||||
|
//
|
||||||
|
// This is tested via TestInitTrailingGarbage() in tests/cli/cli_test.go.
|
||||||
|
func CheckTrailingGarbage() {
|
||||||
|
if terminal.IsTerminal(int(os.Stdin.Fd())) {
|
||||||
|
// Be lenient when interacting with a human.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
b := make([]byte, 1)
|
||||||
|
wg.Done()
|
||||||
|
n, _ := os.Stdin.Read(b)
|
||||||
|
if n > 0 {
|
||||||
|
tlog.Fatal.Printf("Received trailing garbage after the password")
|
||||||
|
os.Exit(exitCode)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// Wait for the goroutine to start up plus one millisecond for the read to
|
||||||
|
// return. If there is data available, this SHOULD be plenty of time to
|
||||||
|
// read one byte. However, I don't see a way to be sure.
|
||||||
|
wg.Wait()
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
1
main.go
1
main.go
@ -87,6 +87,7 @@ func changePassword(args *argContainer) {
|
|||||||
}
|
}
|
||||||
tlog.Info.Println("Please enter your new password.")
|
tlog.Info.Println("Please enter your new password.")
|
||||||
newPw := readpassword.Twice(args.extpass)
|
newPw := readpassword.Twice(args.extpass)
|
||||||
|
readpassword.CheckTrailingGarbage()
|
||||||
confFile.EncryptKey(masterkey, newPw, confFile.ScryptObject.LogN())
|
confFile.EncryptKey(masterkey, newPw, confFile.ScryptObject.LogN())
|
||||||
if args.masterkey != "" {
|
if args.masterkey != "" {
|
||||||
bak := args.config + ".bak"
|
bak := args.config + ".bak"
|
||||||
|
2
mount.go
2
mount.go
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/rfjakob/gocryptfs/internal/ctlsock"
|
"github.com/rfjakob/gocryptfs/internal/ctlsock"
|
||||||
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
|
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
|
||||||
"github.com/rfjakob/gocryptfs/internal/fusefrontend_reverse"
|
"github.com/rfjakob/gocryptfs/internal/fusefrontend_reverse"
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/readpassword"
|
||||||
"github.com/rfjakob/gocryptfs/internal/tlog"
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -96,6 +97,7 @@ func doMount(args *argContainer) int {
|
|||||||
}
|
}
|
||||||
os.Exit(ErrExitLoadConf)
|
os.Exit(ErrExitLoadConf)
|
||||||
}
|
}
|
||||||
|
readpassword.CheckTrailingGarbage()
|
||||||
printMasterKey(masterkey)
|
printMasterKey(masterkey)
|
||||||
}
|
}
|
||||||
// We cannot use JSON for pretty-printing as the fields are unexported
|
// We cannot use JSON for pretty-printing as the fields are unexported
|
||||||
|
@ -272,3 +272,47 @@ func TestShadows(t *testing.T) {
|
|||||||
t.Errorf("Should have failed")
|
t.Errorf("Should have failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestInitTrailingGarbage verfies that gocryptfs exits with an error if we
|
||||||
|
// pass additional data after the password.
|
||||||
|
func TestInitTrailingGarbage(t *testing.T) {
|
||||||
|
table := []struct {
|
||||||
|
pw string
|
||||||
|
closeStdin bool
|
||||||
|
expectSuccess bool
|
||||||
|
}{
|
||||||
|
{"foo\n", false, true},
|
||||||
|
{"foo", true, true},
|
||||||
|
{"foo\n", true, true},
|
||||||
|
{"foo\n\n", false, false},
|
||||||
|
{"foo\nbar", false, false},
|
||||||
|
{"foo\n\n", true, false},
|
||||||
|
{"foo\nbar", true, false},
|
||||||
|
}
|
||||||
|
for _, row := range table {
|
||||||
|
dir, err := ioutil.TempDir(test_helpers.TmpDir, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cmd := exec.Command(test_helpers.GocryptfsBinary, "-q", "-init", "-scryptn=10", dir)
|
||||||
|
childStdin, err := cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
childStdin.Write([]byte(row.pw))
|
||||||
|
if row.closeStdin {
|
||||||
|
childStdin.Close()
|
||||||
|
}
|
||||||
|
err = cmd.Wait()
|
||||||
|
success := (err == nil)
|
||||||
|
if success == true && row.expectSuccess == false {
|
||||||
|
t.Errorf("pw=%q should have failed, but succeeded", row.pw)
|
||||||
|
} else if success == false && row.expectSuccess == true {
|
||||||
|
t.Errorf("pw=%q should have succeeded, but failed", row.pw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user