Skip to content

Commit

Permalink
Secure usage of Emscripten heap (#495)
Browse files Browse the repository at this point in the history
* Heap utilities

Provide some wrapper functions to hide all the intricacies of dealing
with Emscripten heap. We should use these functions instead of calling
C directly.

Note that they ensure that allocated memory is zeroed out before use
as well as after use. This makes it easier to debug initialization
issues, and reduces the likelihood of sensitive data leakage through
Emscripten heap.

* Use heap securely in key generation
* Use heap securely in Secure Cell
* Use heap securely in Secure Message
* Use heap securely in Secure Comparator
* Use heap securely in Secure Session

Instead of calling malloc() and free() directly, use our new helpers
to deal with passing byte arrays between JavaScript and Emscripten.

Instead of calling malloc() and free() directly, use our new helpers
to deal with passing byte arrays between JavaScript and Emscripten.

* Avoid NULL dereference

heapAlloc: if malloc() fails then do not zero out the result

heapFree: make this function a no-op to allow its usage in failure
paths where the pointer is null (e.g., returned by failed heapAlloc)

We use a weird check "!!buffer" because JavaScript has weird ideas
about what is null and what is zero. malloc() results are generally
checked with "!ptr" so we invert this check.
  • Loading branch information
ilammy authored Jul 11, 2019
1 parent a58e0c8 commit 258d0aa
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 183 deletions.
50 changes: 24 additions & 26 deletions src/wrappers/themis/wasm/src/secure_cell_context_imprint.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,16 @@ module.exports = class SecureCellContextImprint {
let result_length_ptr = libthemis.allocate(4, 'i32', libthemis.ALLOC_STACK)
let master_key_ptr, message_ptr, context_ptr, result_ptr, result_length
try {
master_key_ptr = libthemis._malloc(this.masterKey.length)
message_ptr = libthemis._malloc(message.length)
context_ptr = libthemis._malloc(context.length)
master_key_ptr = utils.heapAlloc(this.masterKey.length)
message_ptr = utils.heapAlloc(message.length)
context_ptr = utils.heapAlloc(context.length)
if (!master_key_ptr || !message_ptr || !context_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}

libthemis.writeArrayToMemory(this.masterKey, master_key_ptr)
libthemis.writeArrayToMemory(message, message_ptr)
libthemis.writeArrayToMemory(context, context_ptr)
utils.heapPutArray(this.masterKey, master_key_ptr)
utils.heapPutArray(message, message_ptr)
utils.heapPutArray(context, context_ptr)

status = libthemis._themis_secure_cell_encrypt_context_imprint(
master_key_ptr, this.masterKey.length,
Expand All @@ -84,7 +84,7 @@ module.exports = class SecureCellContextImprint {
}

result_length = libthemis.getValue(result_length_ptr, 'i32')
result_ptr = libthemis._malloc(result_length)
result_ptr = utils.heapAlloc(result_length)
if (!result_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}
Expand All @@ -101,14 +101,13 @@ module.exports = class SecureCellContextImprint {

result_length = libthemis.getValue(result_length_ptr, 'i32')

return libthemis.HEAPU8.slice(result_ptr, result_ptr + result_length)
return utils.heapGetArray(result_ptr, result_length)
}
finally {
libthemis._memset(master_key_ptr, 0, this.masterKey.length)
libthemis._free(master_key_ptr)
libthemis._free(message_ptr)
libthemis._free(context_ptr)
libthemis._free(result_ptr)
utils.heapFree(master_key_ptr, this.masterKey.length)
utils.heapFree(message_ptr, message.length)
utils.heapFree(context_ptr, context.length)
utils.heapFree(result_ptr, result_length)
}
}

Expand Down Expand Up @@ -138,16 +137,16 @@ module.exports = class SecureCellContextImprint {
let result_length_ptr = libthemis.allocate(4, 'i32', libthemis.ALLOC_STACK)
let master_key_ptr, message_ptr, context_ptr, result_ptr, result_length
try {
master_key_ptr = libthemis._malloc(this.masterKey.length)
message_ptr = libthemis._malloc(message.length)
context_ptr = libthemis._malloc(context.length)
master_key_ptr = utils.heapAlloc(this.masterKey.length)
message_ptr = utils.heapAlloc(message.length)
context_ptr = utils.heapAlloc(context.length)
if (!master_key_ptr || !message_ptr || !context_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}

libthemis.writeArrayToMemory(this.masterKey, master_key_ptr)
libthemis.writeArrayToMemory(message, message_ptr)
libthemis.writeArrayToMemory(context, context_ptr)
utils.heapPutArray(this.masterKey, master_key_ptr)
utils.heapPutArray(message, message_ptr)
utils.heapPutArray(context, context_ptr)

status = libthemis._themis_secure_cell_decrypt_context_imprint(
master_key_ptr, this.masterKey.length,
Expand All @@ -160,7 +159,7 @@ module.exports = class SecureCellContextImprint {
}

result_length = libthemis.getValue(result_length_ptr, 'i32')
result_ptr = libthemis._malloc(result_length)
result_ptr = utils.heapAlloc(result_length)
if (!result_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}
Expand All @@ -177,14 +176,13 @@ module.exports = class SecureCellContextImprint {

result_length = libthemis.getValue(result_length_ptr, 'i32')

return libthemis.HEAPU8.slice(result_ptr, result_ptr + result_length)
return utils.heapGetArray(result_ptr, result_length)
}
finally {
libthemis._memset(master_key_ptr, 0, this.masterKey.length)
libthemis._free(master_key_ptr)
libthemis._free(message_ptr)
libthemis._free(context_ptr)
libthemis._free(result_ptr)
utils.heapFree(master_key_ptr, this.masterKey.length)
utils.heapFree(message_ptr, message.length)
utils.heapFree(context_ptr, context.length)
utils.heapFree(result_ptr, result_length)
}
}
}
50 changes: 24 additions & 26 deletions src/wrappers/themis/wasm/src/secure_cell_seal.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ module.exports = class SecureCellSeal {
let result_length_ptr = libthemis.allocate(4, 'i32', libthemis.ALLOC_STACK)
let master_key_ptr, message_ptr, context_ptr, result_ptr, result_length
try {
master_key_ptr = libthemis._malloc(this.masterKey.length)
message_ptr = libthemis._malloc(message.length)
context_ptr = libthemis._malloc(context.length)
master_key_ptr = utils.heapAlloc(this.masterKey.length)
message_ptr = utils.heapAlloc(message.length)
context_ptr = utils.heapAlloc(context.length)
if (!master_key_ptr || !message_ptr || !context_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}

libthemis.writeArrayToMemory(this.masterKey, master_key_ptr)
libthemis.writeArrayToMemory(message, message_ptr)
libthemis.writeArrayToMemory(context, context_ptr)
utils.heapPutArray(this.masterKey, master_key_ptr)
utils.heapPutArray(message, message_ptr)
utils.heapPutArray(context, context_ptr)

status = libthemis._themis_secure_cell_encrypt_seal(
master_key_ptr, this.masterKey.length,
Expand All @@ -77,7 +77,7 @@ module.exports = class SecureCellSeal {
}

result_length = libthemis.getValue(result_length_ptr, 'i32')
result_ptr = libthemis._malloc(result_length)
result_ptr = utils.heapAlloc(result_length)
if (!result_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}
Expand All @@ -94,14 +94,13 @@ module.exports = class SecureCellSeal {

result_length = libthemis.getValue(result_length_ptr, 'i32')

return libthemis.HEAPU8.slice(result_ptr, result_ptr + result_length)
return utils.heapGetArray(result_ptr, result_length)
}
finally {
libthemis._memset(master_key_ptr, 0, this.masterKey.length)
libthemis._free(master_key_ptr)
libthemis._free(message_ptr)
libthemis._free(context_ptr)
libthemis._free(result_ptr)
utils.heapFree(master_key_ptr, this.masterKey.length)
utils.heapFree(message_ptr, message.length)
utils.heapFree(context_ptr, context.length)
utils.heapFree(result_ptr, result_length)
}
}

Expand All @@ -124,16 +123,16 @@ module.exports = class SecureCellSeal {
let result_length_ptr = libthemis.allocate(4, 'i32', libthemis.ALLOC_STACK)
let master_key_ptr, message_ptr, context_ptr, result_ptr, result_length
try {
master_key_ptr = libthemis._malloc(this.masterKey.length)
message_ptr = libthemis._malloc(message.length)
context_ptr = libthemis._malloc(context.length)
master_key_ptr = utils.heapAlloc(this.masterKey.length)
message_ptr = utils.heapAlloc(message.length)
context_ptr = utils.heapAlloc(context.length)
if (!master_key_ptr || !message_ptr || !context_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}

libthemis.writeArrayToMemory(this.masterKey, master_key_ptr)
libthemis.writeArrayToMemory(message, message_ptr)
libthemis.writeArrayToMemory(context, context_ptr)
utils.heapPutArray(this.masterKey, master_key_ptr)
utils.heapPutArray(message, message_ptr)
utils.heapPutArray(context, context_ptr)

status = libthemis._themis_secure_cell_decrypt_seal(
master_key_ptr, this.masterKey.length,
Expand All @@ -146,7 +145,7 @@ module.exports = class SecureCellSeal {
}

result_length = libthemis.getValue(result_length_ptr, 'i32')
result_ptr = libthemis._malloc(result_length)
result_ptr = utils.heapAlloc(result_length)
if (!result_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}
Expand All @@ -163,14 +162,13 @@ module.exports = class SecureCellSeal {

result_length = libthemis.getValue(result_length_ptr, 'i32')

return libthemis.HEAPU8.slice(result_ptr, result_ptr + result_length)
return utils.heapGetArray(result_ptr, result_length)
}
finally {
libthemis._memset(master_key_ptr, 0, this.masterKey.length)
libthemis._free(master_key_ptr)
libthemis._free(message_ptr)
libthemis._free(context_ptr)
libthemis._free(result_ptr)
utils.heapFree(master_key_ptr, this.masterKey.length)
utils.heapFree(message_ptr, message.length)
utils.heapFree(context_ptr, context.length)
utils.heapFree(result_ptr, result_length)
}
}
}
62 changes: 30 additions & 32 deletions src/wrappers/themis/wasm/src/secure_cell_token_protect.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,16 @@ module.exports = class SecureCellTokenProtect {
let token_length_ptr = libthemis.allocate(4, 'i32', libthemis.ALLOC_STACK)
let master_key_ptr, message_ptr, context_ptr, result_ptr, result_length, token_ptr, token_length
try {
master_key_ptr = libthemis._malloc(this.masterKey.length)
message_ptr = libthemis._malloc(message.length)
context_ptr = libthemis._malloc(context.length)
master_key_ptr = utils.heapAlloc(this.masterKey.length)
message_ptr = utils.heapAlloc(message.length)
context_ptr = utils.heapAlloc(context.length)
if (!master_key_ptr || !message_ptr || !context_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}

libthemis.writeArrayToMemory(this.masterKey, master_key_ptr)
libthemis.writeArrayToMemory(message, message_ptr)
libthemis.writeArrayToMemory(context, context_ptr)
utils.heapPutArray(this.masterKey, master_key_ptr)
utils.heapPutArray(message, message_ptr)
utils.heapPutArray(context, context_ptr)

status = libthemis._themis_secure_cell_encrypt_token_protect(
master_key_ptr, this.masterKey.length,
Expand All @@ -80,8 +80,8 @@ module.exports = class SecureCellTokenProtect {

result_length = libthemis.getValue(result_length_ptr, 'i32')
token_length = libthemis.getValue(token_length_ptr, 'i32')
result_ptr = libthemis._malloc(result_length)
token_ptr = libthemis._malloc(token_length)
result_ptr = utils.heapAlloc(result_length)
token_ptr = utils.heapAlloc(token_length)
if (!result_ptr || !token_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}
Expand All @@ -101,17 +101,16 @@ module.exports = class SecureCellTokenProtect {
token_length = libthemis.getValue(token_length_ptr, 'i32')

return {
data: libthemis.HEAPU8.slice(result_ptr, result_ptr + result_length),
token: libthemis.HEAPU8.slice(token_ptr, token_ptr + token_length)
data: utils.heapGetArray(result_ptr, result_length),
token: utils.heapGetArray(token_ptr, token_length)
}
}
finally {
libthemis._memset(master_key_ptr, 0, this.masterKey.length)
libthemis._free(master_key_ptr)
libthemis._free(message_ptr)
libthemis._free(context_ptr)
libthemis._free(result_ptr)
libthemis._free(token_ptr)
utils.heapFree(master_key_ptr, this.masterKey.length)
utils.heapFree(message_ptr, message.length)
utils.heapFree(context_ptr, context.length)
utils.heapFree(result_ptr, result_length)
utils.heapFree(token_ptr, token_length)
}
}

Expand Down Expand Up @@ -140,18 +139,18 @@ module.exports = class SecureCellTokenProtect {
let result_length_ptr = libthemis.allocate(4, 'i32', libthemis.ALLOC_STACK)
let master_key_ptr, message_ptr, context_ptr, token_ptr, result_ptr, result_length
try {
master_key_ptr = libthemis._malloc(this.masterKey.length)
message_ptr = libthemis._malloc(message.length)
context_ptr = libthemis._malloc(context.length)
token_ptr = libthemis._malloc(token.length)
master_key_ptr = utils.heapAlloc(this.masterKey.length)
message_ptr = utils.heapAlloc(message.length)
context_ptr = utils.heapAlloc(context.length)
token_ptr = utils.heapAlloc(token.length)
if (!master_key_ptr || !message_ptr || !context_ptr || !token_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}

libthemis.writeArrayToMemory(this.masterKey, master_key_ptr)
libthemis.writeArrayToMemory(message, message_ptr)
libthemis.writeArrayToMemory(context, context_ptr)
libthemis.writeArrayToMemory(token, token_ptr)
utils.heapPutArray(this.masterKey, master_key_ptr)
utils.heapPutArray(message, message_ptr)
utils.heapPutArray(context, context_ptr)
utils.heapPutArray(token, token_ptr)

status = libthemis._themis_secure_cell_decrypt_token_protect(
master_key_ptr, this.masterKey.length,
Expand All @@ -165,7 +164,7 @@ module.exports = class SecureCellTokenProtect {
}

result_length = libthemis.getValue(result_length_ptr, 'i32')
result_ptr = libthemis._malloc(result_length)
result_ptr = utils.heapAlloc(result_length)
if (!result_ptr) {
throw new ThemisError(cryptosystem_name, ThemisErrorCode.NO_MEMORY)
}
Expand All @@ -183,15 +182,14 @@ module.exports = class SecureCellTokenProtect {

result_length = libthemis.getValue(result_length_ptr, 'i32')

return libthemis.HEAPU8.slice(result_ptr, result_ptr + result_length)
return utils.heapGetArray(result_ptr, result_length)
}
finally {
libthemis._memset(master_key_ptr, 0, this.masterKey.length)
libthemis._free(master_key_ptr)
libthemis._free(message_ptr)
libthemis._free(context_ptr)
libthemis._free(token_ptr)
libthemis._free(result_ptr)
utils.heapFree(master_key_ptr, this.masterKey.length)
utils.heapFree(message_ptr, message.length)
utils.heapFree(context_ptr, context.length)
utils.heapFree(result_ptr, result_length)
utils.heapFree(token_ptr, token.length)
}
}
}
Loading

0 comments on commit 258d0aa

Please sign in to comment.