Adding Secure Lock to lock the device with a random 256 bit key.

This is an extra layer of security to avoid brute force attacks if PIN is too weak.
At every hard reset (on device plug), the device must be unlocked prior any other command. Once unlocked, the device can be used as usual.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2022-10-31 15:09:54 +01:00
parent eda8b53949
commit 00279da8d5
5 changed files with 215 additions and 4 deletions

View File

@@ -15,14 +15,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common.h"
#include "mbedtls/ecdh.h"
#include "sc_hsm.h"
#include "hardware/rtc.h"
#include "files.h"
#include "random.h"
#include "kek.h"
#include "mbedtls/hkdf.h"
#include "mbedtls/chachapoly.h"
int cmd_extras() {
if (P2(apdu) != 0x0)
return SW_INCORRECT_P1P2();
if (P1(apdu) == 0xA) { //datetime operations
if (P2(apdu) != 0x0)
return SW_INCORRECT_P1P2();
if (apdu.nc == 0) {
datetime_t dt;
if (!rtc_get_datetime(&dt))
@@ -52,6 +58,8 @@ int cmd_extras() {
}
}
else if (P1(apdu) == 0x6) { //dynamic options
if (P2(apdu) != 0x0)
return SW_INCORRECT_P1P2();
if (apdu.nc > sizeof(uint8_t))
return SW_WRONG_LENGTH();
uint16_t opts = get_device_options();
@@ -66,6 +74,86 @@ int cmd_extras() {
low_flash_available();
}
}
else if (P1(apdu) == 0x3A) { // secure lock
if (apdu.nc == 0) {
return SW_WRONG_LENGTH();
}
if (P2(apdu) == 0x01) { // Key Agreement
mbedtls_ecdh_context hkey;
mbedtls_ecdh_init(&hkey);
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1);
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_gen, NULL);
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
ret = mbedtls_ecp_point_read_binary(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.Qp, apdu.data, apdu.nc);
if (ret != 0) {
mbedtls_ecdh_free(&hkey);
return SW_WRONG_DATA();
}
memcpy(mse.Qpt, apdu.data, sizeof(mse.Qpt));
uint8_t buf[MBEDTLS_ECP_MAX_BYTES];
size_t olen = 0;
ret = mbedtls_ecdh_calc_secret(&hkey, &olen, buf, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL);
if (ret != 0) {
mbedtls_ecdh_free(&hkey);
mbedtls_platform_zeroize(buf, sizeof(buf));
return SW_WRONG_DATA();
}
ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), NULL, 0, buf, olen, mse.Qpt, sizeof(mse.Qpt), mse.key_enc, sizeof(mse.key_enc));
mbedtls_platform_zeroize(buf, sizeof(buf));
if (ret != 0) {
mbedtls_ecdh_free(&hkey);
return SW_EXEC_ERROR();
}
ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, res_APDU, 4096);
mbedtls_ecdh_free(&hkey);
if (ret != 0) {
return SW_EXEC_ERROR();
}
mse.init = true;
res_APDU_size = olen;
}
else if (P2(apdu) == 0x02 || P2(apdu) == 0x03 || P2(apdu) == 0x04) {
if (mse.init == false)
return SW_COMMAND_NOT_ALLOWED();
int ret = mse_decrypt_ct(apdu.data, apdu.nc);
if (ret != 0) {
return SW_WRONG_DATA();
}
if (P2(apdu) == 0x02 || P2(apdu) == 0x04) { // Enable
uint16_t opts = get_device_options();
uint8_t newopts[] = { opts >> 8, (opts & 0xff) };
if ((P2(apdu) == 0x02 && !(opts & HSM_OPT_SECURE_LOCK)) || (P2(apdu) == 0x04 && (opts & HSM_OPT_SECURE_LOCK))) {
uint16_t tfids[] = { EF_MKEK, EF_MKEK_SO };
for (int t = 0; t < sizeof(tfids)/sizeof(uint16_t); t++) {
file_t *tf = search_by_fid(tfids[t], NULL, SPECIFY_EF);
if (tf) {
uint8_t *tmp = (uint8_t *)calloc(1, file_get_size(tf));
memcpy(tmp, file_get_data(tf), file_get_size(tf));
for (int i = 0; i < MKEK_KEY_SIZE; i++) {
MKEK_KEY(tmp)[i] ^= apdu.data[i];
}
flash_write_data_to_file(tf, tmp, file_get_size(tf));
free(tmp);
}
}
}
if (P2(apdu) == 0x02)
newopts[0] |= HSM_OPT_SECURE_LOCK >> 8;
else if (P2(apdu) == 0x04)
newopts[0] &= ~HSM_OPT_SECURE_LOCK >> 8;
file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF);
flash_write_data_to_file(tf, newopts, sizeof(newopts));
low_flash_available();
}
else if (P2(apdu) == 0x03) {
memcpy(mkek_mask, apdu.data, apdu.nc);
has_mkek_mask = true;
}
}
}
else
return SW_INCORRECT_P1P2();
return SW_OK();

