From 6a678000570ccf95dbc67446a0fe4fdddfc5f28e Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Fri, 3 Jan 2025 01:20:58 +0100 Subject: [PATCH] Add support for PIN hash storage and MKEK. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 3 + src/fido/cbor_client_pin.c | 84 ++++++++++++++++++---- src/fido/fido.c | 31 ++++++++- src/fido/fido.h | 2 + src/fido/files.c | 48 ++++--------- src/fido/files.h | 2 + src/fido/kek.c | 138 +++++++++++++++++++++++++++++++++++++ src/fido/kek.h | 46 +++++++++++++ 8 files changed, 308 insertions(+), 46 deletions(-) create mode 100644 src/fido/kek.c create mode 100644 src/fido/kek.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a01ac9c..3ce3d40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,8 @@ cmake_minimum_required(VERSION 3.13) if(ESP_PLATFORM) +set(DEBUG_APDU 1) +set(DENABLE_POWER_ON_RESET 0) set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src) include($ENV{IDF_PATH}/tools/cmake/project.cmake) else() @@ -77,6 +79,7 @@ endif() set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.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_authenticate.c ${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_version.c diff --git a/src/fido/cbor_client_pin.c b/src/fido/cbor_client_pin.c index d0adfa9..1ceb701 100644 --- a/src/fido/cbor_client_pin.c +++ b/src/fido/cbor_client_pin.c @@ -37,6 +37,7 @@ #include "crypto_utils.h" #include "pico_keys.h" #include "apdu.h" +#include "kek.h" uint32_t usage_timer = 0, initial_usage_time_limit = 0; uint32_t max_usage_time_period = 600 * 1000; @@ -279,6 +280,21 @@ int pinUvAuthTokenUsageTimerObserver() { 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; 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) { CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); } - uint8_t hsh[34]; + uint8_t hsh[34], dhash[32]; hsh[0] = MAX_PIN_RETRIES; hsh[1] = pin_len; - mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2); - file_put_data(ef_pin, hsh, 2 + 16); + mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash); + double_hash_pin(dhash, 16, hsh + 2); + file_put_data(ef_pin, hsh, 2 + 32); 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 } 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)); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); } - uint8_t pin_data[18]; - memcpy(pin_data, file_get_data(ef_pin), 18); + uint8_t pin_data[34]; + memcpy(pin_data, file_get_data(ef_pin), 34); pin_data[0] -= 1; file_put_data(ef_pin, pin_data, sizeof(pin_data)); low_flash_available(); @@ -474,7 +498,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) { mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); 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(); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); if (retries == 0) { @@ -488,6 +514,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) { CBOR_ERROR(CTAP2_ERR_PIN_INVALID); } } + hash_multi(paddedNewPin, 16, session_pin); pin_data[0] = MAX_PIN_RETRIES; file_put_data(ef_pin, pin_data, sizeof(pin_data)); low_flash_available(); @@ -515,12 +542,33 @@ int cbor_client_pin(const uint8_t *data, size_t len) { uint8_t hsh[34]; hsh[0] = MAX_PIN_RETRIES; 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 && - 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); } - 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) { uint8_t *tmpf = (uint8_t *) calloc(1, 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)); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); } - uint8_t pin_data[18]; - memcpy(pin_data, file_get_data(ef_pin), 18); + uint8_t pin_data[34]; + memcpy(pin_data, file_get_data(ef_pin), 34); pin_data[0] -= 1; file_put_data(ef_pin, pin_data, sizeof(pin_data)); low_flash_available(); @@ -582,7 +630,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) { mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); 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(); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); if (retries == 0) { @@ -596,9 +646,19 @@ int cbor_client_pin(const uint8_t *data, size_t len) { 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; new_pin_mismatches = 0; 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(); 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) { diff --git a/src/fido/fido.c b/src/fido/fido.c index 6ef148f..7566989 100644 --- a/src/fido/fido.c +++ b/src/fido/fido.c @@ -16,6 +16,7 @@ */ #include "fido.h" +#include "kek.h" #include "pico_keys.h" #include "apdu.h" #include "ctap.h" @@ -46,6 +47,7 @@ pinUvAuthToken_t paut = { 0 }; uint8_t keydev_dec[32]; bool has_keydev_dec = false; +uint8_t session_pin[32] = { 0 }; const uint8_t fido_aid[] = { 8, @@ -188,12 +190,15 @@ int load_keydev(uint8_t *key) { } else { 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) { return PICOKEY_EXEC_ERROR; } } - //return mkek_decrypt(key, file_get_size(ef_keydev)); 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() { 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_mkek = search_by_fid(EF_MKEK, NULL, SPECIFY_EF); if (ef_keydev) { if (!file_has_data(ef_keydev) && !file_has_data(ef_keydev_enc)) { 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"); } 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); if (ef_authtoken) { if (!file_has_data(ef_authtoken)) { @@ -371,6 +384,22 @@ int scan_files() { 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); } + + 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(); return PICOKEY_OK; } diff --git a/src/fido/fido.h b/src/fido/fido.h index a27f2b0..4666fda 100644 --- a/src/fido/fido.h +++ b/src/fido/fido.h @@ -130,4 +130,6 @@ extern uint32_t user_present_time_limit; 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 uint8_t session_pin[32]; + #endif //_FIDO_H diff --git a/src/fido/files.c b/src/fido/files.c index 11573c5..bf403bd 100644 --- a/src/fido/files.c +++ b/src/fido/files.c @@ -18,39 +18,20 @@ #include "files.h" file_t file_entries[] = { - { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, - .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_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 - { .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 - { .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 - { .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_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 + { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .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_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 + { .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_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 + { .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 + { .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_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]; @@ -62,3 +43,4 @@ file_t *ef_pin = NULL; file_t *ef_authtoken = NULL; file_t *ef_keydev_enc = NULL; file_t *ef_largeblob = NULL; +file_t *ef_mkek = NULL; diff --git a/src/fido/files.h b/src/fido/files.h index 328eb13..93ceec9 100644 --- a/src/fido/files.h +++ b/src/fido/files.h @@ -22,6 +22,7 @@ #define EF_KEY_DEV 0xCC00 #define EF_KEY_DEV_ENC 0xCC01 +#define EF_MKEK 0xCC0F #define EF_EE_DEV 0xCE00 #define EF_EE_DEV_EA 0xCE01 #define EF_COUNTER 0xC000 @@ -46,5 +47,6 @@ extern file_t *ef_pin; extern file_t *ef_authtoken; extern file_t *ef_keydev_enc; extern file_t *ef_largeblob; +extern file_t *ef_mkek; #endif //_FILES_H_ diff --git a/src/fido/kek.c b/src/fido/kek.c new file mode 100644 index 0000000..69a9edc --- /dev/null +++ b/src/fido/kek.c @@ -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 . + */ + +#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 +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; +} diff --git a/src/fido/kek.h b/src/fido/kek.h new file mode 100644 index 0000000..4cb1e11 --- /dev/null +++ b/src/fido/kek.h @@ -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 . + */ + +#ifndef _KEK_H_ +#define _KEK_H_ + +#include "crypto_utils.h" +#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM) +#include +#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