mirror of
https://github.com/jedisct1/libsodium.git
synced 2024-12-19 18:15:18 -07:00
Implement key shielding to protect against side channels
We may want to fold this into `sodium_mprotect_*()` instead of exposing these functions. The drawback is that a transition from PROT_NONE to PROT_READ (or the other way round) would need an intermediary state in PROT_WRITE for shielding/unshielding. Shielding is also not thread-safe, while the `mprotect_*()` functions are, and adding locks would make things more complicated than they probably should.
This commit is contained in:
parent
60f4bc8212
commit
bfeca0eb73
@ -158,6 +158,12 @@ int sodium_mprotect_readonly(void *ptr) __attribute__ ((nonnull));
|
|||||||
SODIUM_EXPORT
|
SODIUM_EXPORT
|
||||||
int sodium_mprotect_readwrite(void *ptr) __attribute__ ((nonnull));
|
int sodium_mprotect_readwrite(void *ptr) __attribute__ ((nonnull));
|
||||||
|
|
||||||
|
SODIUM_EXPORT
|
||||||
|
int sodium_mshield(void *ptr) __attribute__ ((nonnull));
|
||||||
|
|
||||||
|
SODIUM_EXPORT
|
||||||
|
int sodium_munshield(void *ptr) __attribute__ ((nonnull));
|
||||||
|
|
||||||
SODIUM_EXPORT
|
SODIUM_EXPORT
|
||||||
int sodium_pad(size_t *padded_buflen_p, unsigned char *buf,
|
int sodium_pad(size_t *padded_buflen_p, unsigned char *buf,
|
||||||
size_t unpadded_buflen, size_t blocksize, size_t max_buflen)
|
size_t unpadded_buflen, size_t blocksize, size_t max_buflen)
|
||||||
|
@ -43,7 +43,10 @@ void *alloca (size_t);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
#include "crypto_generichash.h"
|
||||||
|
#include "crypto_stream.h"
|
||||||
#include "randombytes.h"
|
#include "randombytes.h"
|
||||||
|
#include "private/common.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#ifndef ENOSYS
|
#ifndef ENOSYS
|
||||||
@ -58,6 +61,8 @@ void *alloca (size_t);
|
|||||||
#define CANARY_SIZE 16U
|
#define CANARY_SIZE 16U
|
||||||
#define GARBAGE_VALUE 0xdb
|
#define GARBAGE_VALUE 0xdb
|
||||||
|
|
||||||
|
#define SHIELDING_PREKEY_SIZE 16384U
|
||||||
|
|
||||||
#ifndef MAP_NOCORE
|
#ifndef MAP_NOCORE
|
||||||
# ifdef MAP_CONCEAL
|
# ifdef MAP_CONCEAL
|
||||||
# define MAP_NOCORE MAP_CONCEAL
|
# define MAP_NOCORE MAP_CONCEAL
|
||||||
@ -87,6 +92,7 @@ void *alloca (size_t);
|
|||||||
|
|
||||||
static size_t page_size;
|
static size_t page_size;
|
||||||
static unsigned char canary[CANARY_SIZE];
|
static unsigned char canary[CANARY_SIZE];
|
||||||
|
static unsigned char shielding_prekey[SHIELDING_PREKEY_SIZE];
|
||||||
|
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
#ifdef HAVE_WEAK_SYMBOLS
|
#ifdef HAVE_WEAK_SYMBOLS
|
||||||
@ -402,7 +408,11 @@ _sodium_alloc_init(void)
|
|||||||
sodium_misuse(); /* LCOV_EXCL_LINE */
|
sodium_misuse(); /* LCOV_EXCL_LINE */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
randombytes_buf(canary, sizeof canary);
|
COMPILER_ASSERT(sizeof shielding_prekey >= randombytes_SEEDBYTES);
|
||||||
|
randombytes_buf(shielding_prekey, randombytes_SEEDBYTES);
|
||||||
|
randombytes_buf_deterministic(canary, sizeof canary, shielding_prekey);
|
||||||
|
shielding_prekey[0] ^= 0x01;
|
||||||
|
randombytes_buf_deterministic(shielding_prekey, sizeof shielding_prekey, shielding_prekey);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -715,6 +725,38 @@ sodium_mprotect_readwrite(void *ptr)
|
|||||||
return _sodium_mprotect(ptr, _mprotect_readwrite);
|
return _sodium_mprotect(ptr, _mprotect_readwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sodium_mshield(void *ptr)
|
||||||
|
{
|
||||||
|
unsigned char shielding_key[crypto_stream_KEYBYTES];
|
||||||
|
unsigned char nonce[crypto_stream_NONCEBYTES];
|
||||||
|
unsigned char *base_ptr;
|
||||||
|
unsigned char *unprotected_ptr;
|
||||||
|
size_t unprotected_size;
|
||||||
|
|
||||||
|
unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr);
|
||||||
|
base_ptr = unprotected_ptr - page_size * 2U;
|
||||||
|
memcpy(&unprotected_size, base_ptr, sizeof unprotected_size);
|
||||||
|
|
||||||
|
crypto_generichash(shielding_key, sizeof shielding_key,
|
||||||
|
shielding_prekey, sizeof shielding_prekey, NULL, 0);
|
||||||
|
COMPILER_ASSERT(sizeof nonce >= (sizeof unprotected_ptr) + (sizeof unprotected_size));
|
||||||
|
memset(nonce, 0, sizeof nonce);
|
||||||
|
memcpy(nonce, &unprotected_ptr, sizeof unprotected_ptr);
|
||||||
|
memcpy(nonce + sizeof unprotected_ptr, &unprotected_size, sizeof unprotected_size);
|
||||||
|
crypto_stream_xor(unprotected_ptr, unprotected_ptr, unprotected_size, nonce, shielding_prekey);
|
||||||
|
sodium_memzero(shielding_key, sizeof shielding_key);
|
||||||
|
sodium_memzero(nonce, sizeof nonce);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sodium_munshield(void *ptr)
|
||||||
|
{
|
||||||
|
return sodium_mshield(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sodium_pad(size_t *padded_buflen_p, unsigned char *buf,
|
sodium_pad(size_t *padded_buflen_p, unsigned char *buf,
|
||||||
size_t unpadded_buflen, size_t blocksize, size_t max_buflen)
|
size_t unpadded_buflen, size_t blocksize, size_t max_buflen)
|
||||||
|
@ -40,9 +40,24 @@ segv_handler(int sig)
|
|||||||
int
|
int
|
||||||
main(void)
|
main(void)
|
||||||
{
|
{
|
||||||
void * buf;
|
void *buf;
|
||||||
size_t size;
|
void *buf2;
|
||||||
unsigned int i;
|
size_t size;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
size = randombytes_uniform(100U);
|
||||||
|
if ((buf = sodium_malloc(size)) == NULL ||
|
||||||
|
(buf2 = sodium_malloc(size)) == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
randombytes_buf(buf, size);
|
||||||
|
memcpy(buf2, buf, size);
|
||||||
|
sodium_mshield(buf);
|
||||||
|
assert(size == 0U || memcmp(buf, buf2, size) != 0);
|
||||||
|
sodium_munshield(buf);
|
||||||
|
assert(size == 0U || memcmp(buf, buf2, size) == 0);
|
||||||
|
sodium_free(buf2);
|
||||||
|
sodium_free(buf);
|
||||||
|
|
||||||
if (sodium_malloc(SIZE_MAX - 1U) != NULL) {
|
if (sodium_malloc(SIZE_MAX - 1U) != NULL) {
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user