Added memory locking for secrets (#1491)

When caching a PIN in memory or using an OpenSSL private key this data should not be swapped to disk.
This commit is contained in:
Frank Morgner 2018-10-10 14:52:01 +02:00 committed by GitHub
parent 6bf67f7917
commit ea6f7cfe1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 105 additions and 7 deletions

View File

@ -38,6 +38,7 @@
#include "common/libscdl.h"
#include "internal.h"
#include "sc-ossl-compat.h"
static int ignored_reader(sc_context_t *ctx, sc_reader_t *reader)
{
@ -831,6 +832,13 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm)
return r;
}
#ifdef ENABLE_OPENSSL
if (!CRYPTO_secure_malloc_initialized()) {
/* XXX What's a reasonable amount of secure heap? */
CRYPTO_secure_malloc_init(4096, 32);
}
#endif
process_config_file(ctx, &opts);
sc_log(ctx, "==================================="); /* first thing in the log */
sc_log(ctx, "opensc version: %s", sc_get_version());

View File

@ -131,6 +131,8 @@ sc_lock
sc_logout
sc_make_cache_dir
sc_mem_clear
sc_mem_secure_alloc
sc_mem_secure_free
sc_mem_reverse
sc_match_atr_block
sc_path_print

View File

@ -1366,6 +1366,8 @@ int sc_base64_decode(const char *in, u8 *out, size_t outlen);
* @param len length of the memory buffer
*/
void sc_mem_clear(void *ptr, size_t len);
void *sc_mem_secure_alloc(size_t len);
void sc_mem_secure_free(void *ptr, size_t len);
int sc_mem_reverse(unsigned char *buf, size_t len);
int sc_get_cache_dir(sc_context_t *ctx, char *buf, size_t bufsize);

View File

@ -2496,8 +2496,15 @@ sc_pkcs15_make_absolute_path(const struct sc_path *parent, struct sc_path *child
void sc_pkcs15_free_object_content(struct sc_pkcs15_object *obj)
{
if (obj->content.value && obj->content.len) {
sc_mem_clear(obj->content.value, obj->content.len);
free(obj->content.value);
if (SC_PKCS15_TYPE_AUTH & obj->type
|| SC_PKCS15_TYPE_SKEY & obj->type
|| SC_PKCS15_TYPE_PRKEY & obj->type) {
/* clean everything that potentially contains a secret */
sc_mem_clear(obj->content.value, obj->content.len);
sc_mem_secure_free(obj->content.value, obj->content.len);
} else {
free(obj->content.value);
}
}
obj->content.value = NULL;
obj->content.len = 0;
@ -2521,7 +2528,13 @@ sc_pkcs15_allocate_object_content(struct sc_context *ctx, struct sc_pkcs15_objec
/* Need to pass by temporary variable,
* because 'value' and 'content.value' pointers can be the sames.
*/
tmp_buf = calloc(sizeof *tmp_buf, len);
if (SC_PKCS15_TYPE_AUTH & obj->type
|| SC_PKCS15_TYPE_SKEY & obj->type
|| SC_PKCS15_TYPE_PRKEY & obj->type) {
tmp_buf = sc_mem_secure_alloc(len);
} else {
tmp_buf = malloc(len);
}
if (!tmp_buf)
return SC_ERROR_OUT_OF_MEMORY;

View File

@ -230,6 +230,19 @@ static sc_ossl_inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
}
#endif /* OPENSSL_NO_EC */
static sc_ossl_inline int CRYPTO_secure_malloc_init(size_t size, int minsize)
{
return 0;
}
static sc_ossl_inline int CRYPTO_secure_malloc_initialized()
{
return 0;
}
#else
#include <openssl/crypto.h>
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */

View File

@ -34,6 +34,7 @@
#include <openssl/crypto.h> /* for OPENSSL_cleanse */
#endif
#include "internal.h"
#ifdef PACKAGE_VERSION
@ -42,6 +43,19 @@ static const char *sc_version = PACKAGE_VERSION;
static const char *sc_version = "(undef)";
#endif
#ifdef _WIN32
#include <windows.h>
#define PAGESIZE 0
#else
#include <sys/mman.h>
#include <limits.h>
#include <unistd.h>
#ifndef PAGESIZE
#define PAGESIZE 0
#endif
#endif
static size_t page_size = PAGESIZE;
const char *sc_get_version(void)
{
return sc_version;
@ -826,6 +840,52 @@ int _sc_parse_atr(sc_reader_t *reader)
return SC_SUCCESS;
}
static void init_page_size()
{
if (page_size == 0) {
#ifdef _WIN32
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
page_size = system_info.dwPageSize;
#else
page_size = sysconf(_SC_PAGESIZE);
if ((long) page_size < 0) {
page_size = 0;
}
#endif
}
}
void *sc_mem_secure_alloc(size_t len)
{
void *p;
init_page_size();
if (page_size > 0) {
size_t pages = (len + page_size - 1) / page_size;
len = pages * page_size;
}
p = malloc(len);
#ifdef _WIN32
VirtualLock(p, len);
#else
mlock(p, len);
#endif
return p;
}
void sc_mem_secure_free(void *ptr, size_t len)
{
#ifdef _WIN32
VirtualUnlock(ptr, len);
#else
munlock(ptr, len);
#endif
free(ptr);
}
void sc_mem_clear(void *ptr, size_t len)
{
if (len > 0) {

View File

@ -187,7 +187,7 @@ CK_RV push_login_state(struct sc_pkcs11_slot *slot,
}
if (pPin && ulPinLen) {
login->pPin = calloc((sizeof *pPin), ulPinLen);
login->pPin = sc_mem_secure_alloc((sizeof *pPin)*ulPinLen);
if (login->pPin == NULL) {
goto err;
}
@ -207,7 +207,7 @@ err:
if (login) {
if (login->pPin) {
sc_mem_clear(login->pPin, login->ulPinLen);
free(login->pPin);
sc_mem_secure_free(login->pPin, login->ulPinLen);
}
free(login);
}
@ -223,7 +223,7 @@ void pop_login_state(struct sc_pkcs11_slot *slot)
struct sc_pkcs11_login *login = list_get_at(&slot->logins, size-1);
if (login) {
sc_mem_clear(login->pPin, login->ulPinLen);
free(login->pPin);
sc_mem_secure_free(login->pPin, login->ulPinLen);
free(login);
}
if (0 > list_delete_at(&slot->logins, size-1))
@ -238,7 +238,7 @@ void pop_all_login_states(struct sc_pkcs11_slot *slot)
struct sc_pkcs11_login *login = list_fetch(&slot->logins);
while (login) {
sc_mem_clear(login->pPin, login->ulPinLen);
free(login->pPin);
sc_mem_secure_free(login->pPin, login->ulPinLen);
free(login);
login = list_fetch(&slot->logins);
}