8 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
16 changed files with 133 additions and 105 deletions

View File

@@ -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 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; static const uint8_t *volatile cbor_data = NULL;
size_t cbor_len = 0; static volatile size_t cbor_len = 0;
uint8_t cbor_cmd = 0; static volatile uint8_t cbor_cmd = 0;
int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) { int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len) {
if (len == 0 && cmd == CTAPHID_CBOR) { if (len == 0 && cmd == CTAPHID_CBOR) {
@@ -108,7 +108,10 @@ void *cbor_thread(void *arg) {
if (m == EV_EXIT) { if (m == EV_EXIT) {
break; 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) { if (apdu.sw == 0) {
DEBUG_DATA(res_APDU, res_APDU_size); DEBUG_DATA(res_APDU, res_APDU_size);
} }

View File

@@ -20,6 +20,7 @@
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
#include "mbedtls/hkdf.h" #include "mbedtls/hkdf.h"
#include "mbedtls/constant_time.h"
#include "cbor.h" #include "cbor.h"
#include "ctap.h" #include "ctap.h"
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
@@ -221,10 +222,10 @@ int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, uint16_t l
return ret; return ret;
} }
if (protocol == 1) { if (protocol == 1) {
return ct_memcmp(sign, hmac, 16); return mbedtls_ct_memcmp(sign, hmac, 16);
} }
else if (protocol == 2) { else if (protocol == 2) {
return ct_memcmp(sign, hmac, 32); return mbedtls_ct_memcmp(sign, hmac, 32);
} }
return -1; return -1;
} }
@@ -491,7 +492,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_derive_verifier(paddedNewPin, 16, dhash); 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(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (retries == 0) { if (retries == 0) {
@@ -569,7 +570,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
pin_data[2] = 1; // New format indicator pin_data[2] = 1; // New format indicator
pin_derive_verifier(dhash, 16, pin_data + 3); 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); CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
} }
file_put_data(ef_pin, pin_data, sizeof(pin_data)); file_put_data(ef_pin, pin_data, sizeof(pin_data));
@@ -652,7 +653,7 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
else { else {
pin_derive_verifier(paddedNewPin, 16, dhash); 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(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
mbedtls_platform_zeroize(dhash, sizeof(dhash)); mbedtls_platform_zeroize(dhash, sizeof(dhash));

View File

@@ -32,6 +32,7 @@
#include "random.h" #include "random.h"
int cbor_get_assertion(const uint8_t *data, size_t len, bool next); int cbor_get_assertion(const uint8_t *data, size_t len, bool next);
extern char *rp_id, *user_name, *display_name;
bool residentx = false; bool residentx = false;
Credential credsx[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 }; 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) { if (rpId.present == false || clientDataHash.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
} }
rp_id = rpId.data;
user_name = NULL;
display_name = NULL;
uint8_t flags = 0; uint8_t flags = 0;
uint8_t rp_id_hash[32] = {0}; uint8_t rp_id_hash[32] = {0};

View File

@@ -28,6 +28,8 @@
#include "random.h" #include "random.h"
#include "crypto_utils.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) { int cbor_make_credential(const uint8_t *data, size_t len) {
CborParser parser; CborParser parser;
CborValue map; CborValue map;
@@ -192,6 +194,9 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
} }
CBOR_PARSE_MAP_END(map, 1); 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 flags = FIDO2_AUT_FLAG_AT;
uint8_t rp_id_hash[32] = {0}; uint8_t rp_id_hash[32] = {0};

View File

@@ -35,7 +35,7 @@ int cbor_reset(void) {
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
} }
#endif #endif
if (wait_button_pressed() == true) { if (wait_button_pressed() > 0) {
return CTAP2_ERR_USER_ACTION_TIMEOUT; return CTAP2_ERR_USER_ACTION_TIMEOUT;
} }
#endif #endif

View File

@@ -20,9 +20,16 @@
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
#include "ctap.h" #include "ctap.h"
extern char *rp_id, *user_name, *display_name;
int cbor_selection(void) { 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; return CTAP2_ERR_USER_ACTION_TIMEOUT;
} }
else if (ret == 2) {
return CTAP2_ERR_OPERATION_DENIED;
}
return CTAP2_OK; return CTAP2_OK;
} }

View File

