12 Commits

Author SHA1 Message Date
Pol Henarejos
9ffcfb4beb Harden core-shared command/result state
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-01 13:38:36 +02:00
Pol Henarejos
3ccd6e827f Add cancel button event.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-01 01:43:25 +02:00
Pol Henarejos
a2044d697d Set persistent rpId, userName and userDisplay.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-01 00:22:18 +02:00
Pol Henarejos
659c04c837 Add slots for button signals.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-06-01 00:15:22 +02:00
Pol Henarejos
a0437dbfb2 Fix otp first build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-29 11:36:50 +02:00
Pol Henarejos
604e7868e2 Fix autobuild.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-29 00:20:05 +02:00
Pol Henarejos
0e3d0d9a7d Add libtss2 to runners.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-28 23:47:20 +02:00
Pol Henarejos
1f4be2a051 Update PicoKeys SDK
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-28 23:43:06 +02:00
Pol Henarejos
dc6007d1b4 Fix pico build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-02 12:04:48 +02:00
Pol Henarejos
6aa986ca06 Use ecp keypair calc public instead.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 21:01:45 +02:00
Pol Henarejos
98145a0ef4 Use dynamic dependence resolver.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 19:47:56 +02:00
Pol Henarejos
342ae90df8 Upgrade PicoKeys SDK
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 18:30:19 +02:00
26 changed files with 391 additions and 359 deletions

View File

