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