Author SHA1 Message Date
Fabrice Bellamy fcb453f459 Update product name in USB descriptor 2026-03-03 10:52:55 +01:00
Fabrice BellamyandGitHub 7d9be9c7bd Merge pull request #3 from librekeys/feat/librekeys-patches
feat: Update usb descriptors to librekeys url and info
2026-03-03 00:19:13 +01:00
Fabrice BellamyandGitHub 08cab0c0b1 Update product name in USB descriptor 2026-03-03 00:18:48 +01:00
Suyog Tandel f78c0594fc feat: update string descriptors and url in usb-descriptors.c 2026-02-28 01:04:22 +05:30
Suyog Tandel 5ee971ec73 Merge branch 'main' into feat/librekeys-patches 2026-02-28 00:59:35 +05:30
Pol HenarejosandFabrice Bellamy 7723b2c53e Fix phy marker write.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-27 18:48:02 +01:00
Pol HenarejosandFabrice Bellamy 32e7e5cb75 Fix res_APDU size.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-27 18:48:02 +01:00
Pol HenarejosandFabrice Bellamy 40cf563a92 Rename pico key sdk project to pico_rescue.
This is a minimal firmware for rescue.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-27 18:48:02 +01:00
Pol HenarejosandFabrice Bellamy 2c36523afd Pico Keys SDK 8.5
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-27 18:48:02 +01:00
Pol HenarejosandFabrice Bellamy 5184f3b91d Add weak init callback.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-27 18:48:02 +01:00
Pol HenarejosandFabrice Bellamy 7267f09825 Add a PHY marker for RP2040 to preserve the serial number in BOOTSEL.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-27 18:48:02 +01:00
Pol HenarejosandFabrice Bellamy 15ba96a362 Move crc to crypto utils.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-27 18:48:02 +01:00
Pol HenarejosandFabrice Bellamy 7d82d77ab6 Add 8K flash area for binding.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-27 18:48:02 +01:00
Pol HenarejosandFabrice Bellamy 931d598acd Add rescue support for RP2040.
Note, however, that this is a best-effort approach since it does not have OTP. All security attempts are flawled and shall not be used to keep security information.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-27 18:48:02 +01:00
Fabrice BellamyandGitHub dd8602530c update licensing info for this fork of the community edition (#1)
* cleanup licensing info for this fork of the community edition

* add README.md

* typo

* update readme

* update license

* restore source files headers

* Use the new VID:PID allocated to Librekeys by OpenMoko
2026-02-27 19:46:07 +05:30
Suyog Tandel b82fd0312a chore: change branding in the usb_descriptors.c to librekeys 2026-01-21 12:08:29 +05:30
13 changed files with 209 additions and 52 deletions
+14 -14
View File
@@ -26,7 +26,7 @@ else()
include(pico_sdk_import.cmake)
endif()
project(picokey C CXX ASM)
project(pico_rescue C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
@@ -38,7 +38,7 @@ else()
add_definitions(-D__FOR_CI)
endif()
add_executable(picokey)
add_executable(pico_rescue)
endif()
set(USB_ITF_CCID 1)
@@ -53,48 +53,48 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/version.c
)
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/pico_keys_version.h" 2)
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/pico_keys_version.h" 3)
if(ESP_PLATFORM)
project(picokey)
project(pico_rescue)
endif()
if(NOT ESP_PLATFORM)
target_sources(picokey PUBLIC ${SOURCES})
target_include_directories(picokey PUBLIC ${INCLUDES})
target_sources(pico_rescue PUBLIC ${SOURCES})
target_include_directories(pico_rescue PUBLIC ${INCLUDES})
target_compile_options(picokey PUBLIC
target_compile_options(pico_rescue PUBLIC
-Wall
)
if(NOT MSVC)
target_compile_options(picokey PUBLIC
target_compile_options(pico_rescue PUBLIC
-Werror
)
endif()
if(ENABLE_EMULATION)
if(NOT MSVC)
target_compile_options(picokey PUBLIC
target_compile_options(pico_rescue PUBLIC
-fdata-sections
-ffunction-sections
)
endif()
if(APPLE)
target_link_options(picokey PUBLIC
target_link_options(pico_rescue PUBLIC
-Wl,-dead_strip
)
elseif(MSVC)
target_compile_options(picokey PUBLIC
target_compile_options(pico_rescue PUBLIC
-WX
)
target_link_libraries(picokey PUBLIC wsock32 ws2_32 Bcrypt)
target_link_libraries(pico_rescue PUBLIC wsock32 ws2_32 Bcrypt)
else()
target_link_options(picokey PUBLIC
target_link_options(pico_rescue PUBLIC
-Wl,--gc-sections
)
endif(APPLE)
target_link_libraries(picokey PRIVATE pthread m)
target_link_libraries(pico_rescue PRIVATE pthread m)
else()
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
endif()
+21 -1
View File
@@ -1,3 +1,23 @@
Unless stated otherwise at the top of a file, all the files of this
project are licensed under the GNU Affero General Public License v3
(AGPLv3). The full text of this license is reproduced at the bottom of
this document.
The copyright holders are indicated at the top of each file.
The project is using the following libraries, sdk or portions of code:
- mdebtls, licensed under Apache-2.0 and GPL-2.0-or-later licenses,
https://github.com/Mbed-TLS/mbedtls
- tinyUSB, licensed under the MIT License,
https://github.com/hathach/tinyusb
- tinycbor, licensed under the MIT license,
https://github.com/intel/tinycbor
- mlkem-native, the Apache-2.0 license OR the ISC license OR the MIT
license, https://github.com/pq-code-package/mlkem-native
- USB CCID from Raspberry Pi (Trading) Ltd, licensed under the BSD
license,
________________________________________________________________________
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
@@ -658,4 +678,4 @@ specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.
+4
View File
@@ -0,0 +1,4 @@
# Pico Keys SDK
This is a fork of the community edition of the project located at https://github.com/polhenarejos/pico-keys-sdk
For licensing information and credits, see the LICENSE file
+19 -4
View File
@@ -10,7 +10,7 @@
},
"partitions": [
{
"name": "Pico Keys Firmware",
"name": "PicoKeys Firmware",
"id": 0,
"start": 0,
"size": "1024K",
@@ -22,10 +22,10 @@
}
},
{
"name": "Pico Keys Data",
"name": "PicoKeys Data",
"id": 1,
"start": "1024K",
"size": "3072K",
"start": "1032K",
"size": "3064K",
"families": ["data"],
"permissions": {
"secure": "rw",
@@ -35,6 +35,21 @@
"link": ["owner", 0],
"ignored_during_arm_boot": true,
"ignored_during_riscv_boot": true
},
{
"name": "PicoKeys Binding",
"id": 2,
"start": "1024K",
"size": "8K",
"families": ["data"],
"permissions": {
"secure": "r",
"nonsecure": "",
"bootloader": "w"
},
"link": ["owner", 0],
"ignored_during_arm_boot": true,
"ignored_during_riscv_boot": true
}
]
}
+3 -3
View File
@@ -64,12 +64,12 @@ if(ESP_PLATFORM)
endif()
if(NOT DEFINED USB_VID)
set(USB_VID 0x2E8A)
set(USB_VID 0x1D50)
endif()
add_definitions(-DUSB_VID=${USB_VID})
if(NOT DEFINED USB_PID)
set(USB_PID 0x10FD)
set(USB_PID 0x619B)
endif()
add_definitions(-DUSB_PID=${USB_PID})
@@ -126,7 +126,7 @@ if(NOT ESP_PLATFORM)
)
if(ENABLE_EDDSA)
set(MBEDTLS_ORIGIN "https://github.com/polhenarejos/mbedtls.git")
set(MBEDTLS_ORIGIN "https://github.com/librekeys/mbedtls.git")
set(MBEDTLS_REF "mbedtls-3.6-eddsa")
execute_process(
+1 -1
View File
@@ -30,7 +30,7 @@ uint8_t *rdata_gr = NULL;
uint16_t rdata_bk = 0x0;
extern uint32_t timeout;
bool is_chaining = false;
uint8_t chain_buf[4096];
uint8_t chain_buf[2038];
uint8_t *chain_ptr = NULL;
int process_apdu() {
+13
View File
@@ -278,3 +278,16 @@ mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_
}
return MBEDTLS_ECP_DP_NONE;
}
#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;
}
+1
View File
@@ -56,5 +56,6 @@ extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size,
extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len);
extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len);
extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
extern uint32_t crc32c(const uint8_t *buf, size_t len);
#endif
+46
View File
@@ -22,6 +22,7 @@
#include "pico_keys.h"
#include <string.h>
#include "crypto_utils.h"
#ifdef PICO_PLATFORM
#include "pico/stdlib.h"
#include "hardware/flash.h"
@@ -158,8 +159,14 @@ void do_flash() {
sem_release(&sem_flash);
}
#ifdef PICO_RP2040
void phymarker_write();
#endif
//this function has to be called from the core 0
void low_flash_init() {
#ifdef PICO_RP2040
phymarker_write();
#endif
memset(flash_pages, 0, sizeof(page_flash_t) * TOTAL_FLASH_PAGES);
mutex_init(&mtx_flash);
sem_init(&sem_flash, 0, 1);
@@ -371,3 +378,42 @@ bool flash_check_blank(const uint8_t *p_start, size_t size) {
}
return true;
}
#ifdef PICO_RP2040
typedef struct {
uint64_t magic;
uint16_t version;
uint16_t flags;
uint8_t uid[PICO_UNIQUE_BOARD_ID_SIZE_BYTES];
uint32_t crc32;
} __attribute__ ((packed)) phymarker_t;
uintptr_t __phymarker_start = (uintptr_t)0x10100000;
const uint64_t PHYSICAL_MARKER_MAGIC = 0x5049434F4B455953ULL; // "PICOKEYS"
void phymarker_write() {
const uint64_t magic = *(uint64_t *)__phymarker_start;
if (magic == PHYSICAL_MARKER_MAGIC) {
return;
}
phymarker_t pm = {
.magic = PHYSICAL_MARKER_MAGIC, // "PICOKEYS"
.version = 0x0001,
.flags = 0x0000,
.crc32 = 0x00000000
};
memcpy(pm.uid, pico_serial.id, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
pm.crc32 = crc32c((const uint8_t *)&pm, sizeof(phymarker_t) - sizeof(uint32_t));
uint8_t buf[FLASH_PAGE_SIZE] = {0};
memcpy(buf, &pm, sizeof(phymarker_t));
uint32_t ints = save_and_disable_interrupts();
flash_range_erase((uint32_t)__phymarker_start - XIP_BASE, FLASH_SECTOR_SIZE);
flash_range_program((uint32_t)__phymarker_start - XIP_BASE, (const uint8_t *)buf, sizeof(buf));
restore_interrupts(ints);
}
#endif
+9
View File
@@ -235,6 +235,11 @@ bool wait_button() {
req_button_pending = false;
return timeout || cancel_button;
}
__attribute__((weak)) int picokey_init() {
return 0;
}
#endif
bool set_rtc = false;
@@ -393,6 +398,10 @@ int main(void) {
#endif
#endif
#ifndef ENABLE_EMULATION
picokey_init();
#endif
#ifdef ESP_PLATFORM
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0);
#else
+1 -1
View File
@@ -18,7 +18,7 @@
#ifndef __VERSION_H_
#define __VERSION_H_
#define PICO_KEYS_SDK_VERSION 0x0804
#define PICO_KEYS_SDK_VERSION 0x0805
#define PICO_KEYS_SDK_VERSION_MAJOR ((PICO_KEYS_SDK_VERSION >> 8) & 0xff)
#define PICO_KEYS_SDK_VERSION_MINOR (PICO_KEYS_SDK_VERSION & 0xff)
+69 -20
View File
@@ -22,6 +22,7 @@
#include "mbedtls/ecdsa.h"
#include "mbedtls/sha256.h"
#include "random.h"
#include "crypto_utils.h"
#ifdef PICO_PLATFORM
extern char __flash_binary_start;
@@ -46,6 +47,8 @@ const uint8_t rescue_aid[] = {
#define PICO_MCU 0
#endif
#define EF_DEVCERT_KEY 0xE0C1
extern uint8_t PICO_PRODUCT;
extern uint8_t PICO_VERSION_MAJOR;
extern uint8_t PICO_VERSION_MINOR;
@@ -75,30 +78,69 @@ int rescue_unload() {
return PICOKEY_OK;
}
static int load_internal_keydev(mbedtls_ecp_keypair *ecp, mbedtls_ecp_group_id ec_id) {
file_t *ef_devcert_key = file_new(EF_DEVCERT_KEY);
if (!ef_devcert_key) {
return SW_FILE_NOT_FOUND();
}
uint8_t kbase[32] = {0};
derive_kbase(kbase);
if (file_has_data(ef_devcert_key)) {
uint8_t pkey[32] = {0};
memcpy(pkey, file_get_data(ef_devcert_key), 32);
aes_decrypt(kbase, pico_serial_hash, 32 * 8, PICO_KEYS_AES_MODE_CBC, pkey, 32);
int ret = mbedtls_ecp_read_key(ec_id, ecp, pkey, 32);
mbedtls_platform_zeroize(pkey, sizeof(pkey));
if (ret != 0) {
return SW_EXEC_ERROR();
}
}
else {
// Generate new key
uint8_t pkey[MBEDTLS_ECP_MAX_BYTES] = {0};
size_t olen = 0;
mbedtls_ecp_gen_key(ec_id, ecp, random_gen, NULL);
mbedtls_ecp_write_key_ext(ecp, &olen, pkey, sizeof(pkey));
aes_encrypt(kbase, pico_serial_hash, 32 * 8, PICO_KEYS_AES_MODE_CBC, pkey, 32);
file_put_data(ef_devcert_key, pkey, (uint16_t)olen);
mbedtls_platform_zeroize(pkey, sizeof(pkey));
low_flash_available();
}
return PICOKEY_OK;
}
int cmd_keydev_sign() {
uint8_t p1 = P1(apdu);
if (p1 == 0x01) {
if (apdu.nc != 32) {
return SW_WRONG_LENGTH();
}
mbedtls_ecp_keypair ecp;
mbedtls_ecp_keypair_init(&ecp);
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
if (!otp_key_2) {
return SW_INS_NOT_SUPPORTED();
int ret = load_internal_keydev(&ecp, ec_id);
if (ret != PICOKEY_OK) {
mbedtls_ecp_keypair_free(&ecp);
return ret;
}
}
mbedtls_ecdsa_context ecdsa;
mbedtls_ecdsa_init(&ecdsa);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256K1, &ecdsa, otp_key_2, 32);
if (ret != 0) {
mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR();
else {
int ret = mbedtls_ecp_read_key(ec_id, &ecp, otp_key_2, 32);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
}
uint16_t key_size = 2 * (int)((mbedtls_ecp_curve_info_from_grp_id(MBEDTLS_ECP_DP_SECP256K1)->bit_size + 7) / 8);
uint16_t key_size = 2 * (int)((mbedtls_ecp_curve_info_from_grp_id(ec_id)->bit_size + 7) / 8);
mbedtls_mpi r, s;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
ret = mbedtls_ecdsa_sign(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), apdu.data, apdu.nc, random_gen, NULL);
int ret = mbedtls_ecdsa_sign(&ecp.MBEDTLS_PRIVATE(grp), &r, &s, &ecp.MBEDTLS_PRIVATE(d), apdu.data, apdu.nc, random_gen, NULL);
if (ret != 0) {
mbedtls_ecdsa_free(&ecdsa);
mbedtls_ecp_keypair_free(&ecp);
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
return SW_EXEC_ERROR();
@@ -106,32 +148,39 @@ int cmd_keydev_sign() {
mbedtls_mpi_write_binary(&r, res_APDU, key_size / 2); res_APDU_size = key_size / 2;
mbedtls_mpi_write_binary(&s, res_APDU + res_APDU_size, key_size / 2); res_APDU_size += key_size / 2;
mbedtls_ecdsa_free(&ecdsa);
mbedtls_ecp_keypair_free(&ecp);
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
}
else if (p1 == 0x02) {
// Return public key
if (!otp_key_2) {
return SW_INS_NOT_SUPPORTED();
}
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
mbedtls_ecp_keypair ecp;
mbedtls_ecp_keypair_init(&ecp);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256K1, &ecp, otp_key_2, 32);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
if (!otp_key_2) {
int ret = load_internal_keydev(&ecp, ec_id);
if (ret != PICOKEY_OK) {
mbedtls_ecp_keypair_free(&ecp);
return ret;
}
}
ret = mbedtls_ecp_mul(&ecp.MBEDTLS_PRIVATE(grp), &ecp.MBEDTLS_PRIVATE(Q), &ecp.MBEDTLS_PRIVATE(d), &ecp.MBEDTLS_PRIVATE(grp).G, random_gen, NULL);
else {
int ret = mbedtls_ecp_read_key(ec_id, &ecp, otp_key_2, 32);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
}
int ret = mbedtls_ecp_mul(&ecp.MBEDTLS_PRIVATE(grp), &ecp.MBEDTLS_PRIVATE(Q), &ecp.MBEDTLS_PRIVATE(d), &ecp.MBEDTLS_PRIVATE(grp).G, random_gen, NULL);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
size_t olen = 0;
ret = mbedtls_ecp_point_write_binary(&ecp.MBEDTLS_PRIVATE(grp), &ecp.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, res_APDU, 4096);
ret = mbedtls_ecp_point_write_binary(&ecp.MBEDTLS_PRIVATE(grp), &ecp.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, res_APDU, 2038);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
+8 -8
View File
@@ -28,10 +28,10 @@
#include "usb.h"
#ifndef USB_VID
#define USB_VID 0x2E8A
#define USB_VID 0x1D50
#endif
#ifndef USB_PID
#define USB_PID 0x10FD
#define USB_PID 0x619B
#endif
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
@@ -214,7 +214,7 @@ enum
VENDOR_REQUEST_WEBUSB = 1,
VENDOR_REQUEST_MICROSOFT = 2
};
#define URL "www.picokeys.com"
#define URL "www.librekeys.org"
static bool web_serial_connected = false;
const tusb_desc_webusb_url_t desc_url =
@@ -318,11 +318,11 @@ uint8_t const *tud_descriptor_bos_cb(void) {
// array of pointer to string descriptors
char *string_desc_itf[4] = {0};
char const *string_desc_arr [] = {
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"Pol Henarejos", // 1: Manufacturer
"Pico Key", // 2: Product
"11223344", // 3: Serials, should use chip ID
"Config" // 4: Vendor Interface
(const char[]) { 0x09, 0x04 }, // 0: Supported language : English (0x0409)
"LibreKeys", // 1: Manufacturer
"One", // 2: Product
"11223344", // 3: Serials, should use chip ID
"Config" // 4: Vendor Interfaces
, "HID Interface"
, "HID Keyboard Interface"
, "CCID OTP FIDO Interface"