mirror of
https://github.com/polhenarejos/pico-fido.git
synced 2025-12-19 02:48:04 +08:00
Add support for PIN hash storage and MKEK.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
@@ -18,6 +18,8 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
if(ESP_PLATFORM)
|
if(ESP_PLATFORM)
|
||||||
|
set(DEBUG_APDU 1)
|
||||||
|
set(DENABLE_POWER_ON_RESET 0)
|
||||||
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
|
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
else()
|
else()
|
||||||
@@ -77,6 +79,7 @@ endif()
|
|||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.c
|
${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/files.c
|
${CMAKE_CURRENT_LIST_DIR}/src/fido/files.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/fido/kek.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c
|
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_authenticate.c
|
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_authenticate.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_version.c
|
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_version.c
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "crypto_utils.h"
|
#include "crypto_utils.h"
|
||||||
#include "pico_keys.h"
|
#include "pico_keys.h"
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
|
#include "kek.h"
|
||||||
|
|
||||||
uint32_t usage_timer = 0, initial_usage_time_limit = 0;
|
uint32_t usage_timer = 0, initial_usage_time_limit = 0;
|
||||||
uint32_t max_usage_time_period = 600 * 1000;
|
uint32_t max_usage_time_period = 600 * 1000;
|
||||||
@@ -279,6 +280,21 @@ int pinUvAuthTokenUsageTimerObserver() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int check_mkek_encrypted(const uint8_t *dhash) {
|
||||||
|
if (file_get_size(ef_mkek) == MKEK_IV_SIZE + MKEK_KEY_SIZE) {
|
||||||
|
hash_multi(dhash, 16, session_pin); // Only for storing MKEK
|
||||||
|
uint8_t mkek[MKEK_SIZE] = {0};
|
||||||
|
memcpy(mkek, file_get_data(ef_mkek), MKEK_IV_SIZE + MKEK_KEY_SIZE);
|
||||||
|
int ret = store_mkek(mkek);
|
||||||
|
mbedtls_platform_zeroize(mkek, sizeof(mkek));
|
||||||
|
mbedtls_platform_zeroize(session_pin, sizeof(session_pin));
|
||||||
|
if (ret != PICOKEY_OK) {
|
||||||
|
return CTAP2_ERR_PIN_AUTH_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PICOKEY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t new_pin_mismatches = 0;
|
uint8_t new_pin_mismatches = 0;
|
||||||
|
|
||||||
int cbor_client_pin(const uint8_t *data, size_t len) {
|
int cbor_client_pin(const uint8_t *data, size_t len) {
|
||||||
@@ -415,12 +431,20 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
|
|||||||
if (pin_len < minPin) {
|
if (pin_len < minPin) {
|
||||||
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
|
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
|
||||||
}
|
}
|
||||||
uint8_t hsh[34];
|
uint8_t hsh[34], dhash[32];
|
||||||
hsh[0] = MAX_PIN_RETRIES;
|
hsh[0] = MAX_PIN_RETRIES;
|
||||||
hsh[1] = pin_len;
|
hsh[1] = pin_len;
|
||||||
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2);
|
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash);
|
||||||
file_put_data(ef_pin, hsh, 2 + 16);
|
double_hash_pin(dhash, 16, hsh + 2);
|
||||||
|
file_put_data(ef_pin, hsh, 2 + 32);
|
||||||
low_flash_available();
|
low_flash_available();
|
||||||
|
|
||||||
|
ret = check_mkek_encrypted(dhash);
|
||||||
|
if (ret != PICOKEY_OK) {
|
||||||
|
CBOR_ERROR(ret);
|
||||||
|
}
|
||||||
|
mbedtls_platform_zeroize(hsh, sizeof(hsh));
|
||||||
|
mbedtls_platform_zeroize(dhash, sizeof(dhash));
|
||||||
goto err; //No return
|
goto err; //No return
|
||||||
}
|
}
|
||||||
else if (subcommand == 0x4) { //changePIN
|
else if (subcommand == 0x4) { //changePIN
|
||||||
@@ -462,8 +486,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
|
|||||||
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
||||||
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
|
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
|
||||||
}
|
}
|
||||||
uint8_t pin_data[18];
|
uint8_t pin_data[34];
|
||||||
memcpy(pin_data, file_get_data(ef_pin), 18);
|
memcpy(pin_data, file_get_data(ef_pin), 34);
|
||||||
pin_data[0] -= 1;
|
pin_data[0] -= 1;
|
||||||
file_put_data(ef_pin, pin_data, sizeof(pin_data));
|
file_put_data(ef_pin, pin_data, sizeof(pin_data));
|
||||||
low_flash_available();
|
low_flash_available();
|
||||||
@@ -474,7 +498,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
|
|||||||
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
||||||
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
|
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
|
||||||
}
|
}
|
||||||
if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) {
|
uint8_t dhash[32];
|
||||||
|
double_hash_pin(paddedNewPin, 16, dhash);
|
||||||
|
if (memcmp(dhash, file_get_data(ef_pin) + 2, 32) != 0) {
|
||||||
regenerate();
|
regenerate();
|
||||||
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
||||||
if (retries == 0) {
|
if (retries == 0) {
|
||||||
@@ -488,6 +514,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
|
|||||||
CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
|
CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hash_multi(paddedNewPin, 16, session_pin);
|
||||||
pin_data[0] = MAX_PIN_RETRIES;
|
pin_data[0] = MAX_PIN_RETRIES;
|
||||||
file_put_data(ef_pin, pin_data, sizeof(pin_data));
|
file_put_data(ef_pin, pin_data, sizeof(pin_data));
|
||||||
low_flash_available();
|
low_flash_available();
|
||||||
@@ -515,12 +542,33 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
|
|||||||
uint8_t hsh[34];
|
uint8_t hsh[34];
|
||||||
hsh[0] = MAX_PIN_RETRIES;
|
hsh[0] = MAX_PIN_RETRIES;
|
||||||
hsh[1] = pin_len;
|
hsh[1] = pin_len;
|
||||||
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2);
|
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash);
|
||||||
|
double_hash_pin(dhash, 16, hsh + 2);
|
||||||
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 &&
|
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 &&
|
||||||
memcmp(hsh + 2, file_get_data(ef_pin) + 2, 16) == 0) {
|
memcmp(hsh + 2, file_get_data(ef_pin) + 2, 32) == 0) {
|
||||||
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
|
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
|
||||||
}
|
}
|
||||||
file_put_data(ef_pin, hsh, 2 + 16);
|
|
||||||
|
uint8_t mkek[MKEK_SIZE] = {0};
|
||||||
|
ret = load_mkek(mkek);
|
||||||
|
if (ret != PICOKEY_OK) {
|
||||||
|
CBOR_ERROR(ret);
|
||||||
|
}
|
||||||
|
file_put_data(ef_pin, hsh, 2 + 32);
|
||||||
|
|
||||||
|
ret = check_mkek_encrypted(dhash);
|
||||||
|
if (ret != PICOKEY_OK) {
|
||||||
|
CBOR_ERROR(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_multi(dhash, 16, session_pin);
|
||||||
|
ret = store_mkek(mkek);
|
||||||
|
mbedtls_platform_zeroize(mkek, sizeof(mkek));
|
||||||
|
if (ret != PICOKEY_OK) {
|
||||||
|
CBOR_ERROR(ret);
|
||||||
|
}
|
||||||
|
mbedtls_platform_zeroize(hsh, sizeof(hsh));
|
||||||
|
mbedtls_platform_zeroize(dhash, sizeof(dhash));
|
||||||
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
|
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
|
||||||
uint8_t *tmpf = (uint8_t *) calloc(1, file_get_size(ef_minpin));
|
uint8_t *tmpf = (uint8_t *) calloc(1, file_get_size(ef_minpin));
|
||||||
memcpy(tmpf, file_get_data(ef_minpin), file_get_size(ef_minpin));
|
memcpy(tmpf, file_get_data(ef_minpin), file_get_size(ef_minpin));
|
||||||
@@ -570,8 +618,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
|
|||||||
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
||||||
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
|
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
|
||||||
}
|
}
|
||||||
uint8_t pin_data[18];
|
uint8_t pin_data[34];
|
||||||
memcpy(pin_data, file_get_data(ef_pin), 18);
|
memcpy(pin_data, file_get_data(ef_pin), 34);
|
||||||
pin_data[0] -= 1;
|
pin_data[0] -= 1;
|
||||||
file_put_data(ef_pin, pin_data, sizeof(pin_data));
|
file_put_data(ef_pin, pin_data, sizeof(pin_data));
|
||||||
low_flash_available();
|
low_flash_available();
|
||||||
@@ -582,7 +630,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
|
|||||||
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
||||||
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
|
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
|
||||||
}
|
}
|
||||||
if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) {
|
uint8_t dhash[32];
|
||||||
|
double_hash_pin(paddedNewPin, 16, dhash);
|
||||||
|
if (memcmp(dhash, file_get_data(ef_pin) + 2, 32) != 0) {
|
||||||
regenerate();
|
regenerate();
|
||||||
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
|
||||||
if (retries == 0) {
|
if (retries == 0) {
|
||||||
@@ -596,9 +646,19 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
|
|||||||
CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
|
CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = check_mkek_encrypted(paddedNewPin);
|
||||||
|
if (ret != PICOKEY_OK) {
|
||||||
|
CBOR_ERROR(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_multi(paddedNewPin, 16, session_pin);
|
||||||
pin_data[0] = MAX_PIN_RETRIES;
|
pin_data[0] = MAX_PIN_RETRIES;
|
||||||
new_pin_mismatches = 0;
|
new_pin_mismatches = 0;
|
||||||
file_put_data(ef_pin, pin_data, sizeof(pin_data));
|
file_put_data(ef_pin, pin_data, sizeof(pin_data));
|
||||||
|
mbedtls_platform_zeroize(pin_data, sizeof(pin_data));
|
||||||
|
mbedtls_platform_zeroize(dhash, sizeof(dhash));
|
||||||
|
|
||||||
low_flash_available();
|
low_flash_available();
|
||||||
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
|
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
|
||||||
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
|
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fido.h"
|
#include "fido.h"
|
||||||
|
#include "kek.h"
|
||||||
#include "pico_keys.h"
|
#include "pico_keys.h"
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
#include "ctap.h"
|
#include "ctap.h"
|
||||||
@@ -46,6 +47,7 @@ pinUvAuthToken_t paut = { 0 };
|
|||||||
|
|
||||||
uint8_t keydev_dec[32];
|
uint8_t keydev_dec[32];
|
||||||
bool has_keydev_dec = false;
|
bool has_keydev_dec = false;
|
||||||
|
uint8_t session_pin[32] = { 0 };
|
||||||
|
|
||||||
const uint8_t fido_aid[] = {
|
const uint8_t fido_aid[] = {
|
||||||
8,
|
8,
|
||||||
@@ -188,12 +190,15 @@ int load_keydev(uint8_t *key) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memcpy(key, file_get_data(ef_keydev), file_get_size(ef_keydev));
|
memcpy(key, file_get_data(ef_keydev), file_get_size(ef_keydev));
|
||||||
|
|
||||||
|
if (mkek_decrypt(key, 32) != PICOKEY_OK) {
|
||||||
|
return PICOKEY_EXEC_ERROR;
|
||||||
|
}
|
||||||
if (otp_key_1 && aes_decrypt(otp_key_1, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, key, 32) != PICOKEY_OK) {
|
if (otp_key_1 && aes_decrypt(otp_key_1, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, key, 32) != PICOKEY_OK) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
return PICOKEY_EXEC_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//return mkek_decrypt(key, file_get_size(ef_keydev));
|
|
||||||
return PICOKEY_OK;
|
return PICOKEY_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,6 +289,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
|
|||||||
int scan_files() {
|
int scan_files() {
|
||||||
ef_keydev = search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF);
|
ef_keydev = search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF);
|
||||||
ef_keydev_enc = search_by_fid(EF_KEY_DEV_ENC, NULL, SPECIFY_EF);
|
ef_keydev_enc = search_by_fid(EF_KEY_DEV_ENC, NULL, SPECIFY_EF);
|
||||||
|
ef_mkek = search_by_fid(EF_MKEK, NULL, SPECIFY_EF);
|
||||||
if (ef_keydev) {
|
if (ef_keydev) {
|
||||||
if (!file_has_data(ef_keydev) && !file_has_data(ef_keydev_enc)) {
|
if (!file_has_data(ef_keydev) && !file_has_data(ef_keydev_enc)) {
|
||||||
printf("KEY DEVICE is empty. Generating SECP256R1 curve...");
|
printf("KEY DEVICE is empty. Generating SECP256R1 curve...");
|
||||||
@@ -354,6 +360,13 @@ int scan_files() {
|
|||||||
printf("FATAL ERROR: Global counter not found in memory!\r\n");
|
printf("FATAL ERROR: Global counter not found in memory!\r\n");
|
||||||
}
|
}
|
||||||
ef_pin = search_by_fid(EF_PIN, NULL, SPECIFY_EF);
|
ef_pin = search_by_fid(EF_PIN, NULL, SPECIFY_EF);
|
||||||
|
if (file_get_size(ef_pin) == 18) { // Upgrade PIN storage
|
||||||
|
uint8_t pin_data[34] = { 0 }, dhash[32];
|
||||||
|
memcpy(pin_data, file_get_data(ef_pin), 18);
|
||||||
|
double_hash_pin(pin_data + 2, 16, dhash);
|
||||||
|
memcpy(pin_data + 2, dhash, 32);
|
||||||
|
file_put_data(ef_pin, pin_data, 34);
|
||||||
|
}
|
||||||
ef_authtoken = search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF);
|
ef_authtoken = search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF);
|
||||||
if (ef_authtoken) {
|
if (ef_authtoken) {
|
||||||
if (!file_has_data(ef_authtoken)) {
|
if (!file_has_data(ef_authtoken)) {
|
||||||
@@ -371,6 +384,22 @@ int scan_files() {
|
|||||||
if (!file_has_data(ef_largeblob)) {
|
if (!file_has_data(ef_largeblob)) {
|
||||||
file_put_data(ef_largeblob, (const uint8_t *) "\x80\x76\xbe\x8b\x52\x8d\x00\x75\xf7\xaa\xe9\x8d\x6f\xa5\x7a\x6d\x3c", 17);
|
file_put_data(ef_largeblob, (const uint8_t *) "\x80\x76\xbe\x8b\x52\x8d\x00\x75\xf7\xaa\xe9\x8d\x6f\xa5\x7a\x6d\x3c", 17);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ef_mkek) { // No encrypted MKEK
|
||||||
|
if (!file_has_data(ef_mkek)) {
|
||||||
|
uint8_t mkek[MKEK_IV_SIZE + MKEK_KEY_SIZE];
|
||||||
|
random_gen(NULL, mkek, sizeof(mkek));
|
||||||
|
file_put_data(ef_mkek, mkek, sizeof(mkek));
|
||||||
|
int ret = aes_encrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), file_get_data(ef_keydev), 32);
|
||||||
|
mbedtls_platform_zeroize(mkek, sizeof(mkek));
|
||||||
|
if (ret != 0) {
|
||||||
|
printf("FATAL ERROR: MKEK encryption failed!\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("FATAL ERROR: MKEK not found in memory!\r\n");
|
||||||
|
}
|
||||||
low_flash_available();
|
low_flash_available();
|
||||||
return PICOKEY_OK;
|
return PICOKEY_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,4 +130,6 @@ extern uint32_t user_present_time_limit;
|
|||||||
extern pinUvAuthToken_t paut;
|
extern pinUvAuthToken_t paut;
|
||||||
extern int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t len, uint8_t *sign);
|
extern int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t len, uint8_t *sign);
|
||||||
|
|
||||||
|
extern uint8_t session_pin[32];
|
||||||
|
|
||||||
#endif //_FIDO_H
|
#endif //_FIDO_H
|
||||||
|
|||||||
@@ -18,39 +18,20 @@
|
|||||||
#include "files.h"
|
#include "files.h"
|
||||||
|
|
||||||
file_t file_entries[] = {
|
file_t file_entries[] = {
|
||||||
{ .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL,
|
{ .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = { 0 } }, // MF
|
||||||
.ef_structure = 0, .acl = { 0 } }, // MF
|
{ .fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key
|
||||||
{ .fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
{ .fid = EF_KEY_DEV_ENC, .parent = 0, .name = NULL,.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key Enc
|
||||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key
|
{ .fid = EF_MKEK, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MKEK
|
||||||
{ .fid = EF_KEY_DEV_ENC, .parent = 0, .name = NULL,
|
{ .fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device
|
||||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
{ .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate
|
||||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key Enc
|
{ .fid = EF_COUNTER, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter
|
||||||
{ .fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
{ .fid = EF_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // PIN
|
||||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device
|
{ .fid = EF_AUTHTOKEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // AUTH TOKEN
|
||||||
{ .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL,
|
{ .fid = EF_MINPINLEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MIN PIN LENGTH
|
||||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
{ .fid = EF_OPTS, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global options
|
||||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate
|
{ .fid = EF_LARGEBLOB, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Large Blob
|
||||||
{ .fid = EF_COUNTER, .parent = 0, .name = NULL,
|
{ .fid = EF_OTP_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } },
|
||||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL, .ef_structure = 0, .acl = { 0 } } //end
|
||||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter
|
|
||||||
{ .fid = EF_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
|
||||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // PIN
|
|
||||||
{ .fid = EF_AUTHTOKEN, .parent = 0, .name = NULL,
|
|
||||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
|
||||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // AUTH TOKEN
|
|
||||||
{ .fid = EF_MINPINLEN, .parent = 0, .name = NULL,
|
|
||||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
|
||||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MIN PIN LENGTH
|
|
||||||
{ .fid = EF_OPTS, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
|
||||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global options
|
|
||||||
{ .fid = EF_LARGEBLOB, .parent = 0, .name = NULL,
|
|
||||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
|
||||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Large Blob
|
|
||||||
{ .fid = EF_OTP_PIN, .parent = 0, .name = NULL,
|
|
||||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
|
||||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } },
|
|
||||||
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL,
|
|
||||||
.ef_structure = 0, .acl = { 0 } } //end
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const file_t *MF = &file_entries[0];
|
const file_t *MF = &file_entries[0];
|
||||||
@@ -62,3 +43,4 @@ file_t *ef_pin = NULL;
|
|||||||
file_t *ef_authtoken = NULL;
|
file_t *ef_authtoken = NULL;
|
||||||
file_t *ef_keydev_enc = NULL;
|
file_t *ef_keydev_enc = NULL;
|
||||||
file_t *ef_largeblob = NULL;
|
file_t *ef_largeblob = NULL;
|
||||||
|
file_t *ef_mkek = NULL;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#define EF_KEY_DEV 0xCC00
|
#define EF_KEY_DEV 0xCC00
|
||||||
#define EF_KEY_DEV_ENC 0xCC01
|
#define EF_KEY_DEV_ENC 0xCC01
|
||||||
|
#define EF_MKEK 0xCC0F
|
||||||
#define EF_EE_DEV 0xCE00
|
#define EF_EE_DEV 0xCE00
|
||||||
#define EF_EE_DEV_EA 0xCE01
|
#define EF_EE_DEV_EA 0xCE01
|
||||||
#define EF_COUNTER 0xC000
|
#define EF_COUNTER 0xC000
|
||||||
@@ -46,5 +47,6 @@ extern file_t *ef_pin;
|
|||||||
extern file_t *ef_authtoken;
|
extern file_t *ef_authtoken;
|
||||||
extern file_t *ef_keydev_enc;
|
extern file_t *ef_keydev_enc;
|
||||||
extern file_t *ef_largeblob;
|
extern file_t *ef_largeblob;
|
||||||
|
extern file_t *ef_mkek;
|
||||||
|
|
||||||
#endif //_FILES_H_
|
#endif //_FILES_H_
|
||||||
|
|||||||
138
src/fido/kek.c
Normal file
138
src/fido/kek.c
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico Fido distribution (https://github.com/polhenarejos/pico-fido).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fido.h"
|
||||||
|
#include "pico_keys.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#endif
|
||||||
|
#include "kek.h"
|
||||||
|
#include "crypto_utils.h"
|
||||||
|
#include "random.h"
|
||||||
|
#include "mbedtls/md.h"
|
||||||
|
#include "mbedtls/cmac.h"
|
||||||
|
#include "mbedtls/rsa.h"
|
||||||
|
#include "mbedtls/ecdsa.h"
|
||||||
|
#include "mbedtls/chachapoly.h"
|
||||||
|
#include "files.h"
|
||||||
|
#include "otp.h"
|
||||||
|
|
||||||
|
extern uint8_t session_pin[32];
|
||||||
|
uint8_t mkek_mask[MKEK_KEY_SIZE];
|
||||||
|
bool has_mkek_mask = false;
|
||||||
|
|
||||||
|
#define POLY 0xedb88320
|
||||||
|
|
||||||
|
uint32_t crc32c(const uint8_t *buf, size_t len) {
|
||||||
|
uint32_t crc = 0xffffffff;
|
||||||
|
while (len--) {
|
||||||
|
crc ^= *buf++;
|
||||||
|
for (int k = 0; k < 8; k++) {
|
||||||
|
crc = (crc >> 1) ^ (POLY & (0 - (crc & 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ~crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mkek_masked(uint8_t *mkek, const uint8_t *mask) {
|
||||||
|
if (mask) {
|
||||||
|
for (int i = 0; i < MKEK_KEY_SIZE; i++) {
|
||||||
|
MKEK_KEY(mkek)[i] ^= mask[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#include <stdio.h>
|
||||||
|
int load_mkek(uint8_t *mkek) {
|
||||||
|
if (paut.in_use == false) {
|
||||||
|
return PICOKEY_NO_LOGIN;
|
||||||
|
}
|
||||||
|
file_t *tf = search_file(EF_MKEK);
|
||||||
|
printf("file_size = %d\n", file_get_size(tf));
|
||||||
|
if (file_has_data(tf)) {
|
||||||
|
memcpy(mkek, file_get_data(tf), MKEK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_mkek_mask) {
|
||||||
|
mkek_masked(mkek, mkek_mask);
|
||||||
|
}
|
||||||
|
if (file_get_size(tf) == MKEK_SIZE) {
|
||||||
|
int ret = aes_decrypt_cfb_256(session_pin, MKEK_IV(mkek), MKEK_KEY(mkek), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
|
||||||
|
if (ret != 0) {
|
||||||
|
return PICOKEY_EXEC_ERROR;
|
||||||
|
}
|
||||||
|
if (crc32c(MKEK_KEY(mkek), MKEK_KEY_SIZE) != *(uint32_t *) MKEK_CHECKSUM(mkek)) {
|
||||||
|
return PICOKEY_WRONG_DKEK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (otp_key_1) {
|
||||||
|
mkek_masked(mkek, otp_key_1);
|
||||||
|
}
|
||||||
|
return PICOKEY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void release_mkek(uint8_t *mkek) {
|
||||||
|
mbedtls_platform_zeroize(mkek, MKEK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int store_mkek(const uint8_t *mkek) {
|
||||||
|
uint8_t tmp_mkek[MKEK_SIZE];
|
||||||
|
if (mkek == NULL) {
|
||||||
|
const uint8_t *rd = random_bytes_get(MKEK_IV_SIZE + MKEK_KEY_SIZE);
|
||||||
|
memcpy(tmp_mkek, rd, MKEK_IV_SIZE + MKEK_KEY_SIZE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(tmp_mkek, mkek, MKEK_SIZE);
|
||||||
|
}
|
||||||
|
*(uint32_t *) MKEK_CHECKSUM(tmp_mkek) = crc32c(MKEK_KEY(tmp_mkek), MKEK_KEY_SIZE);
|
||||||
|
uint8_t tmp_mkek_pin[MKEK_SIZE];
|
||||||
|
memcpy(tmp_mkek_pin, tmp_mkek, MKEK_SIZE);
|
||||||
|
file_t *tf = search_file(EF_MKEK);
|
||||||
|
if (!tf) {
|
||||||
|
release_mkek(tmp_mkek);
|
||||||
|
release_mkek(tmp_mkek_pin);
|
||||||
|
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
aes_encrypt_cfb_256(session_pin, MKEK_IV(tmp_mkek_pin), MKEK_KEY(tmp_mkek_pin), MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE);
|
||||||
|
file_put_data(tf, tmp_mkek_pin, MKEK_SIZE);
|
||||||
|
release_mkek(tmp_mkek_pin);
|
||||||
|
low_flash_available();
|
||||||
|
release_mkek(tmp_mkek);
|
||||||
|
return PICOKEY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mkek_encrypt(uint8_t *data, uint16_t len) {
|
||||||
|
int r;
|
||||||
|
uint8_t mkek[MKEK_SIZE + 4];
|
||||||
|
if ((r = load_mkek(mkek)) != PICOKEY_OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = aes_encrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), data, len);
|
||||||
|
release_mkek(mkek);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mkek_decrypt(uint8_t *data, uint16_t len) {
|
||||||
|
int r;
|
||||||
|
uint8_t mkek[MKEK_SIZE + 4];
|
||||||
|
if ((r = load_mkek(mkek)) != PICOKEY_OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = aes_decrypt_cfb_256(MKEK_KEY(mkek), MKEK_IV(mkek), data, len);
|
||||||
|
release_mkek(mkek);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
46
src/fido/kek.h
Normal file
46
src/fido/kek.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico Fido distribution (https://github.com/polhenarejos/pico-fido).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _KEK_H_
|
||||||
|
#define _KEK_H_
|
||||||
|
|
||||||
|
#include "crypto_utils.h"
|
||||||
|
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
extern int load_mkek(uint8_t *);
|
||||||
|
extern int store_mkek(const uint8_t *);
|
||||||
|
extern void init_mkek();
|
||||||
|
extern void release_mkek(uint8_t *);
|
||||||
|
extern int mkek_encrypt(uint8_t *data, uint16_t len);
|
||||||
|
extern int mkek_decrypt(uint8_t *data, uint16_t len);
|
||||||
|
|
||||||
|
#define MKEK_IV_SIZE (IV_SIZE)
|
||||||
|
#define MKEK_KEY_SIZE (32)
|
||||||
|
#define MKEK_KEY_CS_SIZE (4)
|
||||||
|
#define MKEK_SIZE (MKEK_IV_SIZE + MKEK_KEY_SIZE + MKEK_KEY_CS_SIZE)
|
||||||
|
#define MKEK_IV(p) (p)
|
||||||
|
#define MKEK_KEY(p) (MKEK_IV(p) + MKEK_IV_SIZE)
|
||||||
|
#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;
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user