2022-08-18 23:44:27 +00:00
|
|
|
/*
|
2022-08-13 12:59:27 +00:00
|
|
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
|
|
|
* Copyright (c) 2022 Pol Henarejos.
|
2022-08-18 23:44:27 +00:00
|
|
|
*
|
|
|
|
* 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
|
2022-08-13 12:59:27 +00:00
|
|
|
* the Free Software Foundation, version 3.
|
|
|
|
*
|
2022-08-18 23:44:27 +00:00
|
|
|
* 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
|
2022-08-13 12:59:27 +00:00
|
|
|
* General Public License for more details.
|
|
|
|
*
|
2022-08-18 23:44:27 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
2022-08-13 12:59:27 +00:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2022-08-18 23:44:27 +00:00
|
|
|
|
2022-10-31 14:09:54 +00:00
|
|
|
#include "common.h"
|
|
|
|
#include "mbedtls/ecdh.h"
|
2022-08-13 12:59:27 +00:00
|
|
|
#include "sc_hsm.h"
|
2023-01-12 19:04:23 +00:00
|
|
|
#ifndef ENABLE_EMULATION
|
2022-08-13 12:59:27 +00:00
|
|
|
#include "hardware/rtc.h"
|
2023-01-12 19:04:23 +00:00
|
|
|
#endif
|
2022-08-13 12:59:27 +00:00
|
|
|
#include "files.h"
|
2022-10-31 14:09:54 +00:00
|
|
|
#include "random.h"
|
|
|
|
#include "kek.h"
|
|
|
|
#include "mbedtls/hkdf.h"
|
|
|
|
#include "mbedtls/chachapoly.h"
|
2022-08-13 12:59:27 +00:00
|
|
|
|
2023-02-14 23:10:35 +00:00
|
|
|
int cmd_extras() {
|
2022-08-13 12:59:27 +00:00
|
|
|
if (P1(apdu) == 0xA) { //datetime operations
|
2023-02-14 22:13:46 +00:00
|
|
|
if (P2(apdu) != 0x0) {
|
2022-10-31 14:09:54 +00:00
|
|
|
return SW_INCORRECT_P1P2();
|
2023-02-14 22:13:46 +00:00
|
|
|
}
|
2022-08-13 12:59:27 +00:00
|
|
|
if (apdu.nc == 0) {
|
2023-01-12 19:04:23 +00:00
|
|
|
#ifndef ENABLE_EMULATION
|
2022-08-13 12:59:27 +00:00
|
|
|
datetime_t dt;
|
2023-02-14 22:13:46 +00:00
|
|
|
if (!rtc_get_datetime(&dt)) {
|
2022-08-13 12:59:27 +00:00
|
|
|
return SW_EXEC_ERROR();
|
2023-02-14 22:13:46 +00:00
|
|
|
}
|
2022-08-13 12:59:27 +00:00
|
|
|
res_APDU[res_APDU_size++] = dt.year >> 8;
|
|
|
|
res_APDU[res_APDU_size++] = dt.year & 0xff;
|
|
|
|
res_APDU[res_APDU_size++] = dt.month;
|
|
|
|
res_APDU[res_APDU_size++] = dt.day;
|
|
|
|
res_APDU[res_APDU_size++] = dt.dotw;
|
|
|
|
res_APDU[res_APDU_size++] = dt.hour;
|
|
|
|
res_APDU[res_APDU_size++] = dt.min;
|
|
|
|
res_APDU[res_APDU_size++] = dt.sec;
|
2023-01-12 19:04:23 +00:00
|
|
|
#endif
|
2023-02-14 23:10:35 +00:00
|
|
|
}
|
|
|
|
else {
|
2023-02-14 22:13:46 +00:00
|
|
|
if (apdu.nc != 8) {
|
2022-08-13 12:59:27 +00:00
|
|
|
return SW_WRONG_LENGTH();
|
2023-02-14 22:13:46 +00:00
|
|
|
}
|
2023-01-12 19:04:23 +00:00
|
|
|
#ifndef ENABLE_EMULATION
|
2022-08-13 12:59:27 +00:00
|
|
|
datetime_t dt;
|
|
|
|
dt.year = (apdu.data[0] << 8) | (apdu.data[1]);
|
|
|
|
dt.month = apdu.data[2];
|
|
|
|
dt.day = apdu.data[3];
|
|
|
|
dt.dotw = apdu.data[4];
|
|
|
|
dt.hour = apdu.data[5];
|
|
|
|
dt.min = apdu.data[6];
|
|
|
|
dt.sec = apdu.data[7];
|
2023-02-14 22:13:46 +00:00
|
|
|
if (!rtc_set_datetime(&dt)) {
|
2022-08-13 12:59:27 +00:00
|
|
|
return SW_WRONG_DATA();
|
2023-02-14 22:13:46 +00:00
|
|
|
}
|
2023-01-12 19:04:23 +00:00
|
|
|
#endif
|
2022-08-13 12:59:27 +00:00
|
|
|
}
|
2023-02-14 23:10:35 +00:00
|
|
|
}
|
|
|
|
else if (P1(apdu) == 0x6) { //dynamic options
|
2023-02-14 22:13:46 +00:00
|
|
|
if (P2(apdu) != 0x0) {
|
2022-10-31 14:09:54 +00:00
|
|
|
return SW_INCORRECT_P1P2();
|
2023-02-14 22:13:46 +00:00
|
|
|
}
|
|
|
|
if (apdu.nc > sizeof(uint8_t)) {
|
2022-08-13 12:59:27 +00:00
|
|
|
return SW_WRONG_LENGTH();
|
2023-02-14 22:13:46 +00:00
|
|
|
}
|
2022-08-13 12:59:27 +00:00
|
|
|
uint16_t opts = get_device_options();
|
|
|
|
if (apdu.nc == 0) {
|
|
|
|
res_APDU[res_APDU_size++] = opts >> 8;
|
|
|
|
res_APDU[res_APDU_size++] = opts & 0xff;
|
2023-02-14 23:10:35 +00:00
|
|
|
}
|
|
|
|
else {
|
2022-08-13 12:59:27 +00:00
|
|
|
uint8_t newopts[] = { apdu.data[0], (opts & 0xff) };
|
|
|
|
file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF);
|
|
|
|
flash_write_data_to_file(tf, newopts, sizeof(newopts));
|
|
|
|
low_flash_available();
|
|
|
|
}
|
2023-02-14 23:10:35 +00:00
|
|
|
}
|
|
|
|
else if (P1(apdu) == 0x3A) { // secure lock
|
2022-10-31 14:09:54 +00:00
|
|
|
if (apdu.nc == 0) {
|
|
|
|
return SW_WRONG_LENGTH();
|
|
|
|
}
|
|
|
|
if (P2(apdu) == 0x01) { // Key Agreement
|
|
|
|
mbedtls_ecdh_context hkey;
|
|
|
|
mbedtls_ecdh_init(&hkey);
|
|
|
|
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1);
|
2023-02-14 22:13:46 +00:00
|
|
|
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp,
|
|
|
|
&hkey.ctx.mbed_ecdh.d,
|
|
|
|
&hkey.ctx.mbed_ecdh.Q,
|
|
|
|
random_gen,
|
|
|
|
NULL);
|
2022-10-31 14:09:54 +00:00
|
|
|
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
|
2023-02-14 22:13:46 +00:00
|
|
|
ret = mbedtls_ecp_point_read_binary(&hkey.ctx.mbed_ecdh.grp,
|
|
|
|
&hkey.ctx.mbed_ecdh.Qp,
|
|
|
|
apdu.data,
|
|
|
|
apdu.nc);
|
2022-10-31 14:09:54 +00:00
|
|
|
if (ret != 0) {
|
|
|
|
mbedtls_ecdh_free(&hkey);
|
|
|
|
return SW_WRONG_DATA();
|
|
|
|
}
|
|
|
|
memcpy(mse.Qpt, apdu.data, sizeof(mse.Qpt));
|
|
|
|
|
|
|
|
uint8_t buf[MBEDTLS_ECP_MAX_BYTES];
|
2024-01-01 00:55:49 +00:00
|
|
|
uint16_t olen = 0;
|
2023-02-14 22:13:46 +00:00
|
|
|
ret = mbedtls_ecdh_calc_secret(&hkey,
|
2024-01-01 00:55:49 +00:00
|
|
|
(size_t *)&olen,
|
2023-02-14 22:13:46 +00:00
|
|
|
buf,
|
|
|
|
MBEDTLS_ECP_MAX_BYTES,
|
|
|
|
random_gen,
|
|
|
|
NULL);
|
2022-10-31 14:09:54 +00:00
|
|
|
if (ret != 0) {
|
|
|
|
mbedtls_ecdh_free(&hkey);
|
|
|
|
mbedtls_platform_zeroize(buf, sizeof(buf));
|
|
|
|
return SW_WRONG_DATA();
|
|
|
|
}
|
2023-02-14 22:13:46 +00:00
|
|
|
ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
buf,
|
|
|
|
olen,
|
|
|
|
mse.Qpt,
|
|
|
|
sizeof(mse.Qpt),
|
|
|
|
mse.key_enc,
|
|
|
|
sizeof(mse.key_enc));
|
2022-10-31 14:09:54 +00:00
|
|
|
mbedtls_platform_zeroize(buf, sizeof(buf));
|
|
|
|
if (ret != 0) {
|
|
|
|
mbedtls_ecdh_free(&hkey);
|
|
|
|
return SW_EXEC_ERROR();
|
|
|
|
}
|
|
|
|
|
2023-02-14 22:13:46 +00:00
|
|
|
ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp,
|
|
|
|
&hkey.ctx.mbed_ecdh.Q,
|
|
|
|
MBEDTLS_ECP_PF_UNCOMPRESSED,
|
2024-01-01 00:55:49 +00:00
|
|
|
(size_t *)&olen,
|
2023-02-14 22:13:46 +00:00
|
|
|
res_APDU,
|
|
|
|
4096);
|
2022-10-31 14:09:54 +00:00
|
|
|
mbedtls_ecdh_free(&hkey);
|
|
|
|
if (ret != 0) {
|
|
|
|
return SW_EXEC_ERROR();
|
|
|
|
}
|
|
|
|
mse.init = true;
|
|
|
|
res_APDU_size = olen;
|
2023-02-14 23:10:35 +00:00
|
|
|
}
|
|
|
|
else if (P2(apdu) == 0x02 || P2(apdu) == 0x03 || P2(apdu) == 0x04) {
|
2023-02-14 22:13:46 +00:00
|
|
|
if (mse.init == false) {
|
2022-10-31 14:09:54 +00:00
|
|
|
return SW_COMMAND_NOT_ALLOWED();
|
2023-02-14 22:13:46 +00:00
|
|
|
}
|
2022-10-31 14:09:54 +00:00
|
|
|
|
|
|
|
int ret = mse_decrypt_ct(apdu.data, apdu.nc);
|
|
|
|
if (ret != 0) {
|
|
|
|
return SW_WRONG_DATA();
|
|
|
|
}
|
|
|
|
if (P2(apdu) == 0x02 || P2(apdu) == 0x04) { // Enable
|
|
|
|
uint16_t opts = get_device_options();
|
|
|
|
uint8_t newopts[] = { opts >> 8, (opts & 0xff) };
|
2023-02-14 22:13:46 +00:00
|
|
|
if ((P2(apdu) == 0x02 && !(opts & HSM_OPT_SECURE_LOCK)) ||
|
|
|
|
(P2(apdu) == 0x04 && (opts & HSM_OPT_SECURE_LOCK))) {
|
2022-10-31 14:09:54 +00:00
|
|
|
uint16_t tfids[] = { EF_MKEK, EF_MKEK_SO };
|
2023-02-14 23:10:35 +00:00
|
|
|
for (int t = 0; t < sizeof(tfids) / sizeof(uint16_t); t++) {
|
2022-10-31 14:09:54 +00:00
|
|
|
file_t *tf = search_by_fid(tfids[t], NULL, SPECIFY_EF);
|
|
|
|
if (tf) {
|
2023-02-14 22:13:46 +00:00
|
|
|
uint8_t *tmp = (uint8_t *) calloc(1, file_get_size(tf));
|
2022-10-31 14:09:54 +00:00
|
|
|
memcpy(tmp, file_get_data(tf), file_get_size(tf));
|
|
|
|
for (int i = 0; i < MKEK_KEY_SIZE; i++) {
|
|
|
|
MKEK_KEY(tmp)[i] ^= apdu.data[i];
|
|
|
|
}
|
|
|
|
flash_write_data_to_file(tf, tmp, file_get_size(tf));
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-14 22:13:46 +00:00
|
|
|
if (P2(apdu) == 0x02) {
|
2022-10-31 14:09:54 +00:00
|
|
|
newopts[0] |= HSM_OPT_SECURE_LOCK >> 8;
|
2023-02-14 23:10:35 +00:00
|
|
|
}
|
|
|
|
else if (P2(apdu) == 0x04) {
|
2022-10-31 14:09:54 +00:00
|
|
|
newopts[0] &= ~HSM_OPT_SECURE_LOCK >> 8;
|
2023-02-14 22:13:46 +00:00
|
|
|
}
|
2022-10-31 14:09:54 +00:00
|
|
|
file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF);
|
|
|
|
flash_write_data_to_file(tf, newopts, sizeof(newopts));
|
|
|
|
low_flash_available();
|
2023-02-14 23:10:35 +00:00
|
|
|
}
|
|
|
|
else if (P2(apdu) == 0x03) {
|
2022-10-31 14:09:54 +00:00
|
|
|
memcpy(mkek_mask, apdu.data, apdu.nc);
|
|
|
|
has_mkek_mask = true;
|
|
|
|
}
|
|
|
|
}
|
2023-02-14 23:10:35 +00:00
|
|
|
}
|
|
|
|
else {
|
2022-08-13 12:59:27 +00:00
|
|
|
return SW_INCORRECT_P1P2();
|
2023-02-14 22:13:46 +00:00
|
|
|
}
|
2022-08-13 12:59:27 +00:00
|
|
|
return SW_OK();
|
2022-08-13 21:31:09 +00:00
|
|
|
}
|