From 4b6b9553c4a2e14fd809754f6bf187957ff3cdfd Mon Sep 17 00:00:00 2001 From: invis-z Date: Tue, 21 Nov 2023 18:12:01 +0000 Subject: Add option to set FIDO2 verificatoin option Add an option to specify user verification options for `fido2-assert -t` Options will be saved to config file Provide same functionality to #705 with simpler implementation Resolve #702 --- Documentation/MANPAGE.md | 10 ++++++++-- cli_args.go | 6 +++++- gocryptfs-xray/xray_main.go | 2 +- init_dir.go | 3 ++- internal/configfile/config_file.go | 7 +++++-- internal/fido2/fido2.go | 18 +++++++++++++----- main.go | 2 +- 7 files changed, 35 insertions(+), 13 deletions(-) diff --git a/Documentation/MANPAGE.md b/Documentation/MANPAGE.md index 8c4af3f..9caa359 100644 --- a/Documentation/MANPAGE.md +++ b/Documentation/MANPAGE.md @@ -482,11 +482,17 @@ for details. #### -fido2 DEVICE_PATH Use a FIDO2 token to initialize and unlock the filesystem. -Use "fido2-token -L" to obtain the FIDO2 token device path. -For linux, "fido2-tools" package is needed. +Use `fido2-token -L` to obtain the FIDO2 token device path. +For linux, **fido2-tools** package is needed. Applies to: all actions that ask for a password. +#### -fido2-assert-option OPTION +Options passed to `fido2-assert` with `-t` option. +This option may be specified multiple times, each time it will add two +arguements `-t` `OPTION` to `fido2-assert`. +See `man fido2-assert` to check supported options. + #### -masterkey string Use an explicit master key specified on the command line or, if the special value "stdin" is used, read the masterkey from stdin, instead of reading diff --git a/cli_args.go b/cli_args.go index 75df4d1..2e9e796 100644 --- a/cli_args.go +++ b/cli_args.go @@ -35,7 +35,10 @@ type argContainer struct { // Mount options with opposites dev, nodev, suid, nosuid, exec, noexec, rw, ro, kernel_cache, acl bool masterkey, mountpoint, cipherdir, cpuprofile, - memprofile, ko, ctlsock, fsname, force_owner, trace, fido2 string + memprofile, ko, ctlsock, fsname, force_owner, trace string + // FIDO2 + fido2 string + fido2_assert_options []string // -extpass, -badname, -passfile can be passed multiple times extpass, badname, passfile []string // For reverse mode, several ways to specify exclusions. All can be specified multiple times. @@ -208,6 +211,7 @@ func parseCliOpts(osArgs []string) (args argContainer) { flagSet.StringVar(&args.force_owner, "force_owner", "", "uid:gid pair to coerce ownership") flagSet.StringVar(&args.trace, "trace", "", "Write execution trace to file") flagSet.StringVar(&args.fido2, "fido2", "", "Protect the masterkey using a FIDO2 token instead of a password") + flagSet.StringArrayVar(&args.fido2_assert_options, "fido2-assert-option", nil, "Options to be passed with `fido2-assert -t`") // Exclusion options flagSet.StringArrayVar(&args.exclude, "e", nil, "Alias for -exclude") diff --git a/gocryptfs-xray/xray_main.go b/gocryptfs-xray/xray_main.go index 2bc98f0..1c491f1 100644 --- a/gocryptfs-xray/xray_main.go +++ b/gocryptfs-xray/xray_main.go @@ -146,7 +146,7 @@ func dumpMasterKey(fn string, fido2Path string) { tlog.Fatal.Printf("Masterkey encrypted using FIDO2 token; need to use the --fido2 option.") os.Exit(exitcodes.Usage) } - pw = fido2.Secret(fido2Path, cf.FIDO2.CredentialID, cf.FIDO2.HMACSalt) + pw = fido2.Secret(fido2Path, cf.FIDO2.AssertOptions, cf.FIDO2.CredentialID, cf.FIDO2.HMACSalt) } else { pw, err = readpassword.Once(nil, nil, "") if err != nil { diff --git a/init_dir.go b/init_dir.go index 738590f..9ba1a01 100644 --- a/init_dir.go +++ b/init_dir.go @@ -84,7 +84,7 @@ func initDir(args *argContainer) { if args.fido2 != "" { fido2CredentialID = fido2.Register(args.fido2, filepath.Base(args.cipherdir)) fido2HmacSalt = cryptocore.RandBytes(32) - password = fido2.Secret(args.fido2, fido2CredentialID, fido2HmacSalt) + password = fido2.Secret(args.fido2, args.fido2_assert_options, fido2CredentialID, fido2HmacSalt) } else { // normal password entry password, err = readpassword.Twice([]string(args.extpass), []string(args.passfile)) @@ -105,6 +105,7 @@ func initDir(args *argContainer) { AESSIV: args.aessiv, Fido2CredentialID: fido2CredentialID, Fido2HmacSalt: fido2HmacSalt, + Fido2AssertOptions: args.fido2_assert_options, DeterministicNames: args.deterministic_names, XChaCha20Poly1305: args.xchacha, LongNameMax: args.longnamemax, diff --git a/internal/configfile/config_file.go b/internal/configfile/config_file.go index 3d59dc5..995a0c8 100644 --- a/internal/configfile/config_file.go +++ b/internal/configfile/config_file.go @@ -33,6 +33,7 @@ type FIDO2Params struct { CredentialID []byte // FIDO2 hmac-secret salt HMACSalt []byte + AssertOptions []string } // ConfFile is the content of a config file. @@ -71,6 +72,7 @@ type CreateArgs struct { AESSIV bool Fido2CredentialID []byte Fido2HmacSalt []byte + Fido2AssertOptions []string DeterministicNames bool XChaCha20Poly1305 bool LongNameMax uint8 @@ -117,8 +119,9 @@ func Create(args *CreateArgs) error { if len(args.Fido2CredentialID) > 0 { cf.setFeatureFlag(FlagFIDO2) cf.FIDO2 = &FIDO2Params{ - CredentialID: args.Fido2CredentialID, - HMACSalt: args.Fido2HmacSalt, + CredentialID: args.Fido2CredentialID, + HMACSalt: args.Fido2HmacSalt, + AssertOptions: args.Fido2AssertOptions, } } // Catch bugs and invalid cli flag combinations early diff --git a/internal/fido2/fido2.go b/internal/fido2/fido2.go index fa6015e..e08e589 100644 --- a/internal/fido2/fido2.go +++ b/internal/fido2/fido2.go @@ -35,13 +35,21 @@ func (fc fidoCommand) String() string { const relyingPartyID = "gocryptfs" -func callFidoCommand(command fidoCommand, device string, stdin []string) ([]string, error) { +func callFidoCommand(command fidoCommand, assertOptions []string, device string, stdin []string) ([]string, error) { var cmd *exec.Cmd switch command { case cred: cmd = exec.Command("fido2-cred", "-M", "-h", device) case assert: - cmd = exec.Command("fido2-assert", "-G", "-h", device) + var args []string + args = append(args, "-G") + args = append(args, "-h") + for i := range assertOptions{ + args = append(args, "-t") + args = append(args, assertOptions[i]) + } + args = append(args, device) + cmd = exec.Command("fido2-assert", args...) } tlog.Debug.Printf("callFidoCommand %s: executing %q with args %q", command, cmd.Path, cmd.Args) cmd.Stderr = os.Stderr @@ -67,7 +75,7 @@ func Register(device string, userName string) (credentialID []byte) { cdh := base64.StdEncoding.EncodeToString(cryptocore.RandBytes(32)) userID := base64.StdEncoding.EncodeToString(cryptocore.RandBytes(32)) stdin := []string{cdh, relyingPartyID, userName, userID} - out, err := callFidoCommand(cred, device, stdin) + out, err := callFidoCommand(cred, nil, device, stdin) if err != nil { tlog.Fatal.Println(err) os.Exit(exitcodes.FIDO2Error) @@ -81,14 +89,14 @@ func Register(device string, userName string) (credentialID []byte) { } // Secret generates a HMAC secret using a FIDO2 token -func Secret(device string, credentialID []byte, salt []byte) (secret []byte) { +func Secret(device string, assertOptions []string, credentialID []byte, salt []byte) (secret []byte) { tlog.Info.Printf("FIDO2 Secret: interact with your device ...") cdh := base64.StdEncoding.EncodeToString(cryptocore.RandBytes(32)) crid := base64.StdEncoding.EncodeToString(credentialID) hmacsalt := base64.StdEncoding.EncodeToString(salt) stdin := []string{cdh, relyingPartyID, crid, hmacsalt} // call fido2-assert - out, err := callFidoCommand(assert, device, stdin) + out, err := callFidoCommand(assert, assertOptions, device, stdin) if err != nil { tlog.Fatal.Println(err) os.Exit(exitcodes.FIDO2Error) diff --git a/main.go b/main.go index 7facf78..bb4c4e2 100644 --- a/main.go +++ b/main.go @@ -43,7 +43,7 @@ func loadConfig(args *argContainer) (masterkey []byte, cf *configfile.ConfFile, tlog.Fatal.Printf("Masterkey encrypted using FIDO2 token; need to use the --fido2 option.") return nil, nil, exitcodes.NewErr("", exitcodes.Usage) } - pw = fido2.Secret(args.fido2, cf.FIDO2.CredentialID, cf.FIDO2.HMACSalt) + pw = fido2.Secret(args.fido2, cf.FIDO2.AssertOptions, cf.FIDO2.CredentialID, cf.FIDO2.HMACSalt) } else { pw, err = readpassword.Once([]string(args.extpass), []string(args.passfile), "") if err != nil { -- cgit v1.2.3