From 108cfec47c8b72472acbf6d3f8cc50260bfb09bd Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 11 Sep 2024 23:16:23 +0200 Subject: [PATCH] Enable OTP to store a permanent secret key. It can be used by HSM or Fido to protect the keys and use it as MKEK. --- pico_keys_sdk_import.cmake | 2 + src/fs/otp.c | 100 +++++++++++++++++++++++++++++++++++++ src/fs/otp.h | 32 ++++++++++++ src/main.c | 4 ++ 4 files changed, 138 insertions(+) create mode 100644 src/fs/otp.c create mode 100644 src/fs/otp.h diff --git a/pico_keys_sdk_import.cmake b/pico_keys_sdk_import.cmake index 0ade7d5..2e4ce0d 100644 --- a/pico_keys_sdk_import.cmake +++ b/pico_keys_sdk_import.cmake @@ -202,6 +202,7 @@ set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c ${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c ${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c + ${CMAKE_CURRENT_LIST_DIR}/src/fs/otp.c ${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c ${CMAKE_CURRENT_LIST_DIR}/src/rng/hwrng.c ${CMAKE_CURRENT_LIST_DIR}/src/eac.c @@ -362,6 +363,7 @@ if(PICO_RP2350) pico_sign_binary(${CMAKE_PROJECT_NAME} ${SECURE_BOOT_PKEY}) pico_hash_binary(${CMAKE_PROJECT_NAME}) endif() + target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE pico_bootrom) endif() set(INTERNAL_SOURCES ${SOURCES}) set(SOURCES ${SOURCES} ${EXTERNAL_SOURCES}) diff --git a/src/fs/otp.c b/src/fs/otp.c new file mode 100644 index 0000000..9b1279a --- /dev/null +++ b/src/fs/otp.c @@ -0,0 +1,100 @@ +/* + * This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). + * 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 "file.h" +#include "pico_keys.h" +#include +#include "otp.h" + +#ifdef PICO_RP2350 +#include "pico/bootrom.h" +#include "hardware/structs/otp.h" +#include "hardware/regs/otp_data.h" +#endif +#include "random.h" + +#ifdef PICO_RP2350 + +static bool is_empty_buffer(const uint8_t *buffer, uint16_t buffer_len) { + for (int i = 0; i < buffer_len; i++) { + if (buffer[i] != 0x00) { + return false; + } + } + return true; +} + +static int otp_write_data_mode(uint16_t row, uint8_t *data, uint16_t len, bool is_ecc) { + otp_cmd_t cmd = { .flags = row | (is_ecc ? OTP_CMD_ECC_BITS : 0) | OTP_CMD_WRITE_BITS }; + uint32_t ret = rom_func_otp_access(data, len, cmd); + if (ret) { + printf("OTP Write failed with error: %ld\n", ret); + } + return ret; +} + +static int otp_write_data(uint16_t row, uint8_t *data, uint16_t len) { + return otp_write_data_mode(row, data, len, true); +} +/* +static int otp_write_data_raw(uint16_t row, uint8_t *data, uint16_t len) { + return otp_write_data_mode(row, data, len, false); +} +*/ +static uint8_t* otp_buffer(uint16_t row) { + volatile uint32_t *p = ((uint32_t *)(OTP_DATA_GUARDED_BASE + (row*2))); + return (uint8_t *)p; +} + +static bool is_empty_otp_buffer(uint16_t row, uint16_t len) { + return is_empty_buffer(otp_buffer(row), len); +} + +static bool is_otp_locked_page(uint8_t page) { + volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + ((OTP_DATA_PAGE0_LOCK0_ROW + page*2)*2))); + return ((p[0] & 0xFFFF0000) == 0x3C3C0000 && (p[1] & 0xFF) == 0x3C); +} + +static void otp_lock_page(uint8_t page) { + if (!is_otp_locked_page(page)) { + uint32_t value = 0x3c3c3c; + printf("Locking page %d, with row %d and value %lx\n", page, OTP_DATA_PAGE0_LOCK0_ROW + page*2 + 1, value); + //otp_write_data_raw(OTP_DATA_PAGE0_LOCK0_ROW + page*2 + 1, (uint8_t *)&value, sizeof(value)); + } + + otp_hw->sw_lock[page] = 0b1100; +} +#endif + +const uint8_t *otp_key_1 = NULL; +void init_otp_files() { +#ifdef PICO_RP2350 + + uint8_t page = OTP_KEY_1 >> 6; + if (is_empty_otp_buffer(OTP_KEY_1, 32)) { + uint8_t mkek[32] = {0}; + random_gen(NULL, mkek, sizeof(mkek)); + otp_write_data(OTP_KEY_1, mkek, sizeof(mkek)); + } + else { + DEBUG_DATA(otp_buffer(OTP_KEY_1), 32); + } + otp_key_1 = otp_buffer(OTP_KEY_1); + + otp_lock_page(page); +#endif +} diff --git a/src/fs/otp.h b/src/fs/otp.h new file mode 100644 index 0000000..bac4faa --- /dev/null +++ b/src/fs/otp.h @@ -0,0 +1,32 @@ +/* + * This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). + * 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 _OTP_H_ +#define _OTP_H_ + +#ifdef PICO_RP2350 + +#define OTP_TEST_ROW 0xEF0 + +#define OTP_KEY_1 OTP_TEST_ROW + +#endif + +extern const uint8_t *otp_key_1; + +#endif // _OTP_H_ diff --git a/src/main.c b/src/main.c index 7e4586e..cf7b9fd 100644 --- a/src/main.c +++ b/src/main.c @@ -45,6 +45,7 @@ #include "usb.h" extern void do_flash(); extern void low_flash_init(); +extern void init_otp_files(); app_t apps[4]; uint8_t num_apps = 0; @@ -296,6 +297,8 @@ int main(void) { random_init(); + init_otp_files(); + low_flash_init(); scan_flash(); @@ -303,6 +306,7 @@ int main(void) { init_rtc(); usb_init(); + #ifndef ENABLE_EMULATION #ifdef ESP_PLATFORM gpio_pad_select_gpio(BOOT_PIN);