@@ -88,10 +88,10 @@ else()
endif()
set(USB_ITF_HID 1)
include(pico-keys-sdk/pico_keys_sdk_import.cmake)
include(pico-keys-sdk/picokeys_sdk_import.cmake)
if(NOT ESP_PLATFORM)
set(SOURCES ${PICO_KEYS_SOURCES})
set(SOURCES ${PICOKEYS_SOURCES})
endif()
list(APPEND SOURCES
@@ -147,7 +147,7 @@ if(NOT ESP_PLATFORM)
)
target_compile_options(pico_fido PRIVATE ${COMMON_COMPILE_OPTIONS})
pico_keys_apply_strict_flags(
picokeys_apply_strict_flags(
SOURCES ${SOURCES}
FILTER_REGEX "/src/fido/|/pico-keys-sdk/src/|/pico-keys-sdk/config/"
)
@@ -193,12 +193,12 @@ if(NOT ESP_PLATFORM)
target_link_options(pico_fido PRIVATE ${EMULATION_NON_APPLE_LINK_OPTIONS})
endif()
target_link_libraries(pico_fido PRIVATE pico_keys_sdk mbedtls pthread m)
target_link_libraries(pico_fido PRIVATE picokeys_sdk mbedtls pthread m)
else()
target_link_libraries(
pico_fido
PRIVATE
pico_keys_sdk
picokeys_sdk
pico_stdlib
pico_multicore
hardware_flash

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h"
#endif
@@ -34,9 +34,9 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next);
const uint8_t aaguid[16] = { 0x89, 0xFB, 0x94, 0xB7, 0x06, 0xC9, 0x36, 0x73, 0x9B, 0x7E, 0x30, 0x52, 0x6D, 0x96, 0x81, 0x45 }; // First 16 bytes of SHA256("Pico FIDO2")
const uint8_t *cbor_data = NULL;
size_t cbor_len = 0;
uint8_t cbor_cmd = 0;
static const uint8_t *volatile cbor_data = NULL;
static volatile size_t cbor_len = 0;
static volatile uint8_t cbor_cmd = 0;
int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
if (len == 0 && cmd == CTAPHID_CBOR) {
@@ -108,7 +108,10 @@ void *cbor_thread(void *arg) {
if (m == EV_EXIT) {
break;
}
apdu.sw = (uint16_t)cbor_parse(cbor_cmd, cbor_data, cbor_len);
const uint8_t *data = (const uint8_t *)cbor_data;
size_t len = cbor_len;
uint8_t cmd = cbor_cmd;
apdu.sw = (uint16_t)cbor_parse(cmd, data, len);
if (apdu.sw == 0) {
DEBUG_DATA(res_APDU, res_APDU_size);
}

View File

@@ -15,11 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "mbedtls/ecp.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/sha256.h"
#include "mbedtls/hkdf.h"
#include "mbedtls/constant_time.h"
#include "cbor.h"
#include "ctap.h"
#include "ctap2_cbor.h"
@@ -99,7 +100,7 @@ static int regenerate(void) {
mbedtls_ecdh_init(&hkey);
hkey_init = true;
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1);
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_gen, NULL);
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_fill_iterator, NULL);
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
if (ret != 0) {
return ret;
@@ -131,7 +132,7 @@ static int kdf(uint8_t protocol, const mbedtls_mpi *z, uint8_t *sharedSecret) {
int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret) {
mbedtls_mpi z;
mbedtls_mpi_init(&z);
int ret = mbedtls_ecdh_compute_shared(&hkey.ctx.mbed_ecdh.grp, &z, Q, &hkey.ctx.mbed_ecdh.d, random_gen, NULL);
int ret = mbedtls_ecdh_compute_shared(&hkey.ctx.mbed_ecdh.grp, &z, Q, &hkey.ctx.mbed_ecdh.d, random_fill_iterator, NULL);
ret = kdf(protocol, &z, sharedSecret);
mbedtls_mpi_free(&z);
return ret;
@@ -142,11 +143,11 @@ static void resetAuthToken(bool persistent) {
if (persistent) {
fid = EF_PAUTHTOKEN;
}
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF);
file_t *ef = file_search_by_fid(fid, NULL, SPECIFY_EF);
uint8_t t[32];
random_gen(NULL, t, sizeof(t));
random_fill_buffer(t, sizeof(t));
file_put_data(ef, t, sizeof(t));
low_flash_available();
flash_commit();
}
int resetPinUvAuthToken(void) {
@@ -159,7 +160,7 @@ int resetPinUvAuthToken(void) {
int resetPersistentPinUvAuthToken(void) {
resetAuthToken(true);
file_t *ef_pauthtoken = search_by_fid(EF_PAUTHTOKEN, NULL, SPECIFY_EF);
file_t *ef_pauthtoken = file_search_by_fid(EF_PAUTHTOKEN, NULL, SPECIFY_EF);
ppaut.permissions = 0;
ppaut.data = file_get_data(ef_pauthtoken);
ppaut.len = file_get_size(ef_pauthtoken);
@@ -169,12 +170,12 @@ int resetPersistentPinUvAuthToken(void) {
int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out) {
if (protocol == 1) {
memcpy(out, in, in_len);
return aes_encrypt(key, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len);
return aes_encrypt(key, NULL, 32 * 8, PICOKEYS_AES_MODE_CBC, out, in_len);
}
else if (protocol == 2) {
random_gen(NULL, out, IV_SIZE);
random_fill_buffer(out, IV_SIZE);
memcpy(out + IV_SIZE, in, in_len);
return aes_encrypt(key + 32, out, 32 * 8, PICO_KEYS_AES_MODE_CBC, out + IV_SIZE, in_len);
return aes_encrypt(key + 32, out, 32 * 8, PICOKEYS_AES_MODE_CBC, out + IV_SIZE, in_len);
}
return -1;
@@ -183,11 +184,11 @@ int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in
int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, uint16_t in_len, uint8_t *out) {
if (protocol == 1) {
memcpy(out, in, in_len);
return aes_decrypt(key, NULL, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len);
return aes_decrypt(key, NULL, 32 * 8, PICOKEYS_AES_MODE_CBC, out, in_len);
}
else if (protocol == 2) {
memcpy(out, in + IV_SIZE, in_len - IV_SIZE);
return aes_decrypt(key + 32, in, 32 * 8, PICO_KEYS_AES_MODE_CBC, out, in_len - IV_SIZE);
return aes_decrypt(key + 32, in, 32 * 8, PICOKEYS_AES_MODE_CBC, out, in_len - IV_SIZE);
}
return -1;
@@ -221,10 +222,10 @@ int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t l
return ret;
}
if (protocol == 1) {
return ct_memcmp(sign, hmac, 16);
return mbedtls_ct_memcmp(sign, hmac, 16);
}
else if (protocol == 2) {
return ct_memcmp(sign, hmac, 32);
return mbedtls_ct_memcmp(sign, hmac, 32);
}
return -1;
}
@@ -266,9 +267,9 @@ static int check_keydev_encrypted(const uint8_t pin_token[32]) {
encrypt_with_aad(pin_token, file_get_data(ef_keydev) + 1, 32, 2, tmp_keydev + 1);
file_put_data(ef_keydev, tmp_keydev, sizeof(tmp_keydev));
mbedtls_platform_zeroize(tmp_keydev, sizeof(tmp_keydev));
low_flash_available();
flash_commit();
}
return PICOKEY_OK;
return PICOKEYS_OK;
}
uint8_t new_pin_mismatches = 0;
@@ -400,7 +401,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_len++;
}
uint8_t minPin = 4;
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) {
minPin = *file_get_data(ef_minpin);
}
@@ -415,11 +416,11 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
mbedtls_platform_zeroize(paddedNewPin, sizeof(paddedNewPin));
pin_derive_verifier(dhash, 16, hsh + 3);
file_put_data(ef_pin, hsh, sizeof(hsh));
low_flash_available();
flash_commit();
pin_derive_session(dhash, 16, session_pin);
ret = check_keydev_encrypted(session_pin);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
CBOR_ERROR(ret);
}
mbedtls_platform_zeroize(hsh, sizeof(hsh));
@@ -474,7 +475,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
memcpy(pin_data, file_get_data(ef_pin), file_get_size(ef_pin));
pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, file_get_size(ef_pin));
low_flash_available();
flash_commit();
uint8_t retries = pin_data[0];
uint8_t paddedNewPin[64];
ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, pinHashEnc.data, (uint16_t)pinHashEnc.len, paddedNewPin);
@@ -491,7 +492,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_derive_verifier(paddedNewPin, 16, dhash);
}
if (ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) {
if (mbedtls_ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) {
regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (retries == 0) {
@@ -512,7 +513,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
hash_multi(paddedNewPin, 16, session_pin);
ret = load_keydev(keydev);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
}
encrypt_keydev_f1(keydev);
@@ -520,10 +521,10 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_derive_session(paddedNewPin, 16, session_pin);
pin_data[0] = MAX_PIN_RETRIES;
file_put_data(ef_pin, pin_data, sizeof(pin_data));
low_flash_available();
flash_commit();
ret = check_keydev_encrypted(session_pin);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
CBOR_ERROR(ret);
}
@@ -541,7 +542,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_len++;
}
uint8_t minPin = 4;
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) {
minPin = *file_get_data(ef_minpin);
}
@@ -551,7 +552,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
// New PIN is valid and verified
ret = load_keydev(keydev);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
}
encrypt_keydev_f1(keydev);
@@ -559,17 +560,17 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, dhash);
pin_derive_session(dhash, 16, session_pin);
ret = check_keydev_encrypted(session_pin);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
CBOR_ERROR(ret);
}
low_flash_available();
flash_commit();
pin_data[0] = MAX_PIN_RETRIES;
pin_data[1] = pin_len;
pin_data[2] = 1; // New format indicator
pin_derive_verifier(dhash, 16, pin_data + 3);
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 && ct_memcmp(pin_data + 3, file_get_data(ef_pin) + 3, 32) == 0) {
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 && mbedtls_ct_memcmp(pin_data + 3, file_get_data(ef_pin) + 3, 32) == 0) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
}
file_put_data(ef_pin, pin_data, sizeof(pin_data));
@@ -583,7 +584,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
file_put_data(ef_minpin, tmpf, file_get_size(ef_minpin));
free(tmpf);
}
low_flash_available();
flash_commit();
resetPinUvAuthToken();
resetPersistentPinUvAuthToken();
needs_power_cycle = false;
@@ -636,7 +637,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
memcpy(pin_data, file_get_data(ef_pin), file_get_size(ef_pin));
pin_data[0] -= 1;
file_put_data(ef_pin, pin_data, file_get_size(ef_pin));
low_flash_available();
flash_commit();
uint8_t retries = pin_data[0];
uint8_t paddedNewPin[64], poff = ((uint8_t)pinUvAuthProtocol - 1) * IV_SIZE;
ret = decrypt((uint8_t)pinUvAuthProtocol, sharedSecret, pinHashEnc.data, (uint16_t)pinHashEnc.len, paddedNewPin);
@@ -652,7 +653,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
else {
pin_derive_verifier(paddedNewPin, 16, dhash);
}
if (ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) {
if (mbedtls_ct_memcmp(dhash, file_get_data(ef_pin) + off, 32) != 0) {
regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
mbedtls_platform_zeroize(dhash, sizeof(dhash));
@@ -675,7 +676,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_derive_verifier(paddedNewPin, 16, pin_data + 3);
hash_multi(paddedNewPin, 16, session_pin);
ret = load_keydev(keydev);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
}
encrypt_keydev_f1(keydev);
@@ -683,7 +684,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_derive_session(paddedNewPin, 16, session_pin);
ret = check_keydev_encrypted(session_pin);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
CBOR_ERROR(ret);
}
@@ -693,8 +694,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
file_put_data(ef_pin, pin_data, sizeof(pin_data));
mbedtls_platform_zeroize(pin_data, sizeof(pin_data));
low_flash_available();
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
flash_commit();
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "ctap2_cbor.h"
#include "fido.h"
#include "ctap.h"
@@ -151,7 +151,7 @@ int cbor_config(const uint8_t *data, size_t len) {
file_put_data(ef_keydev, keydev_dec, sizeof(keydev_dec));
mbedtls_platform_zeroize(keydev_dec, sizeof(keydev_dec));
file_put_data(ef_keydev_enc, NULL, 0); // Set ef to 0 bytes
low_flash_available();
flash_commit();
}
else if (vendorCommandId == CTAP_CONFIG_AUT_ENABLE) {
if (!file_has_data(ef_keydev)) {
@@ -168,7 +168,7 @@ int cbor_config(const uint8_t *data, size_t len) {
}
uint8_t key_dev_enc[12 + 32 + 16];
random_gen(NULL, key_dev_enc, 12);
random_fill_buffer(key_dev_enc, 12);
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, vendorParamByteString.data);
ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, file_get_size(ef_keydev), key_dev_enc, NULL, 0, file_get_data(ef_keydev), key_dev_enc + 12, key_dev_enc + 12 + file_get_size(ef_keydev));
@@ -181,17 +181,17 @@ int cbor_config(const uint8_t *data, size_t len) {
mbedtls_platform_zeroize(key_dev_enc, sizeof(key_dev_enc));
file_put_data(ef_keydev, key_dev_enc, file_get_size(ef_keydev)); // Overwrite ef with 0
file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes
low_flash_available();
flash_commit();
}
else if (vendorCommandId == CTAP_CONFIG_EA_UPLOAD) {
if (vendorParamByteString.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
file_t *ef_ee_ea = search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
file_t *ef_ee_ea = file_search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
if (ef_ee_ea) {
file_put_data(ef_ee_ea, vendorParamByteString.data, (uint16_t)vendorParamByteString.len);
}
low_flash_available();
flash_commit();
}
else if (vendorCommandId == CTAP_CONFIG_PIN_POLICY) {
file_t *ef_pin_policy = file_new(EF_PIN_COMPLEXITY_POLICY);
@@ -206,7 +206,7 @@ int cbor_config(const uint8_t *data, size_t len) {
free(val);
}
}
low_flash_available();
flash_commit();
}
else {
CBOR_ERROR(CTAP2_ERR_INVALID_SUBCOMMAND);
@@ -215,7 +215,7 @@ int cbor_config(const uint8_t *data, size_t len) {
}
else if (subcommand == 0x03) {
uint8_t currentMinPinLen = 4;
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) {
currentMinPinLen = *file_get_data(ef_minpin);
}
@@ -242,7 +242,7 @@ int cbor_config(const uint8_t *data, size_t len) {
mbedtls_sha256((uint8_t *) minPinLengthRPIDs[m].data, minPinLengthRPIDs[m].len, dataf + 2 + m * 32, 0);
}
file_put_data(ef_minpin, dataf, (uint16_t)(2 + minPinLengthRPIDs_len * 32));
low_flash_available();
flash_commit();
free(dataf);
goto err; //No return
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "fido.h"
#include "ctap.h"
#include "hid/ctap_hid.h"
@@ -137,7 +137,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
}
uint8_t existing = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
if (file_has_data(search_dynamic_file((uint16_t)(EF_CRED + i)))) {
if (file_has_data(file_search((uint16_t)(EF_CRED + i)))) {
existing++;
}
}
@@ -173,7 +173,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
}
uint8_t skip = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *tef = search_dynamic_file((uint16_t)(EF_RP + i));
file_t *tef = file_search((uint16_t)(EF_RP + i));
if (file_has_data(tef) && *file_get_data(tef) > 0) {
if (++skip == rp_counter) {
if (rp_ef == NULL) {
@@ -239,7 +239,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
file_t *cred_ef = NULL;
uint8_t skip = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *tef = search_dynamic_file((uint16_t)(EF_CRED + i));
file_t *tef = file_search((uint16_t)(EF_CRED + i));
if (file_has_data(tef) && memcmp(file_get_data(tef), rpIdHash.data, 32) == 0) {
if (++skip == cred_counter) {
if (cred_ef == NULL) {
@@ -373,20 +373,20 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
file_t *ef = file_search((uint16_t)(EF_CRED + i));
if (file_has_data(ef) && memcmp(file_get_data(ef) + 32, credentialId.id.data, CRED_RESIDENT_LEN) == 0) {
uint8_t *rp_id_hash = file_get_data(ef);
if (delete_file(ef) != 0) {
if (file_delete(ef) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
for (int j = 0; j < MAX_RESIDENT_CREDENTIALS; j++) {
file_t *rp_ef = search_dynamic_file((uint16_t)(EF_RP + j));
file_t *rp_ef = file_search((uint16_t)(EF_RP + j));
if (file_has_data(rp_ef) && memcmp(file_get_data(rp_ef) + 1, rp_id_hash, 32) == 0) {
uint8_t *rp_data = (uint8_t *) calloc(1, file_get_size(rp_ef));
memcpy(rp_data, file_get_data(rp_ef), file_get_size(rp_ef));
rp_data[0] -= 1;
if (rp_data[0] == 0) {
delete_file(rp_ef);
file_delete(rp_ef);
}
else {
file_put_data(rp_ef, rp_data, file_get_size(rp_ef));
@@ -395,7 +395,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
break;
}
}
low_flash_available();
flash_commit();
goto err; //no error
}
}
@@ -415,7 +415,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
file_t *ef = file_search((uint16_t)(EF_CRED + i));
if (file_has_data(ef) && memcmp(file_get_data(ef) + 32, credentialId.id.data, CRED_RESIDENT_LEN) == 0) {
Credential cred = { 0 };
uint8_t *rp_id_hash = file_get_data(ef);
@@ -439,7 +439,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
if (credential_store(newcred, newcred_len, rp_id_hash) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
low_flash_available();
flash_commit();
goto err; //no error
}
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "cbor.h"
#include "ctap.h"
#if defined(PICO_PLATFORM)
@@ -32,6 +32,7 @@
#include "random.h"
int cbor_get_assertion(const uint8_t *data, size_t len, bool next);
extern char *rp_id, *user_name, *display_name;
bool residentx = false;
Credential credsx[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 };
@@ -205,6 +206,9 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
if (rpId.present == false || clientDataHash.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
rp_id = rpId.data;
user_name = NULL;
display_name = NULL;
uint8_t flags = 0;
uint8_t rp_id_hash[32] = {0};
@@ -301,7 +305,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
if (credential_is_resident(allowList[e].id.data, allowList[e].id.len)) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
file_t *ef = file_search((uint16_t)(EF_CRED + i));
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue;
}
@@ -328,7 +332,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
// Even we provide allowList, we need to check if the credential is resident
if (!resident) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
file_t *ef = file_search((uint16_t)(EF_CRED + i));
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue;
}
@@ -347,7 +351,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
else {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
file_t *ef = file_search((uint16_t)(EF_CRED + i));
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue;
}
@@ -401,7 +405,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
}
if (credential_is_resident(allowList[e].id.data, allowList[e].id.len)) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_CRED + i));
file_t *ef = file_search((uint16_t)(EF_CRED + i));
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue;
}
@@ -611,7 +615,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
uint8_t *pa = aut_data;
memcpy(pa, rp_id_hash, 32); pa += 32;
*pa++ = flags;
pa += put_uint32_t_be(ctr, pa);
pa += put_uint32_be(ctr, pa);
memcpy(pa, ext, ext_len); pa += ext_len;
if ((size_t)(pa - aut_data) != aut_data_len) {
CBOR_ERROR(CTAP1_ERR_OTHER);
@@ -644,11 +648,11 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
#endif
if (md != NULL) {
ret = mbedtls_md(md, aut_data, aut_data_len + clientDataHash.len, hash);
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL);
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_fill_iterator, NULL);
}
#ifdef MBEDTLS_EDDSA_C
else {
ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_gen, NULL);
ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_fill_iterator, NULL);
}
#endif
}
@@ -739,7 +743,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
ctr++;
file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available();
flash_commit();
err:
CBOR_FREE_BYTE_STRING(clientDataHash);
CBOR_FREE_BYTE_STRING(pinUvAuthParam);

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "ctap2_cbor.h"
#include "hid/ctap_hid.h"
#include "fido.h"
@@ -36,7 +36,7 @@ int cbor_get_info(void) {
#else
lfields++;
#endif
file_t *ef_pin_policy = search_by_fid(EF_PIN_COMPLEXITY_POLICY, NULL, SPECIFY_EF);
file_t *ef_pin_policy = file_search_by_fid(EF_PIN_COMPLEXITY_POLICY, NULL, SPECIFY_EF);
if (file_has_data(ef_pin_policy)) {
lfields += 2;
}
@@ -144,7 +144,7 @@ int cbor_get_info(void) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_LARGE_BLOB_SIZE)); // maxSerializedLargeBlobArray
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0C));
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "ctap2_cbor.h"
#include "fido.h"
#include "ctap.h"
@@ -129,7 +129,7 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
uint8_t verify_data[70] = { 0 };
memset(verify_data, 0xff, 32);
verify_data[32] = 0x0C;
put_uint32_t_le((uint32_t)offset, verify_data + 34);
put_uint32_le((uint32_t)offset, verify_data + 34);
mbedtls_sha256(set.data, set.len, verify_data + 38, 0);
if (verify((uint8_t)pinUvAuthProtocol, paut.data, verify_data, (uint16_t)sizeof(verify_data), pinUvAuthParam.data) != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
@@ -152,7 +152,7 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_INTEGRITY_FAILURE);
}
file_put_data(ef_largeblob, temp_lba, (uint16_t)expectedLength);
low_flash_available();
flash_commit();
}
goto err;
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "cbor_make_credential.h"
#include "ctap2_cbor.h"
#include "hid/ctap_hid.h"
@@ -28,6 +28,8 @@
#include "random.h"
#include "crypto_utils.h"
char *rp_id = NULL, *user_name = NULL, *display_name = NULL;
int cbor_make_credential(const uint8_t *data, size_t len) {
CborParser parser;
CborValue map;
@@ -192,6 +194,9 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
}
CBOR_PARSE_MAP_END(map, 1);
rp_id = rp.id.data;
user_name = user.parent.name.data;
display_name = user.displayName.data;
uint8_t flags = FIDO2_AUT_FLAG_AT;
uint8_t rp_id_hash[32] = {0};
@@ -352,7 +357,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
Credential ecred = {0};
if (credential_is_resident(excludeList[e].id.data, excludeList[e].id.len)) {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef_cred = search_dynamic_file((uint16_t)(EF_CRED + i));
file_t *ef_cred = file_search((uint16_t)(EF_CRED + i));
if (!file_has_data(ef_cred) || memcmp(file_get_data(ef_cred), rp_id_hash, 32) != 0) {
continue;
}
@@ -423,7 +428,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
l++;
}
if (extensions.minPinLength == ptrue) {
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
file_t *ef_minpin = file_search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) {
uint8_t *minpin_data = file_get_data(ef_minpin);
for (int o = 2; o < file_get_size(ef_minpin); o += 32) {
@@ -517,7 +522,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
if (pin_complexity_policy == ptrue) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "pinComplexityPolicy"));
file_t *ef_pin_complexity_policy = search_by_fid(EF_PIN_COMPLEXITY_POLICY, NULL, SPECIFY_EF);
file_t *ef_pin_complexity_policy = file_search_by_fid(EF_PIN_COMPLEXITY_POLICY, NULL, SPECIFY_EF);
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, file_has_data(ef_pin_complexity_policy)));
}
@@ -550,16 +555,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
uint8_t *pa = aut_data;
memcpy(pa, rp_id_hash, 32); pa += 32;
*pa++ = flags;
pa += put_uint32_t_be(ctr, pa);
pa += put_uint32_be(ctr, pa);
memcpy(pa, aaguid, 16); pa += 16;
if (options.rk == ptrue) {
uint8_t cred_idr[CRED_RESIDENT_LEN] = {0};
pa += put_uint16_t_be(sizeof(cred_idr), pa);
pa += put_uint16_be(sizeof(cred_idr), pa);
credential_derive_resident(cred_id, cred_id_len, cred_idr);
memcpy(pa, cred_idr, sizeof(cred_idr)); pa += sizeof(cred_idr);
}
else {
pa += put_uint16_t_be(cred_id_len, pa);
pa += put_uint16_be(cred_id_len, pa);
memcpy(pa, cred_id, cred_id_len); pa += (uint16_t)cred_id_len;
}
memcpy(pa, cbor_buf, rs); pa += (uint16_t)rs;
@@ -601,11 +606,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
self_attestation = false;
}
if (md != NULL) {
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_gen, NULL);
ret = mbedtls_ecdsa_write_signature(&ekey, mbedtls_md_get_type(md), hash, mbedtls_md_get_size(md), sig, sizeof(sig), &olen, random_fill_iterator, NULL);
}
#ifdef MBEDTLS_EDDSA_C
else {
ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_gen, NULL);
ret = mbedtls_eddsa_write_signature(&ekey, aut_data, aut_data_len + clientDataHash.len, sig, sizeof(sig), &olen, MBEDTLS_EDDSA_PURE, NULL, 0, random_fill_iterator, NULL);
}
#endif
mbedtls_ecp_keypair_free(&ekey);
@@ -646,7 +651,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CborEncoder arrEncoder;
file_t *ef_cert = NULL;
if (enterpriseAttestation == 2) {
ef_cert = search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
ef_cert = file_search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
}
if (!file_has_data(ef_cert)) {
ef_cert = ef_certdev;
@@ -678,7 +683,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
}
ctr++;
file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available();
flash_commit();
err:
CBOR_FREE_BYTE_STRING(clientDataHash);
CBOR_FREE_BYTE_STRING(pinUvAuthParam);

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "file.h"
#include "fido.h"
#include "ctap2_cbor.h"
@@ -35,11 +35,11 @@ int cbor_reset(void) {
return CTAP2_ERR_NOT_ALLOWED;
}
#endif
if (wait_button_pressed() == true) {
if (wait_button_pressed() > 0) {
return CTAP2_ERR_USER_ACTION_TIMEOUT;
}
#endif
initialize_flash(true);
file_initialize_flash(true);
init_fido();
return 0;
}

