fusefrontend[_reverse]: move crypto init up to caller

Both fusefrontend and fusefrontend_reverse were doing
essentially the same thing, move it into main's
initFuseFrontend.

A side-effect is that we have a reference to cryptocore
in main, which will help with wiping the keys on exit
(https://github.com/rfjakob/gocryptfs/issues/211).
This commit is contained in:
Jakob Unterwurzacher 2018-02-17 16:26:35 +01:00
parent eeed4b4bef
commit 719693ec5d
4 changed files with 32 additions and 48 deletions

View File

@ -2,7 +2,6 @@ package fusefrontend
import ( import (
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
"github.com/rfjakob/gocryptfs/internal/cryptocore"
) )
// Args is a container for arguments that are passed from main() to fusefrontend // Args is a container for arguments that are passed from main() to fusefrontend
@ -10,7 +9,6 @@ type Args struct {
// Cipherdir is the backing storage directory (absolute path). // Cipherdir is the backing storage directory (absolute path).
// For reverse mode, Cipherdir actually contains *plaintext* files. // For reverse mode, Cipherdir actually contains *plaintext* files.
Cipherdir string Cipherdir string
CryptoBackend cryptocore.AEADTypeEnum
PlaintextNames bool PlaintextNames bool
LongNames bool LongNames bool
// Should we chown a file after it has been created? // Should we chown a file after it has been created?
@ -26,15 +24,8 @@ type Args struct {
// location. If it is false, reverse mode maps ".gocryptfs.reverse.conf" // location. If it is false, reverse mode maps ".gocryptfs.reverse.conf"
// to "gocryptfs.conf" in the plaintext dir. // to "gocryptfs.conf" in the plaintext dir.
ConfigCustom bool ConfigCustom bool
// Raw64 is true when RawURLEncoding (without padding) should be used for
// file names.
// Corresponds to the Raw64 feature flag introduced in gocryptfs v1.2.
Raw64 bool
// NoPrealloc disables automatic preallocation before writing // NoPrealloc disables automatic preallocation before writing
NoPrealloc bool NoPrealloc bool
// Use HKDF key derivation.
// Corresponds to the HKDF feature flag introduced in gocryptfs v1.3.
HKDF bool
// Try to serialize read operations, "-serialize_reads" // Try to serialize read operations, "-serialize_reads"
SerializeReads bool SerializeReads bool
// Force decode even if integrity check fails (openSSL only) // Force decode even if integrity check fails (openSSL only)

View File

@ -17,7 +17,6 @@ import (
"github.com/hanwen/go-fuse/fuse/pathfs" "github.com/hanwen/go-fuse/fuse/pathfs"
"github.com/rfjakob/gocryptfs/internal/contentenc" "github.com/rfjakob/gocryptfs/internal/contentenc"
"github.com/rfjakob/gocryptfs/internal/cryptocore"
"github.com/rfjakob/gocryptfs/internal/nametransform" "github.com/rfjakob/gocryptfs/internal/nametransform"
"github.com/rfjakob/gocryptfs/internal/serialize_reads" "github.com/rfjakob/gocryptfs/internal/serialize_reads"
"github.com/rfjakob/gocryptfs/internal/syscallcompat" "github.com/rfjakob/gocryptfs/internal/syscallcompat"
@ -44,20 +43,15 @@ type FS struct {
var _ pathfs.FileSystem = &FS{} // Verify that interface is implemented. var _ pathfs.FileSystem = &FS{} // Verify that interface is implemented.
// NewFS returns a new encrypted FUSE overlay filesystem. // NewFS returns a new encrypted FUSE overlay filesystem.
func NewFS(masterkey []byte, args Args) *FS { func NewFS(args Args, c *contentenc.ContentEnc, n *nametransform.NameTransform) *FS {
cryptoCore := cryptocore.New(masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF, args.ForceDecode)
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS, args.ForceDecode)
nameTransform := nametransform.New(cryptoCore.EMECipher, args.LongNames, args.Raw64)
if args.SerializeReads { if args.SerializeReads {
serialize_reads.InitSerializer() serialize_reads.InitSerializer()
} }
return &FS{ return &FS{
FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir), FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir),
args: args, args: args,
nameTransform: nameTransform, nameTransform: n,
contentEnc: contentEnc, contentEnc: c,
} }
} }

View File

@ -2,7 +2,6 @@ package fusefrontend_reverse
import ( import (
"fmt" "fmt"
"log"
"path/filepath" "path/filepath"
"syscall" "syscall"
@ -42,22 +41,15 @@ var _ pathfs.FileSystem = &ReverseFS{}
// NewFS returns an encrypted FUSE overlay filesystem. // NewFS returns an encrypted FUSE overlay filesystem.
// In this case (reverse mode) the backing directory is plain-text and // In this case (reverse mode) the backing directory is plain-text and
// ReverseFS provides an encrypted view. // ReverseFS provides an encrypted view.
func NewFS(masterkey []byte, args fusefrontend.Args) *ReverseFS { func NewFS(args fusefrontend.Args, c *contentenc.ContentEnc, n *nametransform.NameTransform) *ReverseFS {
if args.CryptoBackend != cryptocore.BackendAESSIV {
log.Panic("reverse mode must use AES-SIV, everything else is insecure")
}
initLongnameCache() initLongnameCache()
cryptoCore := cryptocore.New(masterkey, args.CryptoBackend, contentenc.DefaultIVBits, args.HKDF, false)
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS, false)
nameTransform := nametransform.New(cryptoCore.EMECipher, args.LongNames, args.Raw64)
return &ReverseFS{ return &ReverseFS{
// pathfs.defaultFileSystem returns ENOSYS for all operations // pathfs.defaultFileSystem returns ENOSYS for all operations
FileSystem: pathfs.NewDefaultFileSystem(), FileSystem: pathfs.NewDefaultFileSystem(),
loopbackfs: pathfs.NewLoopbackFileSystem(args.Cipherdir), loopbackfs: pathfs.NewLoopbackFileSystem(args.Cipherdir),
args: args, args: args,
nameTransform: nameTransform, nameTransform: n,
contentEnc: contentEnc, contentEnc: c,
} }
} }

View File

@ -3,6 +3,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"log/syslog" "log/syslog"
"net" "net"
"os" "os"
@ -21,11 +22,13 @@ import (
"github.com/hanwen/go-fuse/fuse/pathfs" "github.com/hanwen/go-fuse/fuse/pathfs"
"github.com/rfjakob/gocryptfs/internal/configfile" "github.com/rfjakob/gocryptfs/internal/configfile"
"github.com/rfjakob/gocryptfs/internal/contentenc"
"github.com/rfjakob/gocryptfs/internal/cryptocore" "github.com/rfjakob/gocryptfs/internal/cryptocore"
"github.com/rfjakob/gocryptfs/internal/ctlsock" "github.com/rfjakob/gocryptfs/internal/ctlsock"
"github.com/rfjakob/gocryptfs/internal/exitcodes" "github.com/rfjakob/gocryptfs/internal/exitcodes"
"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/nametransform"
"github.com/rfjakob/gocryptfs/internal/readpassword" "github.com/rfjakob/gocryptfs/internal/readpassword"
"github.com/rfjakob/gocryptfs/internal/tlog" "github.com/rfjakob/gocryptfs/internal/tlog"
) )
@ -182,6 +185,13 @@ func setOpenFileLimit() {
} }
} }
// ctlsockFs satisfies both the pathfs.FileSystem and the ctlsock.Interface
// interfaces
type ctlsockFs interface {
pathfs.FileSystem
ctlsock.Interface
}
// initFuseFrontend - initialize gocryptfs/fusefrontend // initFuseFrontend - initialize gocryptfs/fusefrontend
// Calls os.Exit on errors // Calls os.Exit on errors
func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile.ConfFile) *fuse.Server { func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile.ConfFile) *fuse.Server {
@ -203,11 +213,8 @@ func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile
Cipherdir: args.cipherdir, Cipherdir: args.cipherdir,
PlaintextNames: args.plaintextnames, PlaintextNames: args.plaintextnames,
LongNames: args.longnames, LongNames: args.longnames,
CryptoBackend: cryptoBackend,
ConfigCustom: args._configCustom, ConfigCustom: args._configCustom,
Raw64: args.raw64,
NoPrealloc: args.noprealloc, NoPrealloc: args.noprealloc,
HKDF: args.hkdf,
SerializeReads: args.serialize_reads, SerializeReads: args.serialize_reads,
ForceDecode: args.forcedecode, ForceDecode: args.forcedecode,
ForceOwner: args._forceOwner, ForceOwner: args._forceOwner,
@ -216,10 +223,10 @@ func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile
if confFile != nil { if confFile != nil {
// Settings from the config file override command line args // Settings from the config file override command line args
frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(configfile.FlagPlaintextNames) frontendArgs.PlaintextNames = confFile.IsFeatureFlagSet(configfile.FlagPlaintextNames)
frontendArgs.Raw64 = confFile.IsFeatureFlagSet(configfile.FlagRaw64) args.raw64 = confFile.IsFeatureFlagSet(configfile.FlagRaw64)
frontendArgs.HKDF = confFile.IsFeatureFlagSet(configfile.FlagHKDF) args.hkdf = confFile.IsFeatureFlagSet(configfile.FlagHKDF)
if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) { if confFile.IsFeatureFlagSet(configfile.FlagAESSIV) {
frontendArgs.CryptoBackend = cryptocore.BackendAESSIV cryptoBackend = cryptocore.BackendAESSIV
} else if args.reverse { } else if args.reverse {
tlog.Fatal.Printf("AES-SIV is required by reverse mode, but not enabled in the config file") tlog.Fatal.Printf("AES-SIV is required by reverse mode, but not enabled in the config file")
os.Exit(exitcodes.Usage) os.Exit(exitcodes.Usage)
@ -232,8 +239,6 @@ func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile
} }
jsonBytes, _ := json.MarshalIndent(frontendArgs, "", "\t") jsonBytes, _ := json.MarshalIndent(frontendArgs, "", "\t")
tlog.Debug.Printf("frontendArgs: %s", string(jsonBytes)) tlog.Debug.Printf("frontendArgs: %s", string(jsonBytes))
var finalFs pathfs.FileSystem
var ctlSockBackend ctlsock.Interface
// pathFsOpts are passed into go-fuse/pathfs // pathFsOpts are passed into go-fuse/pathfs
pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true} pathFsOpts := &pathfs.PathNodeFsOptions{ClientInodes: true}
if args.sharedstorage { if args.sharedstorage {
@ -242,21 +247,23 @@ func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile
// https://github.com/rfjakob/gocryptfs/issues/156 // https://github.com/rfjakob/gocryptfs/issues/156
pathFsOpts.ClientInodes = false pathFsOpts.ClientInodes = false
} }
// Init crypto backend
cCore := cryptocore.New(masterkey, cryptoBackend, contentenc.DefaultIVBits, args.hkdf, args.forcedecode)
cEnc := contentenc.New(cCore, contentenc.DefaultBS, args.forcedecode)
nameTransform := nametransform.New(cCore.EMECipher, frontendArgs.LongNames, args.raw64)
// Spawn fusefrontend
var fs ctlsockFs
if args.reverse { if args.reverse {
// The dance with the intermediate variables is because we need to if cryptoBackend != cryptocore.BackendAESSIV {
// cast the FS into pathfs.FileSystem *and* ctlsock.Interface. This log.Panic("reverse mode must use AES-SIV, everything else is insecure")
// avoids using interface{}. }
fs := fusefrontend_reverse.NewFS(masterkey, frontendArgs) fs = fusefrontend_reverse.NewFS(frontendArgs, cEnc, nameTransform)
finalFs = fs
ctlSockBackend = fs
// Reverse mode is read-only, so we don't need a working link(). // Reverse mode is read-only, so we don't need a working link().
// Disable hard link tracking to avoid strange breakage on duplicate // Disable hard link tracking to avoid strange breakage on duplicate
// inode numbers ( https://github.com/rfjakob/gocryptfs/issues/149 ). // inode numbers ( https://github.com/rfjakob/gocryptfs/issues/149 ).
pathFsOpts.ClientInodes = false pathFsOpts.ClientInodes = false
} else { } else {
fs := fusefrontend.NewFS(masterkey, frontendArgs) fs = fusefrontend.NewFS(frontendArgs, cEnc, nameTransform)
finalFs = fs
ctlSockBackend = fs
} }
// fusefrontend / fusefrontend_reverse have initialized their crypto with // fusefrontend / fusefrontend_reverse have initialized their crypto with
// derived keys (HKDF), we can purge the master key from memory. // derived keys (HKDF), we can purge the master key from memory.
@ -266,9 +273,9 @@ func initFuseFrontend(masterkey []byte, args *argContainer, confFile *configfile
// We have opened the socket early so that we cannot fail here after // We have opened the socket early so that we cannot fail here after
// asking the user for the password // asking the user for the password
if args._ctlsockFd != nil { if args._ctlsockFd != nil {
go ctlsock.Serve(args._ctlsockFd, ctlSockBackend) go ctlsock.Serve(args._ctlsockFd, fs)
} }
pathFs := pathfs.NewPathNodeFs(finalFs, pathFsOpts) pathFs := pathfs.NewPathNodeFs(fs, pathFsOpts)
var fuseOpts *nodefs.Options var fuseOpts *nodefs.Options
if args.sharedstorage { if args.sharedstorage {
// sharedstorage mode sets all cache timeouts to zero so changes to the // sharedstorage mode sets all cache timeouts to zero so changes to the