@@ -34,7 +34,7 @@ int cmd_authenticate(void) {
if (req->keyHandleLen < KEY_HANDLE_LEN) { if (req->keyHandleLen < KEY_HANDLE_LEN) {
return SW_INCORRECT_PARAMS(); 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(); return SW_CONDITIONS_NOT_SATISFIED();
} }

View File

@@ -63,7 +63,7 @@ int cmd_register(void) {
if (apdu.nc != CTAP_APPID_SIZE + CTAP_CHAL_SIZE) { if (apdu.nc != CTAP_APPID_SIZE + CTAP_CHAL_SIZE) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
if (wait_button_pressed() == true) { if (wait_button_pressed() > 0) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
if (memcmp(req->appId, bogus_firefox, if (memcmp(req->appId, bogus_firefox,

View File

@@ -498,22 +498,28 @@ void init_fido(void) {
needs_power_cycle = false; needs_power_cycle = false;
} }
bool wait_button_pressed(void) { int wait_button_pressed(void) {
uint32_t val = EV_PRESS_BUTTON; uint32_t val = EV_PRESS_BUTTON;
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM) #if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
queue_try_add(&card_to_usb_q, &val); queue_try_add(&card_to_usb_q, &val);
do { do {
queue_remove_blocking(&usb_to_card_q, &val); 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 #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; uint32_t user_present_time_limit = 0;
bool check_user_presence(void) { bool check_user_presence(void) {
if (user_present_time_limit == 0 || user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) { 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; return false;
} }
//user_present_time_limit = board_millis(); //user_present_time_limit = board_millis();

View File

@@ -41,7 +41,7 @@ extern int derive_key(const uint8_t *app_id,
int, int,
mbedtls_ecp_keypair *key); mbedtls_ecp_keypair *key);
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecp_keypair *); 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_fido(void);
extern void init_otp(void); extern void init_otp(void);
extern void scan_all(void); extern void scan_all(void);

View File

@@ -22,7 +22,7 @@
#include "apdu.h" #include "apdu.h"
#include "version.h" #include "version.h"
#include "files.h" #include "files.h"
#include "asn1.h" #include "tlv.h"
#include "management.h" #include "management.h"
bool is_gpg = true; bool is_gpg = true;
@@ -64,9 +64,9 @@ bool cap_supported(uint16_t cap) {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; uint16_t tag_len = 0;
asn1_ctx_t ctxi; tlv_ctx_t ctxi;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) { while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag == TAG_USB_ENABLED) { if (tag == TAG_USB_ENABLED) {
uint16_t ecaps = tag_data[0]; uint16_t ecaps = tag_data[0];
if (tag_len == 2) { if (tag_len == 2) {

View File

@@ -22,7 +22,7 @@
#include "files.h" #include "files.h"
#include "random.h" #include "random.h"
#include "version.h" #include "version.h"
#include "asn1.h" #include "tlv.h"
#include "crypto_utils.h" #include "crypto_utils.h"
#include "management.h" #include "management.h"
@@ -128,9 +128,9 @@ static int oath_unload(void) {
static file_t *find_oath_cred(const uint8_t *name, size_t name_len) { static file_t *find_oath_cred(const uint8_t *name, size_t name_len) {
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i)); file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i));
asn1_ctx_t ctxi, ef_tag = { 0 }; tlv_ctx_t ctxi, ef_tag = { 0 };
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); tlv_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) { 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; return ef;
} }
} }
@@ -141,16 +141,16 @@ static int cmd_put(void) {
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
asn1_ctx_t ctxi, key = { 0 }, name = { 0 }, imf = { 0 }; tlv_ctx_t ctxi, key = { 0 }, name = { 0 }, imf = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_KEY, &key) == false) { if (tlv_find_tag(&ctxi, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS(); 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(); return SW_INCORRECT_PARAMS();
} }
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { 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); memcpy(apdu.data + apdu.nc, "\x7a\x08\x00\x00\x00\x00\x00\x00\x00\x00", 10);
apdu.nc += 10; apdu.nc += 10;
} }
@@ -189,9 +189,9 @@ static int cmd_delete(void) {
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
asn1_ctx_t ctxi, ctxo = { 0 }; tlv_ctx_t ctxi, ctxo = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &ctxo) == true) { if (tlv_find_tag(&ctxi, TAG_NAME, &ctxo) == true) {
file_t *ef = find_oath_cred(ctxo.data, ctxo.len); file_t *ef = find_oath_cred(ctxo.data, ctxo.len);
if (ef) { if (ef) {
file_delete(ef); file_delete(ef);
@@ -224,9 +224,9 @@ static int cmd_set_code(void) {
validated = true; validated = true;
return SW_OK(); return SW_OK();
} }
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 }; tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_KEY, &key) == false) { if (tlv_find_tag(&ctxi, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (key.len == 0) { if (key.len == 0) {
@@ -234,10 +234,10 @@ static int cmd_set_code(void) {
validated = true; validated = true;
return SW_OK(); 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(); 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(); return SW_INCORRECT_PARAMS();
} }
@@ -286,19 +286,19 @@ static int cmd_list(void) {
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i)); file_t *ef = file_search((uint16_t)(EF_OATH_CRED + i));
if (file_has_data(ef)) { if (file_has_data(ef)) {
asn1_ctx_t ctxi, key = { 0 }, name = { 0 }, pws = { 0 }; tlv_ctx_t ctxi, key = { 0 }, name = { 0 }, pws = { 0 };
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); tlv_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) { 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++] = TAG_NAME_LIST;
res_APDU[res_APDU_size++] = (uint8_t)(name.len + 1 + (ext ? 1 : 0)); res_APDU[res_APDU_size++] = (uint8_t)(name.len + 1 + (ext ? 1 : 0));
res_APDU[res_APDU_size++] = key.data[0]; res_APDU[res_APDU_size++] = key.data[0];
memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len; memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += name.len;
if (ext) { if (ext) {
uint8_t props = 0x0; 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; 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; props |= 0x1;
} }
res_APDU[res_APDU_size++] = props; res_APDU[res_APDU_size++] = props;
@@ -311,12 +311,12 @@ static int cmd_list(void) {
} }
static int cmd_validate(void) { static int cmd_validate(void) {
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 }; tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, resp = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) { if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS(); 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(); return SW_INCORRECT_PARAMS();
} }
file_t *ef = file_search(EF_OATH_CODE); file_t *ef = file_search(EF_OATH_CODE);
@@ -387,26 +387,26 @@ static int cmd_calculate(void) {
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }; tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) { if (tlv_find_tag(&ctxi, TAG_CHALLENGE, &chal) == false) {
return SW_INCORRECT_PARAMS(); 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(); return SW_INCORRECT_PARAMS();
} }
file_t *ef = find_oath_cred(name.data, name.len); file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
asn1_ctx_t ctxe; tlv_ctx_t ctxe;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe); tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (asn1_find_tag(&ctxe, TAG_KEY, &key) == false) { if (tlv_find_tag(&ctxe, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if ((key.data[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { 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(); return SW_INCORRECT_PARAMS();
} }
} }
@@ -423,9 +423,9 @@ static int cmd_calculate(void) {
v++; v++;
uint8_t *tmp = (uint8_t *) calloc(1, ef_size); uint8_t *tmp = (uint8_t *) calloc(1, ef_size);
memcpy(tmp, file_get_data(ef), ef_size); memcpy(tmp, file_get_data(ef), ef_size);
asn1_ctx_t ctxt; tlv_ctx_t ctxt;
asn1_ctx_init(tmp, (uint16_t)ef_size, &ctxt); tlv_ctx_init(tmp, (uint16_t)ef_size, &ctxt);
asn1_find_tag(&ctxt, TAG_IMF, &chal); tlv_find_tag(&ctxt, TAG_IMF, &chal);
put_uint64_be(v, chal.data); put_uint64_be(v, chal.data);
file_put_data(ef, tmp, (uint16_t)ef_size); file_put_data(ef, tmp, (uint16_t)ef_size);
flash_commit(); flash_commit();
@@ -436,15 +436,15 @@ static int cmd_calculate(void) {
} }
static int cmd_calculate_all(void) { static int cmd_calculate_all(void) {
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, prop = { 0 }; tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, prop = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (P2(apdu) != 0x0 && P2(apdu) != 0x1) { if (P2(apdu) != 0x0 && P2(apdu) != 0x1) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
if (validated == false) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); 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(); return SW_INCORRECT_PARAMS();
} }
res_APDU_size = 0; res_APDU_size = 0;
@@ -453,9 +453,9 @@ static int cmd_calculate_all(void) {
if (file_has_data(ef)) { if (file_has_data(ef)) {
const uint8_t *ef_data = file_get_data(ef); const uint8_t *ef_data = file_get_data(ef);
size_t ef_len = file_get_size(ef); size_t ef_len = file_get_size(ef);
asn1_ctx_t ctxe; tlv_ctx_t ctxe;
asn1_ctx_init((uint8_t *)ef_data, (uint16_t)ef_len, &ctxe); tlv_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) { if (tlv_find_tag(&ctxe, TAG_NAME, &name) == false || tlv_find_tag(&ctxe, TAG_KEY, &key) == false) {
continue; continue;
} }
res_APDU[res_APDU_size++] = TAG_NAME; res_APDU[res_APDU_size++] = TAG_NAME;
@@ -466,7 +466,7 @@ static int cmd_calculate_all(void) {
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[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++] = TAG_TOUCH_RESPONSE;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key.data[1]; res_APDU[res_APDU_size++] = key.data[1];
@@ -495,9 +495,9 @@ static int cmd_set_otp_pin(void) {
if (file_has_data(ef_otp_pin)) { if (file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
asn1_ctx_t ctxi, pw = { 0 }; tlv_ctx_t ctxi, pw = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) { if (tlv_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
hsh[0] = MAX_OTP_COUNTER; hsh[0] = MAX_OTP_COUNTER;
@@ -513,16 +513,16 @@ static int cmd_change_otp_pin(void) {
if (!file_has_data(ef_otp_pin)) { if (!file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
asn1_ctx_t ctxi, pw = { 0 }, new_pw = { 0 }; tlv_ctx_t ctxi, pw = { 0 }, new_pw = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) { if (tlv_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
double_hash_pin(pw.data, pw.len, hsh + 1); double_hash_pin(pw.data, pw.len, hsh + 1);
if (memcmp(file_get_data(ef_otp_pin) + 1, hsh + 1, 32) != 0) { if (memcmp(file_get_data(ef_otp_pin) + 1, hsh + 1, 32) != 0) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); 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(); return SW_INCORRECT_PARAMS();
} }
hsh[0] = MAX_OTP_COUNTER; hsh[0] = MAX_OTP_COUNTER;
@@ -538,9 +538,9 @@ static int cmd_verify_otp_pin(void) {
if (!file_has_data(ef_otp_pin)) { if (!file_has_data(ef_otp_pin)) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
asn1_ctx_t ctxi, pw = { 0 }; tlv_ctx_t ctxi, pw = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) { if (tlv_find_tag(&ctxi, TAG_PASSWORD, &pw) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
double_hash_pin(pw.data, pw.len, hsh + 1); double_hash_pin(pw.data, pw.len, hsh + 1);
@@ -562,29 +562,29 @@ static int cmd_verify_otp_pin(void) {
} }
static int cmd_verify_hotp(void) { static int cmd_verify_hotp(void) {
asn1_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, code = { 0 }; tlv_ctx_t ctxi, key = { 0 }, chal = { 0 }, name = { 0 }, code = { 0 };
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
uint32_t code_int = 0; 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(); return SW_INCORRECT_PARAMS();
} }
file_t *ef = file_search_by_fid(EF_OATH_CRED, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(EF_OATH_CRED, NULL, SPECIFY_EF);
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
asn1_ctx_t ctxe; tlv_ctx_t ctxe;
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe); tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxe);
if (asn1_find_tag(&ctxe, TAG_KEY, &key) == false) { if (tlv_find_tag(&ctxe, TAG_KEY, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if ((key.data[0] & OATH_TYPE_MASK) != OATH_TYPE_HOTP) { if ((key.data[0] & OATH_TYPE_MASK) != OATH_TYPE_HOTP) {
return SW_DATA_INVALID(); 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(); return SW_INCORRECT_PARAMS();
} }
if (asn1_find_tag(&ctxi, TAG_RESPONSE, &code) == true) { if (tlv_find_tag(&ctxi, TAG_RESPONSE, &code) == true) {
code_int = get_uint32_be(code.data); code_int = get_uint32_be(code.data);
} }
@@ -608,7 +608,7 @@ static int cmd_verify_hotp(void) {
} }
static int cmd_rename(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) { if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
@@ -616,13 +616,13 @@ static int cmd_rename(void) {
if (apdu.data[0] != TAG_NAME) { if (apdu.data[0] != TAG_NAME) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) { if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
asn1_ctx_init(name.data + name.len, (uint16_t)(apdu.nc - (name.data + name.len - apdu.data)), &ctxi); tlv_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) { if (tlv_find_tag(&ctxi, TAG_NAME, &new_name) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
if (name.len == new_name.len && memcmp(name.data, new_name.data, name.len) == 0) { if (name.len == new_name.len && memcmp(name.data, new_name.data, name.len) == 0) {
@@ -634,8 +634,8 @@ static int cmd_rename(void) {
} }
uint8_t *fdata = file_get_data(ef); uint8_t *fdata = file_get_data(ef);
uint16_t fsize = file_get_size(ef); uint16_t fsize = file_get_size(ef);
asn1_ctx_init(fdata, fsize, &ctxi); tlv_ctx_init(fdata, fsize, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) { if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
uint8_t *new_data = (uint8_t *) calloc(fsize + new_name.len - name.len, sizeof(uint8_t)); uint8_t *new_data = (uint8_t *) calloc(fsize + new_name.len - name.len, sizeof(uint8_t));
@@ -650,44 +650,44 @@ static int cmd_rename(void) {
} }
static int cmd_get_credential(void) { static int cmd_get_credential(void) {
asn1_ctx_t ctxi, name = { 0 }; tlv_ctx_t ctxi, name = { 0 };
if (apdu.nc < 3) { if (apdu.nc < 3) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
if (apdu.data[0] != TAG_NAME) { if (apdu.data[0] != TAG_NAME) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi); tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == false) { if (tlv_find_tag(&ctxi, TAG_NAME, &name) == false) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = find_oath_cred(name.data, name.len); file_t *ef = find_oath_cred(name.data, name.len);
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
asn1_ctx_t login = { 0 }, pw = { 0 }, meta = { 0 }, prop = { 0 }; tlv_ctx_t login = { 0 }, pw = { 0 }, meta = { 0 }, prop = { 0 };
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
if (asn1_find_tag(&ctxi, TAG_NAME, &name) == true) { if (tlv_find_tag(&ctxi, TAG_NAME, &name) == true) {
res_APDU[res_APDU_size++] = TAG_NAME; res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = (uint8_t)(name.len); res_APDU[res_APDU_size++] = (uint8_t)(name.len);
memcpy(res_APDU + res_APDU_size, name.data, name.len); res_APDU_size += 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++] = TAG_PWS_LOGIN;
res_APDU[res_APDU_size++] = (uint8_t)(login.len); res_APDU[res_APDU_size++] = (uint8_t)(login.len);
memcpy(res_APDU + res_APDU_size, login.data, login.len); res_APDU_size += 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++] = TAG_PWS_PASSWORD;
res_APDU[res_APDU_size++] = (uint8_t)(pw.len); res_APDU[res_APDU_size++] = (uint8_t)(pw.len);
memcpy(res_APDU + res_APDU_size, pw.data, pw.len); res_APDU_size += 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++] = TAG_PWS_METADATA;
res_APDU[res_APDU_size++] = (uint8_t)(meta.len); res_APDU[res_APDU_size++] = (uint8_t)(meta.len);
memcpy(res_APDU + res_APDU_size, meta.data, meta.len); res_APDU_size += 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++] = TAG_PROPERTY;
res_APDU[res_APDU_size++] = (uint8_t)(prop.len); res_APDU[res_APDU_size++] = (uint8_t)(prop.len);
memcpy(res_APDU + res_APDU_size, prop.data, prop.len); res_APDU_size += prop.len; memcpy(res_APDU + res_APDU_size, prop.data, prop.len); res_APDU_size += prop.len;

View File

@@ -24,7 +24,6 @@
#include "files.h" #include "files.h"
#include "random.h" #include "random.h"
#include "version.h" #include "version.h"
#include "asn1.h"
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
#include "usb.h" #include "usb.h"
#if defined(PICO_PLATFORM) #if defined(PICO_PLATFORM)
@@ -148,8 +147,7 @@ static int otp_select(app_t *a, uint8_t force) {
if (cap_supported(CAP_OTP)) { if (cap_supported(CAP_OTP)) {
a->process_apdu = otp_process_apdu; a->process_apdu = otp_process_apdu;
a->unload = otp_unload; a->unload = otp_unload;
if (file_has_data(file_search(EF_OTP_SLOT1)) || if (file_has_data(file_search(EF_OTP_SLOT1)) || file_has_data(file_search(EF_OTP_SLOT2))) {
file_has_data(file_search(EF_OTP_SLOT2))) {
config_seq = 1; config_seq = 1;
} }
else { else {

View File

@@ -22,6 +22,9 @@ RUN apt install -y libccid \
cmake \ cmake \
libfuse-dev \ libfuse-dev \
python3-pyscard \ python3-pyscard \
libtss2-dev \
tpm2-tools \
swtpm \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN pip3 install pytest pycvc cryptography inputimeout fido2==2.0.0 --break-system-packages RUN pip3 install pytest pycvc cryptography inputimeout fido2==2.0.0 --break-system-packages
WORKDIR / 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 esptool.py --chip ESP32-S2 merge_bin -o ../release/pico_fido_esp32-s2.bin @flash_args
cd .. cd ..
else else
sudo apt install -y libtss2-dev tpm2-tools swtpm cmake
mkdir build mkdir build
cd build cd build
cmake -DENABLE_EMULATION=1 .. cmake -DENABLE_EMULATION=1 ..