View File

@@ -15,14 +15,21 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "fido.h"
#include "ctap2_cbor.h"
#include "ctap.h"
extern char *rp_id, *user_name, *display_name;
int cbor_selection(void) {
if (wait_button_pressed() == true) {
rp_id = user_name = display_name = NULL;
int ret = wait_button_pressed() ;
if (ret == 1) {
return CTAP2_ERR_USER_ACTION_TIMEOUT;
}
else if (ret == 2) {
return CTAP2_ERR_OPERATION_DENIED;
}
return CTAP2_OK;
}

View File

@@ -15,7 +15,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "serial.h"
#include "ctap2_cbor.h"
#include "fido.h"
#include "ctap.h"
@@ -116,7 +117,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
file_put_data(ef_keydev_enc, vendorParam.data, (uint16_t)vendorParam.len);
file_put_data(ef_keydev, zeros, file_get_size(ef_keydev)); // Overwrite ef with 0
file_put_data(ef_keydev, NULL, 0); // Set ef to 0 bytes
low_flash_available();
flash_commit();
goto err;
}
else {
@@ -132,7 +133,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
mbedtls_ecdh_context hkey;
mbedtls_ecdh_init(&hkey);
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1);
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_gen, NULL);
int ret = mbedtls_ecdh_gen_public(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.d, &hkey.ctx.mbed_ecdh.Q, random_fill_iterator, NULL);
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -154,7 +155,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
ret = mbedtls_ecdh_calc_secret(&hkey, &olen, buf, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL);
ret = mbedtls_ecdh_calc_secret(&hkey, &olen, buf, MBEDTLS_ECP_MAX_BYTES, random_fill_iterator, NULL);
if (ret != 0) {
mbedtls_ecdh_free(&hkey);
mbedtls_platform_zeroize(buf, sizeof(buf));
@@ -216,7 +217,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING);
}
ret = mbedtls_ecp_mul(&ekey.grp, &ekey.Q, &ekey.d, &ekey.grp.G, random_gen, NULL);
ret = mbedtls_ecp_keypair_calc_public(&ekey, random_fill_iterator, NULL);
if (ret != 0) {
mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING);
@@ -232,7 +233,7 @@ static int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
mbedtls_x509write_csr_set_key(&ctx, &key);
mbedtls_x509write_csr_set_md_alg(&ctx, MBEDTLS_MD_SHA256);
mbedtls_x509write_csr_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xE5\x1C\x01\x01\x04", 0xB, 0, aaguid, sizeof(aaguid));
ret = mbedtls_x509write_csr_der(&ctx, buffer, sizeof(buffer), random_gen, NULL);
ret = mbedtls_x509write_csr_der(&ctx, buffer, sizeof(buffer), random_fill_iterator, NULL);
mbedtls_ecdsa_free(&ekey);
if (ret <= 0) {
mbedtls_x509write_csr_free(&ctx);

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "fido.h"
#include "apdu.h"
#include "ctap.h"
@@ -26,7 +26,7 @@
int cmd_authenticate(void) {
CTAP_AUTHENTICATE_REQ *req = (CTAP_AUTHENTICATE_REQ *) apdu.data;
CTAP_AUTHENTICATE_RESP *resp = (CTAP_AUTHENTICATE_RESP *) res_APDU;
//if (scan_files_fido(true) != PICOKEY_OK)
//if (scan_files_fido(true) != PICOKEYS_OK)
// return SW_EXEC_ERROR();
if (apdu.nc < CTAP_CHAL_SIZE + CTAP_APPID_SIZE + 1 + 1) {
return SW_WRONG_DATA();
@@ -34,7 +34,7 @@ int cmd_authenticate(void) {
if (req->keyHandleLen < KEY_HANDLE_LEN) {
return SW_INCORRECT_PARAMS();
}
if (P1(apdu) == CTAP_AUTH_ENFORCE && wait_button_pressed() == true) {
if (P1(apdu) == CTAP_AUTH_ENFORCE && wait_button_pressed() > 0) {
return SW_CONDITIONS_NOT_SATISFIED();
}
@@ -55,7 +55,7 @@ int cmd_authenticate(void) {
}
}
free(tmp_kh);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
mbedtls_ecp_keypair_free(&key);
return SW_EXEC_ERROR();
}
@@ -66,7 +66,7 @@ int cmd_authenticate(void) {
resp->flags = 0;
resp->flags |= P1(apdu) == CTAP_AUTH_ENFORCE ? CTAP_AUTH_FLAG_TUP : 0x0;
uint32_t ctr = get_sign_counter();
put_uint32_t_be(ctr, resp->ctr);
put_uint32_be(ctr, resp->ctr);
uint8_t hash[32], sig_base[CTAP_APPID_SIZE + 1 + 4 + CTAP_CHAL_SIZE];
memcpy(sig_base, req->appId, CTAP_APPID_SIZE);
memcpy(sig_base + CTAP_APPID_SIZE, &resp->flags, sizeof(uint8_t));
@@ -78,7 +78,7 @@ int cmd_authenticate(void) {
return SW_EXEC_ERROR();
}
size_t olen = 0;
ret = mbedtls_ecdsa_write_signature(&key, MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->sig, CTAP_MAX_EC_SIG_SIZE, &olen, random_gen, NULL);
ret = mbedtls_ecdsa_write_signature(&key, MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->sig, CTAP_MAX_EC_SIG_SIZE, &olen, random_fill_iterator, NULL);
mbedtls_ecp_keypair_free(&key);
if (ret != 0) {
return SW_EXEC_ERROR();
@@ -87,6 +87,6 @@ int cmd_authenticate(void) {
ctr++;
file_put_data(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available();
flash_commit();
return SW_OK();
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "fido.h"
#include "apdu.h"
#include "ctap.h"
@@ -37,9 +37,9 @@ static int u2f_select(app_t *a, uint8_t force) {
if (cap_supported(CAP_U2F)) {
a->process_apdu = u2f_process_apdu;
a->unload = u2f_unload;
return PICOKEY_OK;
return PICOKEYS_OK;
}
return PICOKEY_ERR_FILE_NOT_FOUND;
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
INITIALIZER ( u2f_ctor ) {
@@ -47,7 +47,7 @@ INITIALIZER ( u2f_ctor ) {
}
int u2f_unload(void) {
return PICOKEY_OK;
return PICOKEYS_OK;
}
const uint8_t *bogus_firefox = (const uint8_t *) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
@@ -58,12 +58,12 @@ int cmd_register(void) {
CTAP_REGISTER_RESP *resp = (CTAP_REGISTER_RESP *) res_APDU;
resp->registerId = CTAP_REGISTER_ID;
resp->keyHandleLen = KEY_HANDLE_LEN;
//if (scan_files_fido(true) != PICOKEY_OK)
//if (scan_files_fido(true) != PICOKEYS_OK)
// return SW_EXEC_ERROR();
if (apdu.nc != CTAP_APPID_SIZE + CTAP_CHAL_SIZE) {
return SW_WRONG_LENGTH();
}
if (wait_button_pressed() == true) {
if (wait_button_pressed() > 0) {
return SW_CONDITIONS_NOT_SATISFIED();
}
if (memcmp(req->appId, bogus_firefox,
@@ -72,7 +72,7 @@ int cmd_register(void) {
mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key);
int ret = derive_key(req->appId, true, resp->keyHandleCertSig, MBEDTLS_ECP_DP_SECP256R1, &key);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR();
}
@@ -97,16 +97,16 @@ int cmd_register(void) {
mbedtls_ecdsa_init(&key);
uint8_t key_dev[32] = {0};
ret = load_keydev(key_dev);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
return SW_EXEC_ERROR();
}
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, key_dev, 32);
mbedtls_platform_zeroize(key_dev, sizeof(key_dev));
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR();
}
ret = mbedtls_ecdsa_write_signature(&key,MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->keyHandleCertSig + KEY_HANDLE_LEN + ef_certdev_size, CTAP_MAX_EC_SIG_SIZE, &olen, random_gen, NULL);
ret = mbedtls_ecdsa_write_signature(&key,MBEDTLS_MD_SHA256, hash, 32, (uint8_t *) resp->keyHandleCertSig + KEY_HANDLE_LEN + ef_certdev_size, CTAP_MAX_EC_SIG_SIZE, &olen, random_fill_iterator, NULL);
mbedtls_ecdsa_free(&key);
if (ret != 0) {
return SW_EXEC_ERROR();

View File

@@ -16,7 +16,7 @@
*/
#include "apdu.h"
#include "pico_keys.h"
#include "picokeys.h"
#include "fido.h"
int cmd_version(void) {

View File

@@ -15,7 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "serial.h"
#include "pico_time.h"
#include "mbedtls/chachapoly.h"
#include "mbedtls/sha256.h"
#include "credential.h"
@@ -158,7 +160,7 @@ int credential_create(CborCharString *rpId,
uint8_t key[32] = {0};
credential_derive_chacha_key(key, (const uint8_t *)CRED_PROTO);
uint8_t iv[CRED_IV_LEN] = {0};
random_gen(NULL, iv, sizeof(iv));
random_fill_buffer(iv, sizeof(iv));
mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key);
@@ -310,7 +312,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
return ret;
}
for (uint16_t i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = search_dynamic_file(EF_CRED + i);
file_t *ef = file_search(EF_CRED + i);
Credential rcred = { 0 };
if (!file_has_data(ef)) {
if (sloti == -1) {
@@ -350,7 +352,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
if (new_record == true) { //increase rps
sloti = -1;
for (uint16_t i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
ef = search_dynamic_file(EF_RP + i);
ef = file_search(EF_RP + i);
if (!file_has_data(ef)) {
if (sloti == -1) {
sloti = i;
@@ -365,7 +367,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
if (sloti == -1) {
return -1;
}
ef = search_dynamic_file((uint16_t)(EF_RP + sloti));
ef = file_search((uint16_t)(EF_RP + sloti));
if (file_has_data(ef)) {
data = (uint8_t *) calloc(1, file_get_size(ef));
memcpy(data, file_get_data(ef), file_get_size(ef));
@@ -384,7 +386,7 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
}
}
credential_free(&cred);
low_flash_available();
flash_commit();
return 0;
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "fido.h"
#include "version.h"

View File

@@ -15,8 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "fido.h"
#include "serial.h"
#include "apdu.h"
#include "ctap.h"
#include "files.h"
@@ -75,9 +76,9 @@ static int fido_select(app_t *a, uint8_t force) {
if (cap_supported(CAP_FIDO2)) {
a->process_apdu = fido_process_apdu;
a->unload = fido_unload;
return PICOKEY_OK;
return PICOKEYS_OK;
}
return PICOKEY_ERR_FILE_NOT_FOUND;
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
extern uint8_t (*get_version_major)(void);
@@ -94,7 +95,7 @@ INITIALIZER ( fido_ctor ) {
}
static int fido_unload(void) {
return PICOKEY_OK;
return PICOKEYS_OK;
}
mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
@@ -191,7 +192,7 @@ static int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_
mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO");
mbedtls_x509write_crt_set_subject_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO");
uint8_t serial[16];
random_gen(NULL, serial, sizeof(serial));
random_fill_buffer(serial, sizeof(serial));
mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial));
mbedtls_pk_context key;
mbedtls_pk_init(&key);
@@ -206,7 +207,7 @@ static int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_
mbedtls_x509write_crt_set_key_usage(&ctx,
MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
MBEDTLS_X509_KU_KEY_CERT_SIGN);
int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_gen, NULL);
int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_fill_iterator, NULL);
mbedtls_x509write_crt_free(&ctx);
/* pk cannot be freed, as it is freed later */
//mbedtls_pk_free(&key);
@@ -215,7 +216,7 @@ static int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_
int load_keydev(uint8_t key[32]) {
if (has_keydev_dec == false && !file_has_data(ef_keydev)) {
return PICOKEY_ERR_MEMORY_FATAL;
return PICOKEYS_ERR_MEMORY_FATAL;
}
if (has_keydev_dec == true) {
@@ -225,8 +226,8 @@ int load_keydev(uint8_t key[32]) {
uint16_t fid_size = file_get_size(ef_keydev);
if (fid_size == 32) {
memcpy(key, file_get_data(ef_keydev), 32);
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;
if (otp_key_1 && aes_decrypt(otp_key_1, NULL, 32 * 8, PICOKEYS_AES_MODE_CBC, key, 32) != PICOKEYS_OK) {
return PICOKEYS_EXEC_ERROR;
}
}
else if (fid_size == 33 || fid_size == 61) {
@@ -236,18 +237,18 @@ int load_keydev(uint8_t key[32]) {
uint8_t tmp_key[61], version = format == 0x03 ? 2 : 1;
memcpy(tmp_key, file_get_data(ef_keydev), sizeof(tmp_key));
int ret = decrypt_with_aad(session_pin, tmp_key + 1, 60, version, key);
if (ret != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
if (ret != PICOKEYS_OK) {
return PICOKEYS_EXEC_ERROR;
}
if (format == 0x02) {
tmp_key[0] = 0x03;
ret = encrypt_with_aad(session_pin, key, 32, 2, tmp_key + 1);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
mbedtls_platform_zeroize(tmp_key, sizeof(tmp_key));
return PICOKEY_EXEC_ERROR;
return PICOKEYS_EXEC_ERROR;
}
file_put_data(ef_keydev, tmp_key, sizeof(tmp_key));
low_flash_available();
flash_commit();
}
mbedtls_platform_zeroize(tmp_key, sizeof(tmp_key));
}
@@ -256,17 +257,17 @@ int load_keydev(uint8_t key[32]) {
}
uint8_t kbase[32];
derive_kbase(kbase);
int ret = aes_decrypt(kbase, pico_serial_hash, 32 * 8, PICO_KEYS_AES_MODE_CBC, key, 32);
if (ret != PICOKEY_OK) {
int ret = aes_decrypt(kbase, pico_serial_hash, 32 * 8, PICOKEYS_AES_MODE_CBC, key, 32);
if (ret != PICOKEYS_OK) {
mbedtls_platform_zeroize(kbase, sizeof(kbase));
return PICOKEY_EXEC_ERROR;
return PICOKEYS_EXEC_ERROR;
}
mbedtls_platform_zeroize(kbase, sizeof(kbase));
}
}
}
return PICOKEY_OK;
return PICOKEYS_OK;
}
int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *key) {
@@ -307,7 +308,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
uint8_t outk[67] = { 0 }; //SECP521R1 key is 66 bytes length
int r = 0;
memset(outk, 0, sizeof(outk));
if ((r = load_keydev(outk)) != PICOKEY_OK) {
if ((r = load_keydev(outk)) != PICOKEYS_OK) {
printf("Error loading keydev: %d\n", r);
return r;
}
@@ -315,7 +316,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
for (size_t i = 0; i < KEY_PATH_ENTRIES; i++) {
if (new_key == true) {
uint32_t val = 0;
random_gen(NULL, (uint8_t *) &val, sizeof(val));
random_fill_buffer((uint8_t *) &val, sizeof(val));
val |= 0x80000000;
memcpy(&key_handle[i * sizeof(uint32_t)], &val, sizeof(uint32_t));
}
@@ -348,12 +349,7 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
if (r != 0) {
return r;
}
#ifdef MBEDTLS_EDDSA_C
if (curve == MBEDTLS_ECP_DP_ED25519) {
return mbedtls_ecp_point_edwards(&key->grp, &key->Q, &key->d, random_gen, NULL);
}
#endif
return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL);
return mbedtls_ecp_keypair_calc_public(key, random_fill_iterator, NULL);
}
mbedtls_platform_zeroize(outk, sizeof(outk));
return r;
@@ -365,27 +361,26 @@ int encrypt_keydev_f1(const uint8_t keydev[32]) {
memcpy(kdata + 1, keydev, 32);
uint8_t kbase[32];
derive_kbase(kbase);
int ret = aes_encrypt(kbase, pico_serial_hash, 32 * 8, PICO_KEYS_AES_MODE_CBC, kdata + 1, 32);
int ret = aes_encrypt(kbase, pico_serial_hash, 32 * 8, PICOKEYS_AES_MODE_CBC, kdata + 1, 32);
mbedtls_platform_zeroize(kbase, sizeof(kbase));
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
return ret;
}
ret = file_put_data(ef_keydev, kdata, 33);
mbedtls_platform_zeroize(kdata, sizeof(kdata));
low_flash_available();
flash_commit();
return ret;
}
int scan_files_fido(void) {
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_keydev = file_search_by_fid(EF_KEY_DEV, NULL, SPECIFY_EF);
ef_keydev_enc = file_search_by_fid(EF_KEY_DEV_ENC, 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...");
mbedtls_ecdsa_context ecdsa;
mbedtls_ecdsa_init(&ecdsa);
uint8_t index = 0;
int ret = mbedtls_ecdsa_genkey(&ecdsa, MBEDTLS_ECP_DP_SECP256R1, random_gen, &index);
int ret = mbedtls_ecdsa_genkey(&ecdsa, MBEDTLS_ECP_DP_SECP256R1, random_fill_iterator, NULL);
if (ret != 0) {
mbedtls_ecdsa_free(&ecdsa);
return ret;
@@ -396,12 +391,12 @@ int scan_files_fido(void) {
if (ret != 0 || key_size != 32) {
mbedtls_platform_zeroize(keydev, sizeof(keydev));
mbedtls_ecdsa_free(&ecdsa);
return ret != 0 ? ret : PICOKEY_EXEC_ERROR;
return ret != 0 ? ret : PICOKEYS_EXEC_ERROR;
}
encrypt_keydev_f1(keydev);
mbedtls_platform_zeroize(keydev, sizeof(keydev));
mbedtls_ecdsa_free(&ecdsa);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
return ret;
}
printf(" done!\n");
@@ -410,7 +405,7 @@ int scan_files_fido(void) {
else {
printf("FATAL ERROR: KEY DEV not found in memory!\r\n");
}
ef_certdev = search_by_fid(EF_EE_DEV, NULL, SPECIFY_EF);
ef_certdev = file_search_by_fid(EF_EE_DEV, NULL, SPECIFY_EF);
if (ef_certdev) {
if (!file_has_data(ef_certdev)) {
uint8_t cert[2048], outk[32];
@@ -426,7 +421,7 @@ int scan_files_fido(void) {
mbedtls_ecdsa_free(&key);
return ret;
}
ret = mbedtls_ecp_mul(&key.grp, &key.Q, &key.d, &key.grp.G, random_gen, NULL);
ret = mbedtls_ecp_keypair_calc_public(&key, random_fill_iterator, NULL);
if (ret != 0) {
mbedtls_ecdsa_free(&key);
return ret;
@@ -442,7 +437,7 @@ int scan_files_fido(void) {
else {
printf("FATAL ERROR: CERT DEV not found in memory!\r\n");
}
ef_counter = search_by_fid(EF_COUNTER, NULL, SPECIFY_EF);
ef_counter = file_search_by_fid(EF_COUNTER, NULL, SPECIFY_EF);
if (ef_counter) {
if (!file_has_data(ef_counter)) {
uint32_t v = 0;
@@ -452,13 +447,13 @@ int scan_files_fido(void) {
else {
printf("FATAL ERROR: Global counter not found in memory!\r\n");
}
ef_pin = search_by_fid(EF_PIN, NULL, SPECIFY_EF);
ef_pin_admin = search_by_fid(EF_PIN_ADMIN, NULL, SPECIFY_EF);
ef_authtoken = search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF);
ef_pin = file_search_by_fid(EF_PIN, NULL, SPECIFY_EF);
ef_pin_admin = file_search_by_fid(EF_PIN_ADMIN, NULL, SPECIFY_EF);
ef_authtoken = file_search_by_fid(EF_AUTHTOKEN, NULL, SPECIFY_EF);
if (ef_authtoken) {
if (!file_has_data(ef_authtoken)) {
uint8_t t[32];
random_gen(NULL, t, sizeof(t));
random_fill_buffer(t, sizeof(t));
file_put_data(ef_authtoken, t, sizeof(t));
}
paut.data = file_get_data(ef_authtoken);
@@ -467,11 +462,11 @@ int scan_files_fido(void) {
else {
printf("FATAL ERROR: Auth Token not found in memory!\r\n");
}
file_t *ef_pauthtoken = search_by_fid(EF_PAUTHTOKEN, NULL, SPECIFY_EF);
file_t *ef_pauthtoken = file_search_by_fid(EF_PAUTHTOKEN, NULL, SPECIFY_EF);
if (ef_pauthtoken) {
if (!file_has_data(ef_pauthtoken)) {
uint8_t t[32];
random_gen(NULL, t, sizeof(t));
random_fill_buffer(t, sizeof(t));
file_put_data(ef_pauthtoken, t, sizeof(t));
}
ppaut.data = file_get_data(ef_pauthtoken);
@@ -480,17 +475,17 @@ int scan_files_fido(void) {
else {
printf("FATAL ERROR: Persistent Auth Token not found in memory!\r\n");
}
ef_largeblob = search_by_fid(EF_LARGEBLOB, NULL, SPECIFY_EF);
ef_largeblob = file_search_by_fid(EF_LARGEBLOB, NULL, SPECIFY_EF);
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);
}
low_flash_available();
return PICOKEY_OK;
flash_commit();
return PICOKEYS_OK;
}
void scan_all(void) {
scan_flash();
file_scan_flash();
scan_files_fido();
}
@@ -503,22 +498,28 @@ void init_fido(void) {
needs_power_cycle = false;
}
bool wait_button_pressed(void) {
int wait_button_pressed(void) {
uint32_t val = EV_PRESS_BUTTON;
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
queue_try_add(&card_to_usb_q, &val);
do {
queue_remove_blocking(&usb_to_card_q, &val);
} while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT);
} while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT && val != EV_BUTTON_CANCELLED);
#endif
return val == EV_BUTTON_TIMEOUT;
if (val == EV_BUTTON_TIMEOUT) {
return 1;
}
else if (val == EV_BUTTON_CANCELLED) {
return 2;
}
return 0;
}
uint32_t user_present_time_limit = 0;
bool check_user_presence(void) {
if (user_present_time_limit == 0 || user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) {
if (wait_button_pressed() == true) { //timeout
if (wait_button_pressed() > 0) { //timeout
return false;
}
//user_present_time_limit = board_millis();
@@ -528,11 +529,11 @@ bool check_user_presence(void) {
uint32_t get_sign_counter(void) {
uint8_t *caddr = file_get_data(ef_counter);
return get_uint32_t_le(caddr);
return get_uint32_le(caddr);
}
uint8_t get_opts(void) {
file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF);
file_t *ef = file_search_by_fid(EF_OPTS, NULL, SPECIFY_EF);
if (file_has_data(ef)) {
return *file_get_data(ef);
}
@@ -540,9 +541,9 @@ uint8_t get_opts(void) {
}
void set_opts(uint8_t opts) {
file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF);
file_t *ef = file_search_by_fid(EF_OPTS, NULL, SPECIFY_EF);
file_put_data(ef, &opts, sizeof(uint8_t));
low_flash_available();
flash_commit();
}
#define CTAP_CBOR 0x10

View File

@@ -41,7 +41,7 @@ extern int derive_key(const uint8_t *app_id,
int,
mbedtls_ecp_keypair *key);
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *);
extern bool wait_button_pressed(void);
extern int wait_button_pressed(void);
extern void init_fido(void);
extern void init_otp(void);
extern void scan_all(void);

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "fido.h"
#include "ctap2_cbor.h"

View File

@@ -15,12 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include <stdio.h>
#include "picokeys.h"
#include "serial.h"
#include "fido.h"
#include "apdu.h"
#include "version.h"
#include "files.h"
#include "asn1.h"
#include "tlv.h"
#include "management.h"
bool is_gpg = true;
@@ -45,7 +47,7 @@ static int man_select(app_t *a, uint8_t force) {
#endif
}
is_gpg = false;
return PICOKEY_OK;
return PICOKEYS_OK;
}
INITIALIZER ( man_ctor ) {
@@ -53,22 +55,22 @@ INITIALIZER ( man_ctor ) {
}
static int man_unload(void) {
return PICOKEY_OK;
return PICOKEYS_OK;
}
bool cap_supported(uint16_t cap) {
file_t *ef = search_dynamic_file(EF_DEV_CONF);
file_t *ef = file_search(EF_DEV_CONF);
if (file_has_data(ef)) {
uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0;
asn1_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
tlv_ctx_t ctxi;
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag == TAG_USB_ENABLED) {
uint16_t ecaps = tag_data[0];
if (tag_len == 2) {
ecaps = get_uint16_t_be(tag_data);
ecaps = get_uint16_be(tag_data);
}
return ecaps & cap;
}
@@ -87,7 +89,7 @@ static uint8_t _piv_aid[] = {
};
int man_get_config(void) {
file_t *ef = search_dynamic_file(EF_DEV_CONF);
file_t *ef = file_search(EF_DEV_CONF);
res_APDU_size = 0;
res_APDU[res_APDU_size++] = 0; // Overall length. Filled later
res_APDU[res_APDU_size++] = TAG_USB_SUPPORTED;
@@ -164,7 +166,7 @@ static int cmd_write_config(void) {
}
file_t *ef = file_new(EF_DEV_CONF);
file_put_data(ef, apdu.data + 1, (uint16_t)(apdu.nc - 1));
low_flash_available();
flash_commit();
#ifndef ENABLE_EMULATION
if (cap_supported(CAP_OTP)) {
phy_data.enabled_usb_itf |= PHY_USB_ITF_KB;

View File

@@ -15,13 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "picokeys.h"
#include "serial.h"
#include "fido.h"
#include "apdu.h"
#include "files.h"
#include "random.h"
#include "version.h"
#include "asn1.h"
#include "tlv.h"
#include "crypto_utils.h"
#include "management.h"
@@ -87,8 +88,8 @@ static int oath_select(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = 8;
memcpy(res_APDU + res_APDU_size, pico_serial_str, 8); res_APDU_size += 8;
if (file_has_data(search_dynamic_file(EF_OATH_CODE)) == true) {
random_gen(NULL, challenge, sizeof(challenge));
if (file_has_data(file_search(EF_OATH_CODE)) == true) {
random_fill_buffer(challenge, sizeof(challenge));
res_APDU[res_APDU_size++] = TAG_CHALLENGE;
res_APDU[res_APDU_size++] = sizeof(challenge);
memcpy(res_APDU + res_APDU_size, challenge, sizeof(challenge));
@@ -102,7 +103,7 @@ static int oath_select(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = 8;
memcpy(res_APDU + res_APDU_size, pico_serial_str, 8);
res_APDU_size += 8;
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
file_t *ef_otp_pin = file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (file_has_data(ef_otp_pin)) {
const uint8_t *pin_data = file_get_data(ef_otp_pin);
res_APDU[res_APDU_size++] = TAG_PIN_COUNTER;
@@ -111,9 +112,9 @@ static int oath_select(app_t *a, uint8_t force) {
}
}
apdu.ne = res_APDU_size;
return PICOKEY_OK;
return PICOKEYS_OK;
}
return PICOKEY_ERR_FILE_NOT_FOUND;
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
INITIALIZER ( oath_ctor ) {
@@ -121,15 +122,15 @@ INITIALIZER ( oath_ctor ) {
}
static int oath_unload(void) {
return PICOKEY_OK;
return PICOKEYS_OK;
}
static file_t *find_oath_cred(const uint8_t *name, size_t name_len) {
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
asn1_ctx_t ctxi, ef_tag = { 0 };
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (file_has_data(ef) && asn1_find_tag(&ctxi, TAG_NAME, &ef_tag) == true && ef_tag.len == name_len && memcmp(ef_tag.data, name, name_len) == 0) {
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i));
tlv_ctx_t ctxi, ef_tag = { 0 };
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (file_has_data(ef) && tlv_find_tag(&ctxi, TAG_NAME, &ef_tag) == true && ef_tag.len == name_len && memcmp(ef_tag.data, name, name_len) == 0) {
return ef;
}
}
@@ -140,16 +141,16 @@ static int cmd_put(void) {
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, key = { 0 }, name = { 0 }, imf = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_KEY, &key) == false) {
tlv_ctx_t ctxi, key = { 0 }, name = { 0 }, imf = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_INCORRECT_PARAMS();
}
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (asn1_find_tag(&ctxi, TAG_IMF, &imf) == false) {
if (tlv_find_tag(&ctxi, TAG_IMF, &imf) == false) {
memcpy(apdu.data + apdu.nc, "\x7a\x08\x00\x00\x00\x00\x00\x00\x00\x00", 10);
apdu.nc += 10;
}
@@ -166,15 +167,15 @@ static int cmd_put(void) {
file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef)) {
file_put_data(ef, apdu.data, (uint16_t)apdu.nc);
low_flash_available();
flash_commit();
}
else {
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *tef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
file_t *tef = file_search((uint16_t)(EF_OATH_CRED + i));
if (!file_has_data(tef)) {
tef = file_new((uint16_t)(EF_OATH_CRED + i));
file_put_data(tef, apdu.data, (uint16_t)apdu.nc);
low_flash_available();
flash_commit();
return SW_OK();
}
}
@@ -188,12 +189,12 @@ static int cmd_delete(void) {
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, ctxo = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &ctxo) == true) {
tlv_ctx_t ctxi, ctxo = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &ctxo) == true) {
file_t *ef = find_oath_cred(ctxo.data, ctxo.len);
if (ef) {
delete_file(ef);
file_delete(ef);
return SW_OK();
}
return SW_DATA_INVALID();
@@ -219,24 +220,24 @@ static int cmd_set_code(void) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (apdu.nc == 0) {
delete_file(search_dynamic_file(EF_OATH_CODE));
file_delete(file_search(EF_OATH_CODE));
validated = true;
return SW_OK();
}
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_KEY, &key) == false) {
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS();
}
if (key.len == 0) {
delete_file(search_dynamic_file(EF_OATH_CODE));
file_delete(file_search(EF_OATH_CODE));
validated = true;
return SW_OK();
}
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) {
if (tlv_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) {
return SW_INCORRECT_PARAMS();
}
@@ -252,10 +253,10 @@ static int cmd_set_code(void) {
if (memcmp(hmac, resp.data, resp.len) != 0) {
return SW_DATA_INVALID();
}
random_gen(NULL, challenge, sizeof(challenge));
random_fill_buffer(challenge, sizeof(challenge));
file_t *ef = file_new(EF_OATH_CODE);
file_put_data(ef, key.data, key.len);
low_flash_available();
flash_commit();
validated = false;
return SW_OK();
}
@@ -265,14 +266,14 @@ static int cmd_reset(void) {
return SW_INCORRECT_P1P2();
}
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i));
if (file_has_data(ef)) {
delete_file(ef);
file_delete(ef);
}
}
delete_file(search_dynamic_file(EF_OATH_CODE));
flash_clear_file(search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF));
low_flash_available();
file_delete(file_search(EF_OATH_CODE));
flash_clear_file(file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF));
flash_commit();
validated = true;
return SW_OK();
}
@@ -283,21 +284,21 @@ static int cmd_list(void) {
}
bool ext = (apdu.nc == 1 && apdu.data[0] == 0x01);
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i));
if (file_has_data(ef)) {
asn1_ctx_t ctxi, key = { 0 }, name = { 0 }, pws = { 0 };
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == true && asn1_find_tag(&ctxi, TAG_KEY, &key) == true) {
tlv_ctx_t ctxi, key = { 0 }, name = { 0 }, pws = { 0 };
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == true && tlv_find_tag(&ctxi, TAG_KEY, &key) == true) {
res_APDU[res_APDU_size++] = TAG_NAME_LIST;
res_APDU[res_APDU_size++] = (uint8_t)(name.len + 1 + (ext ? 1 : 0));
res_APDU[res_APDU_size++] = key.data[0];
memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len;
if (ext) {
uint8_t props = 0x0;
if (asn1_find_tag(&ctxi, TAG_PWS_LOGIN, &pws) == true || asn1_find_tag(&ctxi, TAG_PWS_PASSWORD, &pws) == true || asn1_find_tag(&ctxi, TAG_PWS_METADATA, &pws) == true) {
if (tlv_find_tag(&ctxi, TAG_PWS_LOGIN, &pws) == true || tlv_find_tag(&ctxi, TAG_PWS_PASSWORD, &pws) == true || tlv_find_tag(&ctxi, TAG_PWS_METADATA, &pws) == true) {
props |= 0x4;
}
if (asn1_find_tag(&ctxi, TAG_PROPERTY, &pws) == true && (pws.data[0] & PROP_TOUCH)) {
if (tlv_find_tag(&ctxi, TAG_PROPERTY, &pws) == true && (pws.data[0] & PROP_TOUCH)) {
props |= 0x1;
}
res_APDU[res_APDU_size++] = props;
@@ -310,15 +311,15 @@ static int cmd_list(void) {
}
static int cmd_validate(void) {
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) {
if (tlv_find_tag(&ctxi, TAG_RESPONSE, &resp) == false) {
return SW_INCORRECT_PARAMS();
}
file_t *ef = search_dynamic_file(EF_OATH_CODE);
file_t *ef = file_search(EF_OATH_CODE);
if (file_has_data(ef) == false) {
validated = true;
return SW_DATA_INVALID();
@@ -359,7 +360,7 @@ int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const u
int r = mbedtls_md_hmac(md_info, key + 2, key_len - 2, chal, chal_len, hmac);
size_t hmac_size = mbedtls_md_get_size(md_info);
if (r != 0) {
return PICOKEY_EXEC_ERROR;
return PICOKEYS_EXEC_ERROR;
}
if (truncate == 0x01) {
res_APDU[res_APDU_size++] = 4 + 1;
@@ -376,7 +377,7 @@ int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const u
memcpy(res_APDU + res_APDU_size, hmac, hmac_size); res_APDU_size += (uint16_t)hmac_size;
}
apdu.ne = res_APDU_size;
return PICOKEY_OK;
return PICOKEYS_OK;
}
static int cmd_calculate(void) {
@@ -386,26 +387,26 @@ static int cmd_calculate(void) {
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_INCORRECT_PARAMS();
}
file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) {
return SW_DATA_INVALID();
}
asn1_ctx_t ctxe;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (asn1_find_tag(&ctxe, TAG_KEY, &key) == false) {
tlv_ctx_t ctxe;
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (tlv_find_tag(&ctxe, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS();
}
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (asn1_find_tag(&ctxe, TAG_IMF, &chal) == false) {
if (tlv_find_tag(&ctxe, TAG_IMF, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
}
@@ -413,21 +414,21 @@ static int cmd_calculate(void) {
res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu);
int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
return SW_EXEC_ERROR();
}
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
uint64_t v = get_uint64_t_be(chal.data);
uint64_t v = get_uint64_be(chal.data);
size_t ef_size = file_get_size(ef);
v++;
uint8_t *tmp = (uint8_t *) calloc(1, ef_size);
memcpy(tmp, file_get_data(ef), ef_size);
asn1_ctx_t ctxt;
asn1_ctx_init(tmp, (uint16_t)ef_size, &ctxt);
asn1_find_tag(&ctxt, TAG_IMF, &chal);
put_uint64_t_be(v, chal.data);
tlv_ctx_t ctxt;
tlv_ctx_init(tmp, (uint16_t)ef_size, &ctxt);
tlv_find_tag(&ctxt, TAG_IMF, &chal);
put_uint64_be(v, chal.data);
file_put_data(ef, tmp, (uint16_t)ef_size);
low_flash_available();
flash_commit();
free(tmp);
}
apdu.ne = res_APDU_size;
@@ -435,26 +436,26 @@ static int cmd_calculate(void) {
}
static int cmd_calculate_all(void) {
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, prop = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, prop = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (P2(apdu) != 0x0 && P2(apdu) != 0x1) {
return SW_INCORRECT_P1P2();
}
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
res_APDU_size = 0;
for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file((uint16_t)(EF_OATH_CRED + i));
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i));
if (file_has_data(ef)) {
const uint8_t *ef_data = file_get_data(ef);
size_t ef_len = file_get_size(ef);
asn1_ctx_t ctxe;
asn1_ctx_init((uint8_t *)ef_data, (uint16_t)ef_len, &ctxe);
if (asn1_find_tag(&ctxe, TAG_NAME, &name) == false || asn1_find_tag(&ctxe, TAG_KEY, &key) == false) {
tlv_ctx_t ctxe;
tlv_ctx_init((uint8_t *)ef_data, (uint16_t)ef_len, &ctxe);
if (tlv_find_tag(&ctxe, TAG_NAME, &name) == false || tlv_find_tag(&ctxe, TAG_KEY, &key) == false) {
continue;
}
res_APDU[res_APDU_size++] = TAG_NAME;
@@ -465,7 +466,7 @@ static int cmd_calculate_all(void) {
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1];
}
else if (asn1_find_tag(&ctxe, TAG_PROPERTY, &prop) == true && (prop.data[0] & PROP_TOUCH)) {
else if (tlv_find_tag(&ctxe, TAG_PROPERTY, &prop) == true && (prop.data[0] & PROP_TOUCH)) {
res_APDU[res_APDU_size++] = TAG_TOUCH_RESPONSE;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1];
@@ -473,7 +474,7 @@ static int cmd_calculate_all(void) {
else {
res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu);
int ret = calculate_oath(P2(apdu), key.data, key.len, chal.data, chal.len);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1];
}
@@ -490,56 +491,56 @@ static int cmd_send_remaining(void) {
static int cmd_set_otp_pin(void) {
uint8_t hsh[33] = { 0 };
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
file_t *ef_otp_pin = file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, pw = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
tlv_ctx_t ctxi, pw = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
return SW_INCORRECT_PARAMS();
}
hsh[0] = MAX_OTP_COUNTER;
double_hash_pin(pw.data, pw.len, hsh + 1);
file_put_data(ef_otp_pin, hsh, sizeof(hsh));
low_flash_available();
flash_commit();
return SW_OK();
}
static int cmd_change_otp_pin(void) {
uint8_t hsh[33] = { 0 };
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
file_t *ef_otp_pin = file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (!file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, pw = { 0 }, new_pw = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
tlv_ctx_t ctxi, pw = { 0 }, new_pw = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
return SW_INCORRECT_PARAMS();
}
double_hash_pin(pw.data, pw.len, hsh + 1);
if (memcmp(file_get_data(ef_otp_pin) + 1, hsh + 1, 32) != 0) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (asn1_find_tag(&ctxi, TAG_NEW_PASSWORD, &new_pw) == false) {
if (tlv_find_tag(&ctxi, TAG_NEW_PASSWORD, &new_pw) == false) {
return SW_INCORRECT_PARAMS();
}
hsh[0] = MAX_OTP_COUNTER;
double_hash_pin(new_pw.data, new_pw.len, hsh + 1);
file_put_data(ef_otp_pin, hsh, sizeof(hsh));
low_flash_available();
flash_commit();
return SW_OK();
}
static int cmd_verify_otp_pin(void) {
uint8_t hsh[33] = { 0 }, data_hsh[33];
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
file_t *ef_otp_pin = file_search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
if (!file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED();
}
asn1_ctx_t ctxi, pw = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
tlv_ctx_t ctxi, pw = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
return SW_INCORRECT_PARAMS();
}
double_hash_pin(pw.data, pw.len, hsh + 1);
@@ -549,49 +550,49 @@ static int cmd_verify_otp_pin(void) {
data_hsh[0] -= 1;
}
file_put_data(ef_otp_pin, data_hsh, sizeof(data_hsh));
low_flash_available();
flash_commit();
validated = false;
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
data_hsh[0] = MAX_OTP_COUNTER;
file_put_data(ef_otp_pin, data_hsh, sizeof(data_hsh));
low_flash_available();
flash_commit();
validated = true;
return SW_OK();
}
static int cmd_verify_hotp(void) {
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, code = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, code = { 0 };
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
uint32_t code_int = 0;
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_INCORRECT_PARAMS();
}
file_t *ef = find_oath_cred(name.data, name.len);
file_t *ef = file_search_by_fid(EF_OATH_CRED, NULL, SPECIFY_EF);
if (file_has_data(ef) == false) {
return SW_DATA_INVALID();
}
asn1_ctx_t ctxe;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (asn1_find_tag(&ctxe, TAG_KEY, &key) == false) {
tlv_ctx_t ctxe;
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (tlv_find_tag(&ctxe, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS();
}
if ((key.data[0] & OATH_TYPE_MASK) != OATH_TYPE_HOTP) {
return SW_DATA_INVALID();
}
if (asn1_find_tag(&ctxe, TAG_IMF, &chal) == false) {
if (tlv_find_tag(&ctxe, TAG_IMF, &chal) == false) {
return SW_INCORRECT_PARAMS();
}
if (asn1_find_tag(&ctxi, TAG_RESPONSE, &code) == true) {
code_int = get_uint32_t_be(code.data);
if (tlv_find_tag(&ctxi, TAG_RESPONSE, &code) == true) {
code_int = get_uint32_be(code.data);
}
int ret = calculate_oath(0x01, key.data, key.len, chal.data, chal.len);
if (ret != PICOKEY_OK) {
if (ret != PICOKEYS_OK) {
return SW_EXEC_ERROR();
}
uint32_t res_int = get_uint32_t_be(res_APDU + 2);
uint32_t res_int = get_uint32_be(res_APDU + 2);
if (res_APDU[1] == 6) {
res_int %= (uint32_t) 1e6;
}
@@ -607,7 +608,7 @@ static int cmd_verify_hotp(void) {
}
static int cmd_rename(void) {
asn1_ctx_t ctxi, name = { 0 }, new_name = { 0 };
tlv_ctx_t ctxi, name = { 0 }, new_name = { 0 };
if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
@@ -615,13 +616,13 @@ static int cmd_rename(void) {
if (apdu.data[0] != TAG_NAME) {
return SW_WRONG_DATA();
}
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA();
}
asn1_ctx_init(name.data + name.len, (uint16_t)(apdu.nc - (name.data + name.len - apdu.data)), &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &new_name) == false) {
tlv_ctx_init(name.data + name.len, (uint16_t)(apdu.nc - (name.data + name.len - apdu.data)), &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &new_name) == false) {
return SW_WRONG_DATA();
}
if (name.len == new_name.len && memcmp(name.data, new_name.data, name.len) == 0) {
@@ -633,8 +634,8 @@ static int cmd_rename(void) {
}
uint8_t *fdata = file_get_data(ef);
uint16_t fsize = file_get_size(ef);
asn1_ctx_init(fdata, fsize, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
tlv_ctx_init(fdata, fsize, &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA();
}
uint8_t *new_data = (uint8_t *) calloc(fsize + new_name.len - name.len, sizeof(uint8_t));
@@ -643,50 +644,50 @@ static int cmd_rename(void) {
memcpy(new_data + (name.data - fdata), new_name.data, new_name.len);
memcpy(new_data + (name.data - fdata) + new_name.len, name.data + name.len, fsize - (name.data + name.len - fdata));
file_put_data(ef, new_data, fsize + new_name.len - name.len);
low_flash_available();
flash_commit();
free(new_data);
return SW_OK();
}
static int cmd_get_credential(void) {
asn1_ctx_t ctxi, name = { 0 };
tlv_ctx_t ctxi, name = { 0 };
if (apdu.nc < 3) {
return SW_INCORRECT_PARAMS();
}
if (apdu.data[0] != TAG_NAME) {
return SW_WRONG_DATA();
}
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) {
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA();
}
file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) {
return SW_DATA_INVALID();
}
asn1_ctx_t login = { 0 }, pw = { 0 }, meta = { 0 }, prop = { 0 };
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == true) {
tlv_ctx_t login = { 0 }, pw = { 0 }, meta = { 0 }, prop = { 0 };
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (tlv_find_tag(&ctxi, TAG_NAME, &name) == true) {
res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = (uint8_t)(name.len);
memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len;
}
if (asn1_find_tag(&ctxi, TAG_PWS_LOGIN, &login) == true) {
if (tlv_find_tag(&ctxi, TAG_PWS_LOGIN, &login) == true) {
res_APDU[res_APDU_size++] = TAG_PWS_LOGIN;
res_APDU[res_APDU_size++] = (uint8_t)(login.len);
memcpy(res_APDU + res_APDU_size, login.data, login.len); res_APDU_size += login.len;
}
if (asn1_find_tag(&ctxi, TAG_PWS_PASSWORD, &pw) == true) {
if (tlv_find_tag(&ctxi, TAG_PWS_PASSWORD, &pw) == true) {
res_APDU[res_APDU_size++] = TAG_PWS_PASSWORD;
res_APDU[res_APDU_size++] = (uint8_t)(pw.len);
memcpy(res_APDU + res_APDU_size, pw.data, pw.len); res_APDU_size += pw.len;
}
if (asn1_find_tag(&ctxi, TAG_PWS_METADATA, &meta) == true) {
if (tlv_find_tag(&ctxi, TAG_PWS_METADATA, &meta) == true) {
res_APDU[res_APDU_size++] = TAG_PWS_METADATA;
res_APDU[res_APDU_size++] = (uint8_t)(meta.len);
memcpy(res_APDU + res_APDU_size, meta.data, meta.len); res_APDU_size += meta.len;
}
if (asn1_find_tag(&ctxi, TAG_PROPERTY, &prop) == true) {
if (tlv_find_tag(&ctxi, TAG_PROPERTY, &prop) == true) {
res_APDU[res_APDU_size++] = TAG_PROPERTY;
res_APDU[res_APDU_size++] = (uint8_t)(prop.len);
memcpy(res_APDU + res_APDU_size, prop.data, prop.len); res_APDU_size += prop.len;

View File

@@ -15,13 +15,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include <stdio.h>
#include "picokeys.h"
#include "serial.h"
#include "button.h"
#include "fido.h"
#include "apdu.h"
#include "files.h"
#include "random.h"
#include "version.h"
#include "asn1.h"
#include "hid/ctap_hid.h"
#include "usb.h"
#if defined(PICO_PLATFORM)
@@ -145,17 +147,16 @@ static int otp_select(app_t *a, uint8_t force) {
if (cap_supported(CAP_OTP)) {
a->process_apdu = otp_process_apdu;
a->unload = otp_unload;
if (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ||
file_has_data(search_dynamic_file(EF_OTP_SLOT2))) {
if (file_has_data(file_search(EF_OTP_SLOT1)) || file_has_data(file_search(EF_OTP_SLOT2))) {
config_seq = 1;
}
else {
config_seq = 0;
}
otp_status(false);
return PICOKEY_OK;
return PICOKEYS_OK;
}
return PICOKEY_ERR_FILE_NOT_FOUND;
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
uint8_t modhex_tab[] =
@@ -172,22 +173,22 @@ void init_otp(void) {
if (scanned == false) {
scan_all();
for (uint8_t i = 0; i < 4; i++) {
file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i);
file_t *ef = file_search(EF_OTP_SLOT1 + i);
uint8_t *data = file_get_data(ef);
otp_config_t *otp_config = (otp_config_t *) data;
if (file_has_data(ef) && !(otp_config->tkt_flags & OATH_HOTP) &&
!(otp_config->cfg_flags & SHORT_TICKET || otp_config->cfg_flags & STATIC_TICKET)) {
uint16_t counter = get_uint16_t_be(data + otp_config_size);
uint16_t counter = get_uint16_be(data + otp_config_size);
if (++counter <= 0x7fff) {
uint8_t new_data[otp_config_size + 8];
memcpy(new_data, data, sizeof(new_data));
put_uint16_t_be(counter, new_data + otp_config_size);
put_uint16_be(counter, new_data + otp_config_size);
file_put_data(ef, new_data, sizeof(new_data));
}
}
}
scanned = true;
low_flash_available();
flash_commit();
}
}
static uint16_t calculate_crc(const uint8_t *data, size_t data_len) {
@@ -212,7 +213,7 @@ static int otp_button_pressed(uint8_t slot) {
return 3;
}
uint16_t slot_ef = EF_OTP_SLOT1 + slot - 1;
file_t *ef = search_dynamic_file(slot_ef);
file_t *ef = file_search(slot_ef);
const uint8_t *data = file_get_data(ef);
otp_config_t *otp_config = (otp_config_t *) data;
if (file_has_data(ef) == false) {
@@ -228,18 +229,18 @@ static int otp_button_pressed(uint8_t slot) {
memcpy(tmp_key + 2, otp_config->aes_key, KEY_SIZE);
uint64_t imf = 0;
const uint8_t *p = data + otp_config_size;
imf = get_uint64_t_be(p);
imf = get_uint64_be(p);
p += 8;
if (imf == 0) {
imf = get_uint16_t_be(otp_config->uid + 4);
imf = get_uint16_be(otp_config->uid + 4);
}
uint8_t chal[8];
put_uint64_t_be(imf, chal);
put_uint64_be(imf, chal);
res_APDU_size = 0;
int ret = calculate_oath(1, tmp_key, sizeof(tmp_key), chal, sizeof(chal));
if (ret == PICOKEY_OK) {
if (ret == PICOKEYS_OK) {
uint32_t base = otp_config->cfg_flags & OATH_HOTP8 ? 1e8 : 1e6;
uint32_t number = get_uint16_t_be(res_APDU + 2);
uint32_t number = get_uint16_be(res_APDU + 2);
number %= base;
char number_str[9];
if (otp_config->cfg_flags & OATH_HOTP8) {
@@ -252,12 +253,12 @@ static int otp_button_pressed(uint8_t slot) {
}
imf++;
uint8_t new_chal[8];
put_uint64_t_be(imf, new_chal);
put_uint64_be(imf, new_chal);
uint8_t new_otp_config[otp_config_size + sizeof(new_chal)];
memcpy(new_otp_config, otp_config, otp_config_size);
memcpy(new_otp_config + otp_config_size, new_chal, sizeof(new_chal));
file_put_data(ef, new_otp_config, sizeof(new_otp_config));
low_flash_available();
flash_commit();
}
if (otp_config->tkt_flags & APPEND_CR) {
append_keyboard_buffer((const uint8_t *) "\r", 1);
@@ -277,7 +278,7 @@ static int otp_button_pressed(uint8_t slot) {
else {
uint8_t otpk[22], *po = otpk;
bool update_counter = false;
uint16_t counter = get_uint16_t_be(data + otp_config_size), crc = 0;
uint16_t counter = get_uint16_be(data + otp_config_size), crc = 0;
uint32_t ts = board_millis() / 1000;
if (counter == 0) {
update_counter = true;
@@ -287,16 +288,16 @@ static int otp_button_pressed(uint8_t slot) {
po += 6;
memcpy(po, otp_config->uid, UID_SIZE);
po += UID_SIZE;
po += put_uint16_t_le(counter, po);
po += put_uint16_le(counter, po);
ts >>= 1;
*po++ = ts & 0xff;
*po++ = ts >> 8;
*po++ = ts >> 16;
*po++ = session_counter[slot - 1];
random_gen(NULL, po, 2);
random_fill_buffer(po, 2);
po += 2;
crc = calculate_crc(otpk + 6, 14);
po += put_uint16_t_le(~crc, po);
po += put_uint16_le(~crc, po);
mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, otp_config->aes_key, 128);
@@ -317,9 +318,9 @@ static int otp_button_pressed(uint8_t slot) {
if (update_counter == true) {
uint8_t new_data[otp_config_size + 8];
memcpy(new_data, data, sizeof(new_data));
put_uint16_t_be(counter, new_data + otp_config_size);
put_uint16_be(counter, new_data + otp_config_size);
file_put_data(ef, new_data, sizeof(new_data));
low_flash_available();
flash_commit();
}
}
@@ -334,13 +335,13 @@ INITIALIZER( otp_ctor ) {
}
static int otp_unload(void) {
return PICOKEY_OK;
return PICOKEYS_OK;
}
uint8_t status_byte = 0x0;
static uint16_t otp_status_ext(void) {
for (int i = 0; i < 4; i++) {
file_t *ef = search_dynamic_file(EF_OTP_SLOT1 + i);
file_t *ef = file_search(EF_OTP_SLOT1 + i);
if (file_has_data(ef)) {
res_APDU[res_APDU_size++] = 0xB0 + i;
res_APDU[res_APDU_size++] = 0; // Filled later
@@ -385,7 +386,7 @@ static uint16_t otp_status(bool is_otp) {
res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = config_seq;
uint8_t opts = 0;
file_t *ef = search_dynamic_file(EF_OTP_SLOT1);
file_t *ef = file_search(EF_OTP_SLOT1);
if (file_has_data(ef)) {
opts |= CONFIG1_VALID;
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
@@ -393,7 +394,7 @@ static uint16_t otp_status(bool is_otp) {
opts |= CONFIG1_TOUCH;
}
}
ef = search_dynamic_file(EF_OTP_SLOT2);
ef = file_search(EF_OTP_SLOT2);
if (file_has_data(ef)) {
opts |= CONFIG2_VALID;
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
@@ -442,13 +443,13 @@ static int cmd_otp(void) {
}
memset(apdu.data + otp_config_size, 0, 8); // Add 8 bytes extra
file_put_data(ef, apdu.data, otp_config_size + 8);
low_flash_available();
flash_commit();
config_seq++;
return otp_status(_is_otp);
}
}
// Delete slot
delete_file(ef);
file_delete(ef);
config_seq++;
return otp_status(_is_otp);
}
@@ -461,7 +462,7 @@ static int cmd_otp(void) {
if (odata->rfu[0] != 0 || odata->rfu[1] != 0 || check_crc(odata) == false) {
return SW_WRONG_DATA();
}
file_t *ef = search_dynamic_file(slot);
file_t *ef = file_search(slot);
if (file_has_data(ef)) {
otp_config_t *otpc = (otp_config_t *) file_get_data(ef);
if (memcmp(otpc->acc_code, apdu.data + otp_config_size, ACC_CODE_SIZE) != 0) {
@@ -481,7 +482,7 @@ static int cmd_otp(void) {
odata->cfg_flags = otpc->cfg_flags;
}
file_put_data(ef, apdu.data, otp_config_size);
low_flash_available();
flash_commit();
config_seq++;
}
return otp_status(_is_otp);
@@ -507,7 +508,7 @@ static int cmd_otp(void) {
file_put_data(ef1, file_get_data(ef2), file_get_size(ef2));
}
else {
delete_file(ef1);
file_delete(ef1);
// When a dynamic file is deleted, existing referenes are invalidated
ef2 = file_new(slot2);
}
@@ -515,9 +516,9 @@ static int cmd_otp(void) {
file_put_data(ef2, tmp, sizeof(tmp));
}
else {
delete_file(ef2);
file_delete(ef2);
}
low_flash_available();
flash_commit();
config_seq++;
return otp_status(_is_otp);
}
@@ -537,7 +538,7 @@ static int cmd_otp(void) {
return SW_INCORRECT_P1P2();
}
uint16_t slot = (p1 == 0x30 || p1 == 0x20 ? EF_OTP_SLOT1 : EF_OTP_SLOT2) + p2;
file_t *ef = search_dynamic_file(slot);
file_t *ef = file_search(slot);
if (file_has_data(ef)) {
otp_config_t *otp_config = (otp_config_t *) file_get_data(ef);
if (!(otp_config->tkt_flags & CHAL_RESP)) {
@@ -549,7 +550,7 @@ static int cmd_otp(void) {
status_byte = 0x20;
otp_status(_is_otp);
#ifndef ENABLE_EMULATION
if (wait_button() == true) {
if (button_wait()) {
status_byte = 0x00;
otp_status(_is_otp);
return SW_CONDITIONS_NOT_SATISFIED();
@@ -629,7 +630,7 @@ uint8_t otp_header[4] = {0};
static int otp_send_frame(uint8_t *frame, size_t frame_len) {
uint16_t crc = calculate_crc(frame, frame_len);
frame_len += put_uint16_t_le(~crc, frame + frame_len);
frame_len += put_uint16_le(~crc, frame + frame_len);
*get_send_buffer_size(ITF_KEYBOARD) = frame_len;
otp_exp_seq = (frame_len / 7);
if (frame_len % 7) {
@@ -660,7 +661,7 @@ static int otp_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type
if (rseq == 9) {
DEBUG_DATA(otp_frame_rx, sizeof(otp_frame_rx));
DEBUG_PAYLOAD(otp_frame_rx, sizeof(otp_frame_rx));
uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = get_uint16_t_le(otp_frame_rx + 65);
uint16_t residual_crc = calculate_crc(otp_frame_rx, 64), rcrc = get_uint16_le(otp_frame_rx + 65);
uint8_t slot_id = otp_frame_rx[64];
if (residual_crc == rcrc) {
uint8_t hdr[5];

View File

@@ -22,6 +22,9 @@ RUN apt install -y libccid \
cmake \
libfuse-dev \
python3-pyscard \
libtss2-dev \
tpm2-tools \
swtpm \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install pytest pycvc cryptography inputimeout fido2==2.0.0 --break-system-packages
WORKDIR /

View File

@@ -49,6 +49,7 @@ cd build
esptool.py --chip ESP32-S2 merge_bin -o ../release/pico_fido_esp32-s2.bin @flash_args
cd ..
else
sudo apt install -y libtss2-dev tpm2-tools swtpm cmake
mkdir build
cd build
cmake -DENABLE_EMULATION=1 ..