diff --git a/firmware/src/CMakeLists.txt b/firmware/src/CMakeLists.txt index f0e5541..cea7474 100644 --- a/firmware/src/CMakeLists.txt +++ b/firmware/src/CMakeLists.txt @@ -1,12 +1,8 @@ -set(BTSTACK_ROOT ${PICO_SDK_PATH}/lib/btstack) -set(LWIP_ROOT ${PICO_SDK_PATH}/lib/lwip) - function(make_firmware board board_def) - pico_sdk_init() add_executable(${board} main.c slider.c rgb.c button.c savedata.c config.c commands.c cli.c mpr121.c hebtn.c lzfx.c usb_descriptors.c ps4_feat.c gesture.c - ps4key.c) + ps4key.c crypto/ps4_crypto.c) target_compile_definitions(${board} PUBLIC ${board_def}) pico_enable_stdio_usb(${board} 1) pico_enable_stdio_uart(${board} 0) @@ -15,13 +11,10 @@ function(make_firmware board board_def) target_compile_options(${board} PRIVATE -Wall -Werror -Wfatal-errors -O3) target_include_directories(${board} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) - target_include_directories(${board} PRIVATE - ${BTSTACK_ROOT}/src - ${LWIP_ROOT}/src/include) target_link_libraries(${board} PRIVATE pico_multicore pico_stdlib hardware_pio hardware_pwm hardware_flash - hardware_adc hardware_i2c hardware_watchdog + hardware_adc hardware_i2c hardware_watchdog pico_rand pico_mbedtls tinyusb_device tinyusb_board) pico_add_extra_outputs(${board}) diff --git a/firmware/src/commands.c b/firmware/src/commands.c index 9087dcc..f4d420b 100644 --- a/firmware/src/commands.c +++ b/firmware/src/commands.c @@ -13,6 +13,7 @@ #include "savedata.h" #include "cli.h" #include "ps4key.h" +#include "crypto/ps4_crypto.h" #include "gesture.h" @@ -462,8 +463,27 @@ static void handle_ps4key(int argc, char *argv[]) } savedata_write_global(&key, sizeof(key)); - printf("PS4 key stored: Serial: %s, PEM: %d bytes, sig: %d bytes\n", - ps4key_get_serial(&key), key.pem_len - 1, key.sig_len); + printf("PS4 key stored: Serial: %s, sig: %d bytes, N/E/P/Q: %d/%d/%d/%d bytes\n", + ps4key_get_serial(&key), + key.sig_len, + key.rsa_n_len, + key.rsa_e_len, + key.rsa_p_len, + key.rsa_q_len); +} + +static void handle_rsa(int argc, char *argv[]) +{ + (void)argv; + if (argc != 0) { + printf("Usage: rsa\n"); + return; + } + + if (!ps4_crypto_selftest()) { + printf("PS4 crypto selftest failed.\n"); + return; + } } void commands_init() @@ -482,4 +502,5 @@ void commands_init() cli_register("save", handle_save, "Save config to flash."); cli_register("factory", handle_factory_reset, "Reset everything to default."); cli_register("ps4key", handle_ps4key, "Import or clear serialized PS4 key data."); + cli_register("rsa", handle_rsa, "Run hello-world SHA256, nonce SHA256, and RSA context smoke test."); } diff --git a/firmware/src/mbedtls_config.h b/firmware/src/mbedtls_config.h new file mode 100644 index 0000000..877d224 --- /dev/null +++ b/firmware/src/mbedtls_config.h @@ -0,0 +1,38 @@ +/* This can be enabled lated when we use SNTP */ +#undef MBEDTLS_HAVE_TIME_DATE + +#define MBEDTLS_CHECK_PARAMS_ASSERT +#define MBEDTLS_ENTROPY_HARDWARE_ALT +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_AES_FEWER_TABLES +#define MBEDTLS_CAMELLIA_SMALL_MEMORY +#define MBEDTLS_CHECK_RETURN_WARNING +#undef MBEDTLS_FS_IO +#define MBEDTLS_NO_PLATFORM_ENTROPY +#undef MBEDTLS_PSA_CRYPTO_CLIENT +#undef MBEDTLS_PSA_CRYPTO_DRIVERS +#define MBEDTLS_SHA256_C +#define MBEDTLS_RSA_C +#define MBEDTLS_X509_RSASSA_PSS_SUPPORT +#define MBEDTLS_PKCS1_V21 +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_MD_C +#define MBEDTLS_SSL_ASYNC_PRIVATE +#define MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH +#undef MBEDTLS_USE_PSA_CRYPTO +#define MBEDTLS_OID_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_X509_USE_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PEM_WRITE_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_WRITE_C +#define MBEDTLS_PKCS1_PARSE_C +#define MBEDTLS_PK_C +#undef MBEDTLS_NET_C +#undef MBEDTLS_PSA_CRYPTO_STORAGE_C +#undef MBEDTLS_PSA_ITS_FILE_C +#undef MBEDTLS_TIMING_C diff --git a/firmware/src/ps4key.c b/firmware/src/ps4key.c index 39f2bae..772a9f0 100644 --- a/firmware/src/ps4key.c +++ b/firmware/src/ps4key.c @@ -7,6 +7,9 @@ #include #include +#include "mbedtls/pk.h" +#include "mbedtls/rsa.h" + #include "ps4key.h" static uint32_t crc32_calc(const uint8_t *data, size_t size) @@ -122,10 +125,86 @@ static bool serial_is_valid(const uint8_t *serial, size_t size) return true; } -static bool pem_is_valid(const char *pem) +static size_t key_payload_len(const ps4key_t *key) { - return strstr(pem, "-----BEGIN RSA PRIVATE KEY-----") && - strstr(pem, "-----END RSA PRIVATE KEY-----"); + return key->serial_len + key->sig_len + + key->rsa_n_len + key->rsa_e_len + + key->rsa_p_len + key->rsa_q_len; +} + +static size_t sig_offset(const ps4key_t *key) +{ + return key->serial_len; +} + +static size_t rsa_n_offset(const ps4key_t *key) +{ + return sig_offset(key) + key->sig_len; +} + +static size_t rsa_e_offset(const ps4key_t *key) +{ + return rsa_n_offset(key) + key->rsa_n_len; +} + +static size_t rsa_p_offset(const ps4key_t *key) +{ + return rsa_e_offset(key) + key->rsa_e_len; +} + +static size_t rsa_q_offset(const ps4key_t *key) +{ + return rsa_p_offset(key) + key->rsa_p_len; +} + +static bool rebuild_pem(const ps4key_t *key, char *pem, size_t pem_size) +{ + mbedtls_mpi n; + mbedtls_mpi e; + mbedtls_mpi p; + mbedtls_mpi q; + mbedtls_mpi_init(&n); + mbedtls_mpi_init(&e); + mbedtls_mpi_init(&p); + mbedtls_mpi_init(&q); + + int ret = mbedtls_mpi_read_binary(&n, ps4key_get_rsa_n(key), key->rsa_n_len); + if (ret != 0) goto cleanup; + ret = mbedtls_mpi_read_binary(&e, ps4key_get_rsa_e(key), key->rsa_e_len); + if (ret != 0) goto cleanup; + ret = mbedtls_mpi_read_binary(&p, ps4key_get_rsa_p(key), key->rsa_p_len); + if (ret != 0) goto cleanup; + ret = mbedtls_mpi_read_binary(&q, ps4key_get_rsa_q(key), key->rsa_q_len); + if (ret != 0) goto cleanup; + + mbedtls_pk_context pk; + mbedtls_pk_init(&pk); + + ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); + if (ret != 0) { + mbedtls_pk_free(&pk); + goto cleanup; + } + + mbedtls_rsa_context *rsa = mbedtls_pk_rsa(pk); + mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256); + + ret = mbedtls_rsa_import(rsa, &n, &p, &q, NULL, &e); + if (ret == 0) { + ret = mbedtls_rsa_complete(rsa); + } + if (ret == 0) { + ret = mbedtls_pk_write_key_pem(&pk, (unsigned char *)pem, pem_size); + } + + mbedtls_pk_free(&pk); + +cleanup: + mbedtls_mpi_free(&n); + mbedtls_mpi_free(&e); + mbedtls_mpi_free(&p); + mbedtls_mpi_free(&q); + return ret == 0; } static void set_error(const char **error, const char *message) @@ -149,13 +228,16 @@ static bool ps4key_validate(const ps4key_t *key, const char **error) } if ((key->serial_len != (PS4KEY_SERIAL_LENGTH + 1)) || - (key->pem_len <= 1) || (key->pem_len > (PS4KEY_PEM_MAX_LENGTH + 1)) || - (key->sig_len == 0) || (key->sig_len > PS4KEY_SIG_MAX_LENGTH)) { + (key->sig_len != PS4KEY_SIG_LENGTH) || + (key->rsa_n_len != PS4KEY_RSA_N_LENGTH) || + (key->rsa_e_len == 0) || (key->rsa_e_len > PS4KEY_RSA_E_LENGTH) || + (key->rsa_p_len != PS4KEY_RSA_P_LENGTH) || + (key->rsa_q_len != PS4KEY_RSA_Q_LENGTH)) { set_error(error, "Serialized part lengths are invalid."); return false; } - size_t payload_len = key->serial_len + key->pem_len + key->sig_len; + size_t payload_len = key_payload_len(key); if (payload_len > sizeof(key->payload)) { set_error(error, "Serialized length mismatch."); return false; @@ -171,14 +253,9 @@ static bool ps4key_validate(const ps4key_t *key, const char **error) return false; } - const uint8_t *pem_ptr = key->payload + key->serial_len; - if (pem_ptr[key->pem_len - 1] != '\0') { - set_error(error, "PEM data is not null terminated."); - return false; - } - - if (!pem_is_valid((const char *)pem_ptr)) { - set_error(error, "PEM content does not look like an RSA private key."); + size_t rsa_q_end = rsa_q_offset(key) + key->rsa_q_len; + if (rsa_q_end != payload_len) { + set_error(error, "Serialized layout mismatch."); return false; } @@ -211,7 +288,7 @@ bool ps4key_parse_text(const char *text, ps4key_t *key, const char **error) return false; } const ps4key_t *src = (const ps4key_t *)decoded; - size_t payload_len = src->serial_len + src->pem_len + src->sig_len; + size_t payload_len = key_payload_len(src); if (decoded_len != header_len + payload_len) { set_error(error, "Serialized length mismatch."); return false; @@ -238,10 +315,22 @@ const char *ps4key_get_serial(const ps4key_t *key) const char *ps4key_get_pem(const ps4key_t *key) { - if (key == NULL) { + static char pem[2048] = {0}; + static uint32_t last_crc = 0; + + if ((key == NULL) || !ps4key_key_valid(key)) { return NULL; } - return (const char *)(key->payload + key->serial_len); + + if ((last_crc != key->crc32) || (pem[0] == '\0')) { + memset(pem, 0, sizeof(pem)); + if (!rebuild_pem(key, pem, sizeof(pem))) { + return NULL; + } + last_crc = key->crc32; + } + + return pem; } const uint8_t *ps4key_get_sig(const ps4key_t *key) @@ -249,7 +338,7 @@ const uint8_t *ps4key_get_sig(const ps4key_t *key) if (key == NULL) { return NULL; } - return key->payload + key->serial_len + key->pem_len; + return key->payload + sig_offset(key); } size_t ps4key_get_sig_len(const ps4key_t *key) @@ -259,3 +348,35 @@ size_t ps4key_get_sig_len(const ps4key_t *key) } return key->sig_len; } + +const uint8_t *ps4key_get_rsa_n(const ps4key_t *key) +{ + if (key == NULL) { + return NULL; + } + return key->payload + rsa_n_offset(key); +} + +const uint8_t *ps4key_get_rsa_e(const ps4key_t *key) +{ + if (key == NULL) { + return NULL; + } + return key->payload + rsa_e_offset(key); +} + +const uint8_t *ps4key_get_rsa_p(const ps4key_t *key) +{ + if (key == NULL) { + return NULL; + } + return key->payload + rsa_p_offset(key); +} + +const uint8_t *ps4key_get_rsa_q(const ps4key_t *key) +{ + if (key == NULL) { + return NULL; + } + return key->payload + rsa_q_offset(key); +} diff --git a/firmware/src/ps4key.h b/firmware/src/ps4key.h index 1829b20..157737b 100644 --- a/firmware/src/ps4key.h +++ b/firmware/src/ps4key.h @@ -14,17 +14,25 @@ #define PS4KEY_STORAGE_MAGIC 0x4b345350u #define PS4KEY_STORAGE_VERSION 1u #define PS4KEY_SERIAL_LENGTH 16 -#define PS4KEY_PEM_MAX_LENGTH 2048 -#define PS4KEY_SIG_MAX_LENGTH 512 -#define PS4KEY_PAYLOAD_MAX_LENGTH (PS4KEY_SERIAL_LENGTH + 1 + PS4KEY_PEM_MAX_LENGTH + 1 + PS4KEY_SIG_MAX_LENGTH) +#define PS4KEY_SIG_LENGTH 256 +#define PS4KEY_RSA_N_LENGTH 256 +#define PS4KEY_RSA_E_LENGTH 4 +#define PS4KEY_RSA_P_LENGTH 128 +#define PS4KEY_RSA_Q_LENGTH 128 +#define PS4KEY_PAYLOAD_MAX_LENGTH (PS4KEY_SERIAL_LENGTH + 1 + PS4KEY_SIG_LENGTH + \ + PS4KEY_RSA_N_LENGTH + PS4KEY_RSA_E_LENGTH + \ + PS4KEY_RSA_P_LENGTH + PS4KEY_RSA_Q_LENGTH) typedef struct __attribute__((packed)) { uint32_t magic; uint8_t version; uint8_t reserved; uint16_t serial_len; - uint16_t pem_len; uint16_t sig_len; + uint16_t rsa_n_len; + uint16_t rsa_e_len; + uint16_t rsa_p_len; + uint16_t rsa_q_len; uint32_t crc32; uint8_t payload[PS4KEY_PAYLOAD_MAX_LENGTH]; } ps4key_t; @@ -36,5 +44,9 @@ const char *ps4key_get_serial(const ps4key_t *key); const char *ps4key_get_pem(const ps4key_t *key); const uint8_t *ps4key_get_sig(const ps4key_t *key); size_t ps4key_get_sig_len(const ps4key_t *key); +const uint8_t *ps4key_get_rsa_n(const ps4key_t *key); +const uint8_t *ps4key_get_rsa_e(const ps4key_t *key); +const uint8_t *ps4key_get_rsa_p(const ps4key_t *key); +const uint8_t *ps4key_get_rsa_q(const ps4key_t *key); #endif \ No newline at end of file diff --git a/tools/ps4key_packer.html b/tools/ps4key_packer.html index 94971e1..4532b1f 100644 --- a/tools/ps4key_packer.html +++ b/tools/ps4key_packer.html @@ -278,8 +278,11 @@