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

proposal: Go 2: "sensitive" keyword to mark vars / consts containing sensitive data such as crypto keys #21374

Closed
leonklingele opened this issue Aug 9, 2017 · 7 comments
Labels
FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change
Milestone

Comments

@leonklingele
Copy link
Contributor

leonklingele commented Aug 9, 2017

Proposal

As explained in #18645, one is currently missing a way to wipe sensitive material from memory in Go.
Recently a new library (memguard) arose which tries to solve that exact problem and I think something like this should be available in the Go 2 standard library.
(memguard only works with byte slices, this proposal extends that behavior to more (all?) built-in types.)

Reasoning

It's a common practice to erase sensitive data from memory after use and ensure that it is never swapped out to disk. This pretty much sums it up:

RAM was shown to maintain its charge for several seconds after being 
unplugged. Freezing it (e.g. with a compressed air can held upside 
down) extends this to several minutes, maybe even hours. This is 
enough time to plug the memory into another system and dump its 
contents to a file, which can then be analyzed.

Examples

Example 1

Variables and constants which are intended to hold sensitive data such as cryptographic keys can be declared / initialized as follows:

var key sensitive []byte // key marked "sensitive" -> memory is mlock'ed etc.

// Similarly, using :=
key sensitive := []byte("Password")

// The same using const
const pass sensitive = "Password"

As soon as key in the example above goes out of scope it is securely wiped (to be defined) from memory.

Example 2

func main() {
    pass sensitive := "Password"
    printString(pass)
} // pass is wiped

func printString(s string) {
    println(s)
} // s is wiped as it was declared sensitive before being copied-by-value to this function

Example 3

Reassigning variables marked as sensitive should wipe them first

func main() {
    pass sensitive := "Password"
    pass = "Something else" // pass is wiped and then assigned its new value
}

Additions

One should be able to wipe vars declared sensitive before they go out of scope:

wipe(key) // panics if key is not marked "sensitive"
// key is now reset to its zero value: "" for strings, 0 for ints, ..

EDIT:

  • Fixed code indentation
  • Fix typo: mmap -> mlock
@leonklingele leonklingele changed the title proposals: Go 2: "sensitive" keyword to mark vars / consts containing sensitive data such as crypto keys proposal: Go 2: "sensitive" keyword to mark vars / consts containing sensitive data such as crypto keys Aug 9, 2017
@gopherbot gopherbot added this to the Proposal milestone Aug 9, 2017
@bradfitz bradfitz added v2 A language change or incompatible library change LanguageChange labels Aug 9, 2017
@griesemer
Copy link
Contributor

griesemer commented Aug 9, 2017

A few comments:

  1. Constants tend to exist at compile time only, so I'm not sure the sensitive label makes sense there.
  2. This proposal requires new syntax just for this mechanism; also, it's not clear if sensitive is a keyword or something else.
  3. I suspect a lot of interesting code will have sensitive data in heap-allocated objects. Is the assumption that the garbage-collector would wipe sensitive data? (That would be a significant complication).
  4. I don't understand the need for wipe(key): why not simply assign the respective zero value to key and get the same effect.

Overall, I see the appeal of the mechanism, but it seems to me that a library is the better approach than introducing an unproven concept into the language.

@leonklingele
Copy link
Contributor Author

leonklingele commented Aug 9, 2017

Regarding your points:

  1. What do you mean by comments? Why wouldn't sensitive make sense there?

  2. Yes, unreferenced heap memory would need to be wiped by the GC.

  3. pass = "" indeed would do the exact same thing as wipe(pass), the wipe call is just more expressive.

EDIT:
Fix numbering

@griesemer
Copy link
Contributor

griesemer commented Aug 9, 2017

@leonklingele I meant "constants", not "comments", of course. Apologies, my typo. Corrected.

@philhofer
Copy link
Contributor

Language changes aside, it would be useful to have a function in the standard library for zeroing memory that was guaranteed not to be optimized away by dead store elimination. Right now you'd have to resort to something like the old trick of calling memset through a function pointer in a different translation unit.

Asking GC to finalize 'sensitive' data wouldn't be any more reliable than finalizers are today (as in, not very). There would still likely be a large time window during which the data would be 'dead' but still present for an attacker to harvest. Of course, Go is pretty far from a real-time language, so you don't really have any guarantee of timeliness even if you zero the memory explicitly in the code.

@ianlancetaylor
Copy link
Contributor

An explicit Wipe function makes sense to me, though I think it could be in the crypto package as easily as the runtime package.

The sensitive keyword seems somewhat misleading to me. It the variable has a slice type, it is intended to wipe the contents of the slice, not just the value of the variable. But, of course, there may be other references to the slice. So adding sensitive can affect entirely different variables. That seems acceptable for an explicit call to Wipe, but questionable for a keyword. And, since the keyword applies then the variable goes out of scope, it's very nearly equivalent to defer Wipe(key).

@as
Copy link
Contributor

as commented Aug 9, 2017

I disagree about the crypto package. The problem in this proposal is poorly defined and makes assumptions about physical device security. The proposed solution should not be in a package known for making precise security guarantees.

@ianlancetaylor
Copy link
Contributor

As a language design concept, this seems too experimental for Go. It's not clear precisely what it means for Go, and it's not clear that it actually provides any additional security. As mentioned above a few times, this should be addressed as an external package first. As far as I can see, an external package using reflect could do anything that a language keyword could do.

@golang golang locked and limited conversation to collaborators Mar 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests

7 participants