Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insufficient protection of secret information? #211

Closed
yahesh opened this issue Feb 13, 2018 · 5 comments
Closed

Insufficient protection of secret information? #211

yahesh opened this issue Feb 13, 2018 · 5 comments

Comments

@yahesh
Copy link
Contributor

yahesh commented Feb 13, 2018

I sifted through the code of gocryptfs to find out how the secrets are handled that the tool needs to work properly. However, unfortunately I didn't find all the anwers I were looking for.

Protection of the masterkey

I have seen that the masterkey is actually nulled when it is not needed anymore as can be seen in mount.go. However, when OpenSSL is used as a backend, a stupidgcm structure is created in cryptocore.go that contains a copy of the masterkey. The creation of the masterkey copy is even described in a comment. But this copy of the masterkey does not seem to be nulled upon termination.

Furthermore, the masterkey is used in the changePassword() function in main.go but it is never nulled.

Protection of derived keys

Deriving cryptographic keys seems to mainly happen in the cryptocore which are then passed back as a structure in cryptocore.go. However, all those keys never seem to be nulled after use.

Protection of the password

Reading of the passwords seams to happen in read.go which are then returned as a string. The password is passed to a call of configfile.LoadConfigFile() in main.go. However, the pw variable never seems to be nulled.

Furthermore, the password is used in the changePassword() function in main.go but it is never nulled.

Program Flow

If I understand the program flow correctly, main.go calls doMount().

doMount() calls loadConfig() in main.go which is the function that actually reads the password.

doMount() also calls initFuseFrontend(). Within that function either fusefrontend.New() in fs.go or fusefrontend_reverse.New() in rfs.go is called (depending on whether the forward or reverse mode is used). These now call cryptocore.New() in cryptocore.go where the actual keys are derived from the masterkey.

At the end, initFuseFrontend() returns a Fuse server. doMount() calls the Fuse server's srv.Serve() method that handles the actual file system actions until the kernel encounters an unmount.

When that happens, doMount() returns 0 and the main() function just quits.

Expectations

I'd expect that variables that hold secret information (password, masterkey, derived keys) are properly nulled when they are not needed anymore - a process which is actually done for one occurence of a secret information (namely the masterkey). In cases where this is difficult to achieve because a data type is used that is difficult to handle properly (e.g. because it is passed by value so that hidden copies are created), an alternative data type like []byte should be used that's easier to handle.

changePassword()

changePassword() in main.go should null the masterkey and the newPw variable

loadConfig()

loadConfig() in main.go should null the pw variable

readpassword.Twice()

readpassword.Twice() in read.go should null the p2 variable

doMount()

doMount() should null the derived keys which are encapsulated in the cryptocore structure which is encapsulated in the ContentEnc structure which in turn is encapsulated in the FS/ReverseFS structure which then again is encapsulated in the PathNodeFs structure (of the go-fuse library) which might be encapsulated in some other structure down the line.

@rfjakob
Copy link
Owner

rfjakob commented Feb 14, 2018

Zeroing memory is somewhat unreliable in garbage-collected languages ( see https://cryptolosophy.org/memory-security-go/ ), but I agree that we could overwrite more things than we do now.

About the derived keys, you are aware that the encryption functions must have an internal copy?

@yahesh
Copy link
Contributor Author

yahesh commented Feb 14, 2018 via email

@yahesh
Copy link
Contributor Author

yahesh commented Feb 14, 2018 via email

@rfjakob
Copy link
Owner

rfjakob commented Feb 14, 2018

Yes i think we can overwrite the keys. The library will still hold some key equivalent in memory, but i guess it's still an improvement.

rfjakob added a commit that referenced this issue Feb 17, 2018
Not bulletproof due to possible GC copies, but
still raises to bar for extracting the key.

#211
rfjakob added a commit that referenced this issue Feb 17, 2018
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
(#211).
rfjakob added a commit that referenced this issue Feb 18, 2018
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
(#211).
rfjakob added a commit that referenced this issue Feb 18, 2018
Raise the bar for recovering keys from memory.

#211
rfjakob added a commit that referenced this issue Feb 18, 2018
Raise the bar for recovering keys from memory.

#211
rfjakob added a commit that referenced this issue Feb 18, 2018
As soon as we don't need them anymore, overwrite
keys with zeros and make sure they run out of scope
so we don't create a risk of inadvertedly using all-zero
keys for encryption.

#211
rfjakob added a commit that referenced this issue Feb 18, 2018
As soon as we don't need them anymore, overwrite
keys with zeros. Make sure they run out of scope
so we don't create a risk of inadvertedly using
all-zero keys for encryption.

#211
rfjakob added a commit that referenced this issue Feb 18, 2018
This will allows us to overwrite the password
with zeros once we are done with it.

#211
rfjakob added a commit that referenced this issue Feb 18, 2018
Zero the HKDF-derived keys when we don't need them
anymore, and let the variable run of of scope.

#211
@rfjakob
Copy link
Owner

rfjakob commented Feb 18, 2018

Thanks for your detailed report.

I believe I got them all. Keys and password are wiped once they are not longer needed, and the actual encryption keys are wiped on unmount via Wipe():

func (c *CryptoCore) Wipe() {
called from
defer wipeKeys()

Please reopen if you find I missed something!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants