Zeroization of sensitive data in Erlang

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Zeroization of sensitive data in Erlang

Amit K
Hi all,

Concerning the security practice of Zeroizing sensitive data from memory after you're finished with it, such as Cryptographic keys, passwords, etc, I wanted to ask if any of you ever had to implement such a thing in Erlang, and if so, how? :) 

Also note that often this is a requirement that you must fulfill if you want your product to pass a security standard evaluation such as the "Common Criteria" one (As an example requirement see FCS_CKM_EXT.4 here: https://www.commoncriteriaportal.org/files/ppfiles/pp_nd_v1.0.pdf).

The problem of course is that in Erlang (and I suppose - FP in general) once a variable gets assigned, you are not allowed to change its value, and in particular of course overwrite it with zero bytes. 

One option I thought about is doing it with a NIF, but from my understanding a NIF isn't supposed to change its input values, it should treat them as constants, which understandable as well (basic FP language property). 

Any feedback can be helpful :)

Regards,

Amit






Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Dániel Szoboszlay
Hi Amit,

A NIF could use a resource object to implement a zeroable memory location. The Erlang program will only see a handle to the resource, which is immutable. But the contents of the object can be changed by the NIF (it's better explained in the docs). So you could create an API that looks like this for the Erlang program:

Handle = create_secret(Some, Input, Values),
ok = use_secret(Handle),
ok = destroy_secret(Handle), % The NIF zeroes out the memory in the resource object
{error, destroyed} = use_secret(Handle). % The secret is no more at this point

The big problem is that your secret shall never leave the native library. E.g. you cannot hide a cryptographic key behind a zeroable resource object and then pass it to the crypto library. As soon as you convert it into an Erlang term, it is copied onto the non-zeroed stack or heap or a process. Considering this, you may just as well use a port program to hold and work with the secret outside of the Erlang VM.

Probably the only real solution within the VM would be to patch the GC to zero any reclaimed memory. Or maybe not even the GC, but the memory allocators, in case a secret is copied to some non-GC-d memory area, such as an ETS table.

Cheers,
Daniel

On Sat, 26 Oct 2019 at 22:39, Amit K <[hidden email]> wrote:
Hi all,

Concerning the security practice of Zeroizing sensitive data from memory after you're finished with it, such as Cryptographic keys, passwords, etc, I wanted to ask if any of you ever had to implement such a thing in Erlang, and if so, how? :) 

Also note that often this is a requirement that you must fulfill if you want your product to pass a security standard evaluation such as the "Common Criteria" one (As an example requirement see FCS_CKM_EXT.4 here: https://www.commoncriteriaportal.org/files/ppfiles/pp_nd_v1.0.pdf).

The problem of course is that in Erlang (and I suppose - FP in general) once a variable gets assigned, you are not allowed to change its value, and in particular of course overwrite it with zero bytes. 

One option I thought about is doing it with a NIF, but from my understanding a NIF isn't supposed to change its input values, it should treat them as constants, which understandable as well (basic FP language property). 

Any feedback can be helpful :)

Regards,

Amit






Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Amit K
Hi Daniel,

Good to know about that workaround, thank you. However as you already pointed out, I really do want to be able to handle such "sensitive" variables in Erlang code and use the standard "crypto" library of the OTP. 

With regards to GC - that's a great direction I think, and perhaps a more finer grained approach would be to add a new "sensitive" flag for typed variables that the GC can recognize. Then only those variables get zeroized when the GC runs. 
Would probably be better for performance than always zeroizing everything that we free...

BTW - so far I didn't find any FP language that can do something like that, and please correct me if I'm wrong. It would be cool if Erlang would be the first to the gold here (again!) :)

On Sun, Oct 27, 2019 at 1:42 AM Dániel Szoboszlay <[hidden email]> wrote:
Hi Amit,

A NIF could use a resource object to implement a zeroable memory location. The Erlang program will only see a handle to the resource, which is immutable. But the contents of the object can be changed by the NIF (it's better explained in the docs). So you could create an API that looks like this for the Erlang program:

Handle = create_secret(Some, Input, Values),
ok = use_secret(Handle),
ok = destroy_secret(Handle), % The NIF zeroes out the memory in the resource object
{error, destroyed} = use_secret(Handle). % The secret is no more at this point

The big problem is that your secret shall never leave the native library. E.g. you cannot hide a cryptographic key behind a zeroable resource object and then pass it to the crypto library. As soon as you convert it into an Erlang term, it is copied onto the non-zeroed stack or heap or a process. Considering this, you may just as well use a port program to hold and work with the secret outside of the Erlang VM.

Probably the only real solution within the VM would be to patch the GC to zero any reclaimed memory. Or maybe not even the GC, but the memory allocators, in case a secret is copied to some non-GC-d memory area, such as an ETS table.

Cheers,
Daniel

On Sat, 26 Oct 2019 at 22:39, Amit K <[hidden email]> wrote:
Hi all,

Concerning the security practice of Zeroizing sensitive data from memory after you're finished with it, such as Cryptographic keys, passwords, etc, I wanted to ask if any of you ever had to implement such a thing in Erlang, and if so, how? :) 

Also note that often this is a requirement that you must fulfill if you want your product to pass a security standard evaluation such as the "Common Criteria" one (As an example requirement see FCS_CKM_EXT.4 here: https://www.commoncriteriaportal.org/files/ppfiles/pp_nd_v1.0.pdf).

The problem of course is that in Erlang (and I suppose - FP in general) once a variable gets assigned, you are not allowed to change its value, and in particular of course overwrite it with zero bytes. 

One option I thought about is doing it with a NIF, but from my understanding a NIF isn't supposed to change its input values, it should treat them as constants, which understandable as well (basic FP language property). 

Any feedback can be helpful :)

Regards,

Amit






Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Bob Ippolito
With regard to other FP languages, Haskell has a crypto library called raaz that makes an effort to ensure that sensitive memory gets cleared eagerly. Other Haskell libraries might have similar functionality, it's a bit easier to do with GHC than with the Erlang VM for various reasons.


On Sat, Oct 26, 2019 at 4:02 PM Amit K <[hidden email]> wrote:
Hi Daniel,

Good to know about that workaround, thank you. However as you already pointed out, I really do want to be able to handle such "sensitive" variables in Erlang code and use the standard "crypto" library of the OTP. 

With regards to GC - that's a great direction I think, and perhaps a more finer grained approach would be to add a new "sensitive" flag for typed variables that the GC can recognize. Then only those variables get zeroized when the GC runs. 
Would probably be better for performance than always zeroizing everything that we free...

BTW - so far I didn't find any FP language that can do something like that, and please correct me if I'm wrong. It would be cool if Erlang would be the first to the gold here (again!) :)

On Sun, Oct 27, 2019 at 1:42 AM Dániel Szoboszlay <[hidden email]> wrote:
Hi Amit,

A NIF could use a resource object to implement a zeroable memory location. The Erlang program will only see a handle to the resource, which is immutable. But the contents of the object can be changed by the NIF (it's better explained in the docs). So you could create an API that looks like this for the Erlang program:

Handle = create_secret(Some, Input, Values),
ok = use_secret(Handle),
ok = destroy_secret(Handle), % The NIF zeroes out the memory in the resource object
{error, destroyed} = use_secret(Handle). % The secret is no more at this point

The big problem is that your secret shall never leave the native library. E.g. you cannot hide a cryptographic key behind a zeroable resource object and then pass it to the crypto library. As soon as you convert it into an Erlang term, it is copied onto the non-zeroed stack or heap or a process. Considering this, you may just as well use a port program to hold and work with the secret outside of the Erlang VM.

Probably the only real solution within the VM would be to patch the GC to zero any reclaimed memory. Or maybe not even the GC, but the memory allocators, in case a secret is copied to some non-GC-d memory area, such as an ETS table.

Cheers,
Daniel

On Sat, 26 Oct 2019 at 22:39, Amit K <[hidden email]> wrote:
Hi all,

Concerning the security practice of Zeroizing sensitive data from memory after you're finished with it, such as Cryptographic keys, passwords, etc, I wanted to ask if any of you ever had to implement such a thing in Erlang, and if so, how? :) 

Also note that often this is a requirement that you must fulfill if you want your product to pass a security standard evaluation such as the "Common Criteria" one (As an example requirement see FCS_CKM_EXT.4 here: https://www.commoncriteriaportal.org/files/ppfiles/pp_nd_v1.0.pdf).

The problem of course is that in Erlang (and I suppose - FP in general) once a variable gets assigned, you are not allowed to change its value, and in particular of course overwrite it with zero bytes. 

One option I thought about is doing it with a NIF, but from my understanding a NIF isn't supposed to change its input values, it should treat them as constants, which understandable as well (basic FP language property). 

Any feedback can be helpful :)

Regards,

Amit






Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Amit K
Thank you Bob,
Note though that the "gotcha" in the documentation that says: "...there can be strange situations in multi-threaded application where the memory is not wiped out..." is why I think ideally something like that should be built into the language and not provided as an external package, which at best will work only as long the run-time obeys certain rules which are bound to change over time, and at worst will work "most of the time" :) (as this is not acceptable in real security applications that need to go through security certifications). 

On Sun, Oct 27, 2019 at 2:16 AM Bob Ippolito <[hidden email]> wrote:
With regard to other FP languages, Haskell has a crypto library called raaz that makes an effort to ensure that sensitive memory gets cleared eagerly. Other Haskell libraries might have similar functionality, it's a bit easier to do with GHC than with the Erlang VM for various reasons.


On Sat, Oct 26, 2019 at 4:02 PM Amit K <[hidden email]> wrote:
Hi Daniel,

Good to know about that workaround, thank you. However as you already pointed out, I really do want to be able to handle such "sensitive" variables in Erlang code and use the standard "crypto" library of the OTP. 

With regards to GC - that's a great direction I think, and perhaps a more finer grained approach would be to add a new "sensitive" flag for typed variables that the GC can recognize. Then only those variables get zeroized when the GC runs. 
Would probably be better for performance than always zeroizing everything that we free...

BTW - so far I didn't find any FP language that can do something like that, and please correct me if I'm wrong. It would be cool if Erlang would be the first to the gold here (again!) :)

On Sun, Oct 27, 2019 at 1:42 AM Dániel Szoboszlay <[hidden email]> wrote:
Hi Amit,

A NIF could use a resource object to implement a zeroable memory location. The Erlang program will only see a handle to the resource, which is immutable. But the contents of the object can be changed by the NIF (it's better explained in the docs). So you could create an API that looks like this for the Erlang program:

Handle = create_secret(Some, Input, Values),
ok = use_secret(Handle),
ok = destroy_secret(Handle), % The NIF zeroes out the memory in the resource object
{error, destroyed} = use_secret(Handle). % The secret is no more at this point

The big problem is that your secret shall never leave the native library. E.g. you cannot hide a cryptographic key behind a zeroable resource object and then pass it to the crypto library. As soon as you convert it into an Erlang term, it is copied onto the non-zeroed stack or heap or a process. Considering this, you may just as well use a port program to hold and work with the secret outside of the Erlang VM.

Probably the only real solution within the VM would be to patch the GC to zero any reclaimed memory. Or maybe not even the GC, but the memory allocators, in case a secret is copied to some non-GC-d memory area, such as an ETS table.

Cheers,
Daniel

On Sat, 26 Oct 2019 at 22:39, Amit K <[hidden email]> wrote:
Hi all,

Concerning the security practice of Zeroizing sensitive data from memory after you're finished with it, such as Cryptographic keys, passwords, etc, I wanted to ask if any of you ever had to implement such a thing in Erlang, and if so, how? :) 

Also note that often this is a requirement that you must fulfill if you want your product to pass a security standard evaluation such as the "Common Criteria" one (As an example requirement see FCS_CKM_EXT.4 here: https://www.commoncriteriaportal.org/files/ppfiles/pp_nd_v1.0.pdf).

The problem of course is that in Erlang (and I suppose - FP in general) once a variable gets assigned, you are not allowed to change its value, and in particular of course overwrite it with zero bytes. 

One option I thought about is doing it with a NIF, but from my understanding a NIF isn't supposed to change its input values, it should treat them as constants, which understandable as well (basic FP language property). 

Any feedback can be helpful :)

Regards,

Amit






Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Bob Ippolito
Sure, that’s why I said it makes an effort. Most languages with threads (or even certain uses of signals) can have similar edge cases. Having the edge cases documented such that they can be avoided is likely the best you’re going to find anywhere.

On Sat, Oct 26, 2019 at 17:34 Amit K <[hidden email]> wrote:
Thank you Bob,
Note though that the "gotcha" in the documentation that says: "...there can be strange situations in multi-threaded application where the memory is not wiped out..." is why I think ideally something like that should be built into the language and not provided as an external package, which at best will work only as long the run-time obeys certain rules which are bound to change over time, and at worst will work "most of the time" :) (as this is not acceptable in real security applications that need to go through security certifications). 

On Sun, Oct 27, 2019 at 2:16 AM Bob Ippolito <[hidden email]> wrote:
With regard to other FP languages, Haskell has a crypto library called raaz that makes an effort to ensure that sensitive memory gets cleared eagerly. Other Haskell libraries might have similar functionality, it's a bit easier to do with GHC than with the Erlang VM for various reasons.


On Sat, Oct 26, 2019 at 4:02 PM Amit K <[hidden email]> wrote:
Hi Daniel,

Good to know about that workaround, thank you. However as you already pointed out, I really do want to be able to handle such "sensitive" variables in Erlang code and use the standard "crypto" library of the OTP. 

With regards to GC - that's a great direction I think, and perhaps a more finer grained approach would be to add a new "sensitive" flag for typed variables that the GC can recognize. Then only those variables get zeroized when the GC runs. 
Would probably be better for performance than always zeroizing everything that we free...

BTW - so far I didn't find any FP language that can do something like that, and please correct me if I'm wrong. It would be cool if Erlang would be the first to the gold here (again!) :)

On Sun, Oct 27, 2019 at 1:42 AM Dániel Szoboszlay <[hidden email]> wrote:
Hi Amit,

A NIF could use a resource object to implement a zeroable memory location. The Erlang program will only see a handle to the resource, which is immutable. But the contents of the object can be changed by the NIF (it's better explained in the docs). So you could create an API that looks like this for the Erlang program:

Handle = create_secret(Some, Input, Values),
ok = use_secret(Handle),
ok = destroy_secret(Handle), % The NIF zeroes out the memory in the resource object
{error, destroyed} = use_secret(Handle). % The secret is no more at this point

The big problem is that your secret shall never leave the native library. E.g. you cannot hide a cryptographic key behind a zeroable resource object and then pass it to the crypto library. As soon as you convert it into an Erlang term, it is copied onto the non-zeroed stack or heap or a process. Considering this, you may just as well use a port program to hold and work with the secret outside of the Erlang VM.

Probably the only real solution within the VM would be to patch the GC to zero any reclaimed memory. Or maybe not even the GC, but the memory allocators, in case a secret is copied to some non-GC-d memory area, such as an ETS table.

Cheers,
Daniel

On Sat, 26 Oct 2019 at 22:39, Amit K <[hidden email]> wrote:
Hi all,

Concerning the security practice of Zeroizing sensitive data from memory after you're finished with it, such as Cryptographic keys, passwords, etc, I wanted to ask if any of you ever had to implement such a thing in Erlang, and if so, how? :) 

Also note that often this is a requirement that you must fulfill if you want your product to pass a security standard evaluation such as the "Common Criteria" one (As an example requirement see FCS_CKM_EXT.4 here: https://www.commoncriteriaportal.org/files/ppfiles/pp_nd_v1.0.pdf).

The problem of course is that in Erlang (and I suppose - FP in general) once a variable gets assigned, you are not allowed to change its value, and in particular of course overwrite it with zero bytes. 

One option I thought about is doing it with a NIF, but from my understanding a NIF isn't supposed to change its input values, it should treat them as constants, which understandable as well (basic FP language property). 

Any feedback can be helpful :)

Regards,

Amit






Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

PAILLEAU Eric
In reply to this post by Amit K

Hi,

Note that there is a sensitive flag for processes.

Would be neat that variables used by sensitive processes get their memory zeroed.


Envoyé depuis mon mobile



---- Amit K a écrit ----

Hi Daniel,

Good to know about that workaround, thank you. However as you already pointed out, I really do want to be able to handle such "sensitive" variables in Erlang code and use the standard "crypto" library of the OTP. 

With regards to GC - that's a great direction I think, and perhaps a more finer grained approach would be to add a new "sensitive" flag for typed variables that the GC can recognize. Then only those variables get zeroized when the GC runs. 
Would probably be better for performance than always zeroizing everything that we free...

BTW - so far I didn't find any FP language that can do something like that, and please correct me if I'm wrong. It would be cool if Erlang would be the first to the gold here (again!) :)

On Sun, Oct 27, 2019 at 1:42 AM Dániel Szoboszlay <[hidden email]> wrote:
Hi Amit,

A NIF could use a resource object to implement a zeroable memory location. The Erlang program will only see a handle to the resource, which is immutable. But the contents of the object can be changed by the NIF (it's better explained in the docs). So you could create an API that looks like this for the Erlang program:

Handle = create_secret(Some, Input, Values),
ok = use_secret(Handle),
ok = destroy_secret(Handle), % The NIF zeroes out the memory in the resource object
{error, destroyed} = use_secret(Handle). % The secret is no more at this point

The big problem is that your secret shall never leave the native library. E.g. you cannot hide a cryptographic key behind a zeroable resource object and then pass it to the crypto library. As soon as you convert it into an Erlang term, it is copied onto the non-zeroed stack or heap or a process. Considering this, you may just as well use a port program to hold and work with the secret outside of the Erlang VM.

Probably the only real solution within the VM would be to patch the GC to zero any reclaimed memory. Or maybe not even the GC, but the memory allocators, in case a secret is copied to some non-GC-d memory area, such as an ETS table.

Cheers,
Daniel

On Sat, 26 Oct 2019 at 22:39, Amit K <[hidden email]> wrote:
Hi all,

Concerning the security practice of Zeroizing sensitive data from memory after you're finished with it, such as Cryptographic keys, passwords, etc, I wanted to ask if any of you ever had to implement such a thing in Erlang, and if so, how? :) 

Also note that often this is a requirement that you must fulfill if you want your product to pass a security standard evaluation such as the "Common Criteria" one (As an example requirement see FCS_CKM_EXT.4 here: https://www.commoncriteriaportal.org/files/ppfiles/pp_nd_v1.0.pdf).

The problem of course is that in Erlang (and I suppose - FP in general) once a variable gets assigned, you are not allowed to change its value, and in particular of course overwrite it with zero bytes. 

One option I thought about is doing it with a NIF, but from my understanding a NIF isn't supposed to change its input values, it should treat them as constants, which understandable as well (basic FP language property). 

Any feedback can be helpful :)

Regards,

Amit






Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Amit K
Hi Eric,
I like your suggestion, but would it be a reasonable performance overhead, especially for those who are already using the sensitive flag for certain processes? If the answer is likely yes I may well try to implement this and possibly create a PR for that :) 

On Sun, Oct 27, 2019 at 9:21 AM Eric Pailleau <[hidden email]> wrote:

Hi,

Note that there is a sensitive flag for processes.

Would be neat that variables used by sensitive processes get their memory zeroed.


Envoyé depuis mon mobile



---- Amit K a écrit ----

Hi Daniel,

Good to know about that workaround, thank you. However as you already pointed out, I really do want to be able to handle such "sensitive" variables in Erlang code and use the standard "crypto" library of the OTP. 

With regards to GC - that's a great direction I think, and perhaps a more finer grained approach would be to add a new "sensitive" flag for typed variables that the GC can recognize. Then only those variables get zeroized when the GC runs. 
Would probably be better for performance than always zeroizing everything that we free...

BTW - so far I didn't find any FP language that can do something like that, and please correct me if I'm wrong. It would be cool if Erlang would be the first to the gold here (again!) :)

On Sun, Oct 27, 2019 at 1:42 AM Dániel Szoboszlay <[hidden email]> wrote:
Hi Amit,

A NIF could use a resource object to implement a zeroable memory location. The Erlang program will only see a handle to the resource, which is immutable. But the contents of the object can be changed by the NIF (it's better explained in the docs). So you could create an API that looks like this for the Erlang program:

Handle = create_secret(Some, Input, Values),
ok = use_secret(Handle),
ok = destroy_secret(Handle), % The NIF zeroes out the memory in the resource object
{error, destroyed} = use_secret(Handle). % The secret is no more at this point

The big problem is that your secret shall never leave the native library. E.g. you cannot hide a cryptographic key behind a zeroable resource object and then pass it to the crypto library. As soon as you convert it into an Erlang term, it is copied onto the non-zeroed stack or heap or a process. Considering this, you may just as well use a port program to hold and work with the secret outside of the Erlang VM.

Probably the only real solution within the VM would be to patch the GC to zero any reclaimed memory. Or maybe not even the GC, but the memory allocators, in case a secret is copied to some non-GC-d memory area, such as an ETS table.

Cheers,
Daniel

On Sat, 26 Oct 2019 at 22:39, Amit K <[hidden email]> wrote:
Hi all,

Concerning the security practice of Zeroizing sensitive data from memory after you're finished with it, such as Cryptographic keys, passwords, etc, I wanted to ask if any of you ever had to implement such a thing in Erlang, and if so, how? :) 

Also note that often this is a requirement that you must fulfill if you want your product to pass a security standard evaluation such as the "Common Criteria" one (As an example requirement see FCS_CKM_EXT.4 here: https://www.commoncriteriaportal.org/files/ppfiles/pp_nd_v1.0.pdf).

The problem of course is that in Erlang (and I suppose - FP in general) once a variable gets assigned, you are not allowed to change its value, and in particular of course overwrite it with zero bytes. 

One option I thought about is doing it with a NIF, but from my understanding a NIF isn't supposed to change its input values, it should treat them as constants, which understandable as well (basic FP language property). 

Any feedback can be helpful :)

Regards,

Amit






Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Dániel Szoboszlay
Hi Amit,

Regarding the sensitive flag:
  • I like the idea of only zeroing memory of sensitive processes, it sounds like a sensible thing.
  • However, beware that this flag is not used widely enough. For example, I found no usage of it in the OTP source code (except for some test cases verifying it actually works), although applications like ssl could probably make good use of it. Similarly, on GitHub there are only 313 hits if you search for the flag (with a lot of false positives). So you'd definitely have to audit your libraries, such as your webserver, on whether they mark all processes with sensitive data as sensitive.
  • For the above reason, I wouldn't worry that much about performance impact on existing applications. But just to be on the safe side, you could add a command line switch for turning the new feature on, leaving it off by default.
  • What you should worry about are things like shared, reference-counted binaries. They may be shared between sensitive and non-sensitive processes, so do they have to be zeroed or not? What about the memory allocated by NIF-s in sensitive processes? Like the openssl data structures where crypto will copy the keys? I have a feeling that blindly zeroing every freed up memory is inefficient, but doable, while extending the sensitive concept to cover every aspect of the BEAM VM may not be feasible at all.
Regarding more fine grained control via marking terms as sensitive instead of entire processes: I don't think this would be a good idea in practice.
  • The BEAM VM reserves a few low bits in each word of memory for type tags. To mark any term as sensitive, you'd need an unused tag bit, which you don't have. There is one unused tag bit combination for boxed types left, so you could in theory introduce a new, "sensitive data" term type, but that's not feasible to implement. For boxed types on x64, you could also use the top 16 bits of the pointer for meta-data, as currently the physical addresses are only 48 bit wide on this platform. But this also seems unreasonably complicated and isn't even portable to other architectures.
  • Even if you could tag each sensitive term, this wouldn't make the GC faster. The GC only visits (and copies) live terms. I'm pretty sure that reading in every dead term, checking whether they're sensitive and then selectively zeroing parts of the memory would be much-much slower in practice than just blindly zeroing over the entire memory area. We are talking about out of order CPU-s with precious, limited cache space here.
  • What may work instead is to maintain a list of sensitive terms on the heap for each process. This is probably not impossible to do (e.g. processes already maintain a list of shared, reference-counted binaries they use), but it seems impractically complicated.

Daniel

On Sun, 27 Oct 2019 at 17:34, Amit K <[hidden email]> wrote:
Hi Eric,
I like your suggestion, but would it be a reasonable performance overhead, especially for those who are already using the sensitive flag for certain processes? If the answer is likely yes I may well try to implement this and possibly create a PR for that :) 

On Sun, Oct 27, 2019 at 9:21 AM Eric Pailleau <[hidden email]> wrote:

Hi,

Note that there is a sensitive flag for processes.

Would be neat that variables used by sensitive processes get their memory zeroed.


Envoyé depuis mon mobile



---- Amit K a écrit ----

Hi Daniel,

Good to know about that workaround, thank you. However as you already pointed out, I really do want to be able to handle such "sensitive" variables in Erlang code and use the standard "crypto" library of the OTP. 

With regards to GC - that's a great direction I think, and perhaps a more finer grained approach would be to add a new "sensitive" flag for typed variables that the GC can recognize. Then only those variables get zeroized when the GC runs. 
Would probably be better for performance than always zeroizing everything that we free...

BTW - so far I didn't find any FP language that can do something like that, and please correct me if I'm wrong. It would be cool if Erlang would be the first to the gold here (again!) :)

On Sun, Oct 27, 2019 at 1:42 AM Dániel Szoboszlay <[hidden email]> wrote:
Hi Amit,

A NIF could use a resource object to implement a zeroable memory location. The Erlang program will only see a handle to the resource, which is immutable. But the contents of the object can be changed by the NIF (it's better explained in the docs). So you could create an API that looks like this for the Erlang program:

Handle = create_secret(Some, Input, Values),
ok = use_secret(Handle),
ok = destroy_secret(Handle), % The NIF zeroes out the memory in the resource object
{error, destroyed} = use_secret(Handle). % The secret is no more at this point

The big problem is that your secret shall never leave the native library. E.g. you cannot hide a cryptographic key behind a zeroable resource object and then pass it to the crypto library. As soon as you convert it into an Erlang term, it is copied onto the non-zeroed stack or heap or a process. Considering this, you may just as well use a port program to hold and work with the secret outside of the Erlang VM.

Probably the only real solution within the VM would be to patch the GC to zero any reclaimed memory. Or maybe not even the GC, but the memory allocators, in case a secret is copied to some non-GC-d memory area, such as an ETS table.

Cheers,
Daniel

On Sat, 26 Oct 2019 at 22:39, Amit K <[hidden email]> wrote:
Hi all,

Concerning the security practice of Zeroizing sensitive data from memory after you're finished with it, such as Cryptographic keys, passwords, etc, I wanted to ask if any of you ever had to implement such a thing in Erlang, and if so, how? :) 

Also note that often this is a requirement that you must fulfill if you want your product to pass a security standard evaluation such as the "Common Criteria" one (As an example requirement see FCS_CKM_EXT.4 here: https://www.commoncriteriaportal.org/files/ppfiles/pp_nd_v1.0.pdf).

The problem of course is that in Erlang (and I suppose - FP in general) once a variable gets assigned, you are not allowed to change its value, and in particular of course overwrite it with zero bytes. 

One option I thought about is doing it with a NIF, but from my understanding a NIF isn't supposed to change its input values, it should treat them as constants, which understandable as well (basic FP language property). 

Any feedback can be helpful :)

Regards,

Amit






Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Amit K
Hi Daniel,

Thanks very much for your thoughts and insights.
Regarding your following comment about refc binaries:

> What you should worry about are things like shared, reference-counted binaries. They may be shared between sensitive and non-sensitive processes, so do they have to be zeroed or not? What about the memory allocated by NIF-s in sensitive processes? Like the openssl data structures where crypto will copy the keys? I have a feeling that blindly zeroing every freed up memory is inefficient, but doable, while extending the sensitive concept to cover every aspect of the BEAM VM may not be feasible at all.

I read up on this a little bit here:
http://erlang.org/doc/efficiency_guide/binaryhandling.html
and it seems that even when the binary is not shared it can reside on
the global binary heap - either because it is larger than 64 bytes, or
because it was referenced from another term, even if it's in the same
process. The latter seems to be easily avoidable if you carefully
write your sensitive data handling code, and the same goes for shared
binaries - if you're really writing code that handles sensitive data
you need to be careful about which other processes you share it with
anyway :)
The size limitation of 64 bytes however is a bit more painful,
although actually, for symmetric crypto keys and passwords 64 bytes is
very reasonable because AES-256 keys for example are only 32 bytes
long. Most passwords are also much shorter than 64 bytes. However of
course for asymmetric crypto the key sizes are much larger than 64
bytes and this becomes a real issue.

I have two ideas on how to address this:

1. Add a "sensitive" flag for the entire Erlang node as well, which at
least to begin with, will only tell the GC to also zero the binary
heap when it frees it. More relevant actions can be piled on top of
that semantic in the future.

2. The second would be to allow larger binaries to reside on the
process heap of sensitive processes, possibly even make this
configurable. This sounds to me a bit more complex than 1.

One final point about NIFs - I think that's outside the scope of what
is possible to address. The use case I really want to address is the
handling of sensitive data in Erlang code and the passing of it to and
from the "crypto" module. Granted, OpenSSL is a C program and hence a
NIF (hope I got that right) but if OpenSSL fails to zero its internal
sensitive buffers, that's a bug that should be handled in the OpenSSL
context :)

(BTW: after a bit of searching I found that OpenSSL uses
"openssl_cleanse" whenever it
needs to zero a sensitive buffer -
https://github.com/openssl/openssl/search?q=openssl_cleanse&unscoped_q=openssl_cleanse)

Thanks,
Amit
Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Kenneth Lundin-5
The OpenSSL engine concept can be used to store cryptographical keys in a safe manner.
The engine is a plugin for the OpenSSL libcrypto and the API for loading and using engines is supported in the crypto application in OTP.


/Kenneth, Erlang/OTP Ericsson

On Mon, Oct 28, 2019 at 1:24 PM Amit K <[hidden email]> wrote:
Hi Daniel,

Thanks very much for your thoughts and insights.
Regarding your following comment about refc binaries:

> What you should worry about are things like shared, reference-counted binaries. They may be shared between sensitive and non-sensitive processes, so do they have to be zeroed or not? What about the memory allocated by NIF-s in sensitive processes? Like the openssl data structures where crypto will copy the keys? I have a feeling that blindly zeroing every freed up memory is inefficient, but doable, while extending the sensitive concept to cover every aspect of the BEAM VM may not be feasible at all.

I read up on this a little bit here:
http://erlang.org/doc/efficiency_guide/binaryhandling.html
and it seems that even when the binary is not shared it can reside on
the global binary heap - either because it is larger than 64 bytes, or
because it was referenced from another term, even if it's in the same
process. The latter seems to be easily avoidable if you carefully
write your sensitive data handling code, and the same goes for shared
binaries - if you're really writing code that handles sensitive data
you need to be careful about which other processes you share it with
anyway :)
The size limitation of 64 bytes however is a bit more painful,
although actually, for symmetric crypto keys and passwords 64 bytes is
very reasonable because AES-256 keys for example are only 32 bytes
long. Most passwords are also much shorter than 64 bytes. However of
course for asymmetric crypto the key sizes are much larger than 64
bytes and this becomes a real issue.

I have two ideas on how to address this:

1. Add a "sensitive" flag for the entire Erlang node as well, which at
least to begin with, will only tell the GC to also zero the binary
heap when it frees it. More relevant actions can be piled on top of
that semantic in the future.

2. The second would be to allow larger binaries to reside on the
process heap of sensitive processes, possibly even make this
configurable. This sounds to me a bit more complex than 1.

One final point about NIFs - I think that's outside the scope of what
is possible to address. The use case I really want to address is the
handling of sensitive data in Erlang code and the passing of it to and
from the "crypto" module. Granted, OpenSSL is a C program and hence a
NIF (hope I got that right) but if OpenSSL fails to zero its internal
sensitive buffers, that's a bug that should be handled in the OpenSSL
context :)

(BTW: after a bit of searching I found that OpenSSL uses
"openssl_cleanse" whenever it
needs to zero a sensitive buffer -
https://github.com/openssl/openssl/search?q=openssl_cleanse&unscoped_q=openssl_cleanse)

Thanks,
Amit
Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Amit K
Hi Kenneth,

This seems like a great option for integrating with something like HSM (pkcs11 in particular) devices. 

However I want to emphasize again, at the risk of being repetitive, that since the OTP provides the crypto module as an Erlang native way to perform crypto operations, that naturally involve sensitive data such as keys and passwords, the requirement that the OTP will also be able to securely wipe such sensitive data from memory seems very important to me. 

Regards,
Amit

On Mon, Oct 28, 2019, 3:18 PM Kenneth Lundin <[hidden email]> wrote:
The OpenSSL engine concept can be used to store cryptographical keys in a safe manner.
The engine is a plugin for the OpenSSL libcrypto and the API for loading and using engines is supported in the crypto application in OTP.


/Kenneth, Erlang/OTP Ericsson

On Mon, Oct 28, 2019 at 1:24 PM Amit K <[hidden email]> wrote:
Hi Daniel,

Thanks very much for your thoughts and insights.
Regarding your following comment about refc binaries:

> What you should worry about are things like shared, reference-counted binaries. They may be shared between sensitive and non-sensitive processes, so do they have to be zeroed or not? What about the memory allocated by NIF-s in sensitive processes? Like the openssl data structures where crypto will copy the keys? I have a feeling that blindly zeroing every freed up memory is inefficient, but doable, while extending the sensitive concept to cover every aspect of the BEAM VM may not be feasible at all.

I read up on this a little bit here:
http://erlang.org/doc/efficiency_guide/binaryhandling.html
and it seems that even when the binary is not shared it can reside on
the global binary heap - either because it is larger than 64 bytes, or
because it was referenced from another term, even if it's in the same
process. The latter seems to be easily avoidable if you carefully
write your sensitive data handling code, and the same goes for shared
binaries - if you're really writing code that handles sensitive data
you need to be careful about which other processes you share it with
anyway :)
The size limitation of 64 bytes however is a bit more painful,
although actually, for symmetric crypto keys and passwords 64 bytes is
very reasonable because AES-256 keys for example are only 32 bytes
long. Most passwords are also much shorter than 64 bytes. However of
course for asymmetric crypto the key sizes are much larger than 64
bytes and this becomes a real issue.

I have two ideas on how to address this:

1. Add a "sensitive" flag for the entire Erlang node as well, which at
least to begin with, will only tell the GC to also zero the binary
heap when it frees it. More relevant actions can be piled on top of
that semantic in the future.

2. The second would be to allow larger binaries to reside on the
process heap of sensitive processes, possibly even make this
configurable. This sounds to me a bit more complex than 1.

One final point about NIFs - I think that's outside the scope of what
is possible to address. The use case I really want to address is the
handling of sensitive data in Erlang code and the passing of it to and
from the "crypto" module. Granted, OpenSSL is a C program and hence a
NIF (hope I got that right) but if OpenSSL fails to zero its internal
sensitive buffers, that's a bug that should be handled in the OpenSSL
context :)

(BTW: after a bit of searching I found that OpenSSL uses
"openssl_cleanse" whenever it
needs to zero a sensitive buffer -
https://github.com/openssl/openssl/search?q=openssl_cleanse&unscoped_q=openssl_cleanse)

Thanks,
Amit
Reply | Threaded
Open this post in threaded view
|

Re: Zeroization of sensitive data in Erlang

Dániel Szoboszlay
In reply to this post by Amit K
Hi Amit,

Maybe instead of 1. and 2. it would work just to make the GC in sensitive processes to zero refcounted binaries when it removes the last reference to them. This means all binary data exclusive to a sensitive process would be zeroed, and a binary shared between a sensitive and nonsensitive process may or may not get zeroed, depending on which process stops using it last. But that's fine most of the cases: data shared with a nonsensitive process shouldn't be sensitive.

There's one caveat with sub binaries: you may have a large binary in a sensitive process that contains some sensitive data and some nonsensitive data too (e.g. you read in a file that contains a private key and a certificate), in which case you have to be careful not to share the nonsensitive part as a sub binary with an other process. Otherwise the GC may fail to zero out the sensitive part too when run from the nonsensitive process. This could be avoided by using binary:copy/1 before sharing the nonsensitive part.

Daniel


On Mon, 28 Oct 2019 at 13:23, Amit K <[hidden email]> wrote:
Hi Daniel,

Thanks very much for your thoughts and insights.
Regarding your following comment about refc binaries:

> What you should worry about are things like shared, reference-counted binaries. They may be shared between sensitive and non-sensitive processes, so do they have to be zeroed or not? What about the memory allocated by NIF-s in sensitive processes? Like the openssl data structures where crypto will copy the keys? I have a feeling that blindly zeroing every freed up memory is inefficient, but doable, while extending the sensitive concept to cover every aspect of the BEAM VM may not be feasible at all.

I read up on this a little bit here:
http://erlang.org/doc/efficiency_guide/binaryhandling.html
and it seems that even when the binary is not shared it can reside on
the global binary heap - either because it is larger than 64 bytes, or
because it was referenced from another term, even if it's in the same
process. The latter seems to be easily avoidable if you carefully
write your sensitive data handling code, and the same goes for shared
binaries - if you're really writing code that handles sensitive data
you need to be careful about which other processes you share it with
anyway :)
The size limitation of 64 bytes however is a bit more painful,
although actually, for symmetric crypto keys and passwords 64 bytes is
very reasonable because AES-256 keys for example are only 32 bytes
long. Most passwords are also much shorter than 64 bytes. However of
course for asymmetric crypto the key sizes are much larger than 64
bytes and this becomes a real issue.

I have two ideas on how to address this:

1. Add a "sensitive" flag for the entire Erlang node as well, which at
least to begin with, will only tell the GC to also zero the binary
heap when it frees it. More relevant actions can be piled on top of
that semantic in the future.

2. The second would be to allow larger binaries to reside on the
process heap of sensitive processes, possibly even make this
configurable. This sounds to me a bit more complex than 1.

One final point about NIFs - I think that's outside the scope of what
is possible to address. The use case I really want to address is the
handling of sensitive data in Erlang code and the passing of it to and
from the "crypto" module. Granted, OpenSSL is a C program and hence a
NIF (hope I got that right) but if OpenSSL fails to zero its internal
sensitive buffers, that's a bug that should be handled in the OpenSSL
context :)

(BTW: after a bit of searching I found that OpenSSL uses
"openssl_cleanse" whenever it
needs to zero a sensitive buffer -
https://github.com/openssl/openssl/search?q=openssl_cleanse&unscoped_q=openssl_cleanse)

Thanks,
Amit