View File

@@ -27,10 +27,13 @@
#include "mbedtls/cmac.h"
#include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/chachapoly.h"
#include "files.h"
extern bool has_session_pin, has_session_sopin;
extern uint8_t session_pin[32], session_sopin[32];
uint8_t mkek_mask[MKEK_KEY_SIZE];
bool has_mkek_mask = false;
#define POLY 0xedb88320
@@ -65,6 +68,12 @@ int load_mkek(uint8_t *mkek) {
}
if (pin == NULL) //Should never happen
return CCID_EXEC_ERROR;
if (has_mkek_mask) {
for (int i = 0; i < MKEK_KEY_SIZE; i++) {
MKEK_KEY(mkek)[i] ^= mkek_mask[i];
}
}
int ret = aes_decrypt_cfb_256(pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE+MKEK_KEY_CS_SIZE);
if (ret != 0)
return CCID_EXEC_ERROR;
@@ -73,6 +82,17 @@ int load_mkek(uint8_t *mkek) {
return CCID_OK;
}
mse_t mse = {.init = false};
int mse_decrypt_ct(uint8_t *data, size_t len) {
mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, mse.key_enc + 12);
int ret = mbedtls_chachapoly_auth_decrypt(&chatx, len - 16, mse.key_enc, mse.Qpt, 65, data + len - 16, data, data);
mbedtls_chachapoly_free(&chatx);
return ret;
}
int load_dkek(uint8_t id, uint8_t *dkek) {
file_t *tf = search_dynamic_file(EF_DKEK+id);
if (!tf)

View File

@@ -18,6 +18,8 @@
#ifndef _DKEK_H_
#define _DKEK_H_
#include "crypto_utils.h"
extern int load_mkek(uint8_t *);
extern int store_mkek(const uint8_t *);
extern int save_dkek_key(uint8_t, const uint8_t *key);
@@ -45,4 +47,16 @@ extern int dkek_decode_key(uint8_t, void *key_ctx, const uint8_t *in, size_t in_
#define MKEK_CHECKSUM(p) (MKEK_KEY(p)+MKEK_KEY_SIZE)
#define DKEK_KEY_SIZE (32)
extern uint8_t mkek_mask[MKEK_KEY_SIZE];
extern bool has_mkek_mask;
typedef struct mse {
uint8_t Qpt[65];
uint8_t key_enc[12 + 32];
bool init;
} mse_t;
extern mse_t mse;
extern int mse_decrypt_ct(uint8_t *, size_t);
#endif

View File

@@ -77,6 +77,7 @@ extern const uint8_t sc_hsm_aid[];
#define HSM_OPT_RRC_RESET_ONLY 0x0020
#define HSM_OPT_BOOTSEL_BUTTON 0x0100
#define HSM_OPT_KEY_COUNTER_ALL 0x0200
#define HSM_OPT_SECURE_LOCK 0x0400
#define PRKD_PREFIX 0xC4 /* Hi byte in file identifier for PKCS#15 PRKD objects */
#define CD_PREFIX 0xC8 /* Hi byte in file identifier for PKCS#15 CD objects */