Update code style.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2023-03-04 14:05:30 +01:00
parent 483073ebb8
commit 8b2be54ede
24 changed files with 1611 additions and 773 deletions

View File

@@ -38,39 +38,52 @@ int cbor_config(const uint8_t *data, size_t len);
int cbor_vendor(const uint8_t *data, size_t len); int cbor_vendor(const uint8_t *data, size_t len);
int cbor_large_blobs(const uint8_t *data, size_t len); int cbor_large_blobs(const uint8_t *data, size_t len);
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; const uint8_t *cbor_data = NULL;
size_t cbor_len = 0; size_t cbor_len = 0;
uint8_t cmd = 0; uint8_t 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) {
return CTAP1_ERR_INVALID_LEN; return CTAP1_ERR_INVALID_LEN;
if (len > 0) }
DEBUG_DATA(data+1,len-1); if (len > 0) {
DEBUG_DATA(data + 1, len - 1);
}
driver_prepare_response_hid(); driver_prepare_response_hid();
if (cmd == CTAPHID_CBOR) { if (cmd == CTAPHID_CBOR) {
if (data[0] == CTAP_MAKE_CREDENTIAL) if (data[0] == CTAP_MAKE_CREDENTIAL) {
return cbor_make_credential(data + 1, len - 1); return cbor_make_credential(data + 1, len - 1);
if (data[0] == CTAP_GET_INFO) }
if (data[0] == CTAP_GET_INFO) {
return cbor_get_info(); return cbor_get_info();
else if (data[0] == CTAP_RESET) }
else if (data[0] == CTAP_RESET) {
return cbor_reset(); return cbor_reset();
else if (data[0] == CTAP_CLIENT_PIN) }
else if (data[0] == CTAP_CLIENT_PIN) {
return cbor_client_pin(data + 1, len - 1); return cbor_client_pin(data + 1, len - 1);
else if (data[0] == CTAP_GET_ASSERTION) }
else if (data[0] == CTAP_GET_ASSERTION) {
return cbor_get_assertion(data + 1, len - 1, false); return cbor_get_assertion(data + 1, len - 1, false);
else if (data[0] == CTAP_GET_NEXT_ASSERTION) }
else if (data[0] == CTAP_GET_NEXT_ASSERTION) {
return cbor_get_next_assertion(data + 1, len - 1); return cbor_get_next_assertion(data + 1, len - 1);
else if (data[0] == CTAP_SELECTION) }
else if (data[0] == CTAP_SELECTION) {
return cbor_selection(); return cbor_selection();
else if (data[0] == CTAP_CREDENTIAL_MGMT || data[0] == 0x41) }
else if (data[0] == CTAP_CREDENTIAL_MGMT || data[0] == 0x41) {
return cbor_cred_mgmt(data + 1, len - 1); return cbor_cred_mgmt(data + 1, len - 1);
else if (data[0] == CTAP_CONFIG) }
else if (data[0] == CTAP_CONFIG) {
return cbor_config(data + 1, len - 1); return cbor_config(data + 1, len - 1);
else if (data[0] == CTAP_LARGE_BLOBS) }
else if (data[0] == CTAP_LARGE_BLOBS) {
return cbor_large_blobs(data + 1, len - 1); return cbor_large_blobs(data + 1, len - 1);
}
} }
else if (cmd == CTAP_VENDOR_CBOR) { else if (cmd == CTAP_VENDOR_CBOR) {
return cbor_vendor(data, len); return cbor_vendor(data, len);
@@ -88,13 +101,14 @@ void cbor_thread() {
if (m == EV_EXIT) { if (m == EV_EXIT) {
break; break;
} }
apdu.sw = cbor_parse(cmd, cbor_data, cbor_len); apdu.sw = cbor_parse(cmd, cbor_data, cbor_len);
if (apdu.sw == 0) if (apdu.sw == 0) {
DEBUG_DATA(res_APDU + 1, res_APDU_size); DEBUG_DATA(res_APDU + 1, res_APDU_size);
}
finished_data_size = res_APDU_size+1; finished_data_size = res_APDU_size + 1;
uint32_t flag = EV_EXEC_FINISHED; uint32_t flag = EV_EXEC_FINISHED;
queue_add_blocking(&card_to_usb_q, &flag); queue_add_blocking(&card_to_usb_q, &flag);

View File

@@ -35,7 +35,7 @@
#include "apdu.h" #include "apdu.h"
uint32_t usage_timer = 0, initial_usage_time_limit = 0; uint32_t usage_timer = 0, initial_usage_time_limit = 0;
uint32_t max_usage_time_period = 600*1000; uint32_t max_usage_time_period = 600 * 1000;
bool needs_power_cycle = false; bool needs_power_cycle = false;
static mbedtls_ecdh_context hkey; static mbedtls_ecdh_context hkey;
static bool hkey_init = false; static bool hkey_init = false;
@@ -50,18 +50,21 @@ int beginUsingPinUvAuthToken(bool userIsPresent) {
} }
void clearUserPresentFlag() { void clearUserPresentFlag() {
if (paut.in_use == true) if (paut.in_use == true) {
paut.user_present = false; paut.user_present = false;
}
} }
void clearUserVerifiedFlag() { void clearUserVerifiedFlag() {
if (paut.in_use == true) if (paut.in_use == true) {
paut.user_verified = false; paut.user_verified = false;
}
} }
void clearPinUvAuthTokenPermissionsExceptLbw() { void clearPinUvAuthTokenPermissionsExceptLbw() {
if (paut.in_use == true) if (paut.in_use == true) {
paut.permissions = CTAP_PERMISSION_LBW; paut.permissions = CTAP_PERMISSION_LBW;
}
} }
void stopUsingPinUvAuthToken() { void stopUsingPinUvAuthToken() {
@@ -76,28 +79,36 @@ void stopUsingPinUvAuthToken() {
} }
bool getUserPresentFlagValue() { bool getUserPresentFlagValue() {
if (paut.in_use != true) if (paut.in_use != true) {
paut.user_present = false; paut.user_present = false;
}
return paut.user_present; return paut.user_present;
} }
bool getUserVerifiedFlagValue() { bool getUserVerifiedFlagValue() {
if (paut.in_use != true) if (paut.in_use != true) {
paut.user_verified = false; paut.user_verified = false;
}
return paut.user_verified; return paut.user_verified;
} }
int regenerate() { int regenerate() {
if (hkey_init == true) if (hkey_init == true) {
mbedtls_ecdh_free(&hkey); mbedtls_ecdh_free(&hkey);
}
mbedtls_ecdh_init(&hkey); mbedtls_ecdh_init(&hkey);
hkey_init = true; hkey_init = true;
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1); 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_gen,
NULL);
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1); mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
if (ret != 0) if (ret != 0) {
return ret; return ret;
}
return 0; return 0;
} }
@@ -105,17 +116,38 @@ int kdf(uint8_t protocol, const mbedtls_mpi *z, uint8_t *sharedSecret) {
int ret = 0; int ret = 0;
uint8_t buf[32]; uint8_t buf[32];
ret = mbedtls_mpi_write_binary(z, buf, sizeof(buf)); ret = mbedtls_mpi_write_binary(z, buf, sizeof(buf));
if (ret != 0) if (ret != 0) {
return ret; return ret;
}
if (protocol == 1) { if (protocol == 1) {
return mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), buf, sizeof(buf), sharedSecret); return mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
buf,
sizeof(buf),
sharedSecret);
} }
else if (protocol == 2) { else if (protocol == 2) {
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
ret = mbedtls_hkdf(md_info, NULL, 0, buf, sizeof(buf), (uint8_t *)"CTAP2 HMAC key", 14, sharedSecret, 32); ret = mbedtls_hkdf(md_info,
if (ret != 0) NULL,
0,
buf,
sizeof(buf),
(uint8_t *) "CTAP2 HMAC key",
14,
sharedSecret,
32);
if (ret != 0) {
return ret; return ret;
return mbedtls_hkdf(md_info, NULL, 0, buf, sizeof(buf), (uint8_t *)"CTAP2 AES key", 13, sharedSecret+32, 32); }
return mbedtls_hkdf(md_info,
NULL,
0,
buf,
sizeof(buf),
(uint8_t *) "CTAP2 AES key",
13,
sharedSecret + 32,
32);
} }
return -1; return -1;
} }
@@ -123,7 +155,12 @@ 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) { int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret) {
mbedtls_mpi z; mbedtls_mpi z;
mbedtls_mpi_init(&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_gen,
NULL);
ret = kdf(protocol, &z, sharedSecret); ret = kdf(protocol, &z, sharedSecret);
mbedtls_mpi_free(&z); mbedtls_mpi_free(&z);
return ret; return ret;
@@ -144,12 +181,12 @@ int resetPinUvAuthToken() {
int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) { int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) {
if (protocol == 1) { if (protocol == 1) {
memcpy(out, in, in_len); memcpy(out, in, in_len);
return aes_encrypt(key, NULL, 32*8, HSM_AES_MODE_CBC, out, in_len); return aes_encrypt(key, NULL, 32 * 8, HSM_AES_MODE_CBC, out, in_len);
} }
else if (protocol == 2) { else if (protocol == 2) {
random_gen(NULL, out, IV_SIZE); random_gen(NULL, out, IV_SIZE);
memcpy(out + IV_SIZE, in, in_len); memcpy(out + IV_SIZE, in, in_len);
return aes_encrypt(key+32, out, 32*8, HSM_AES_MODE_CBC, out+IV_SIZE, in_len); return aes_encrypt(key + 32, out, 32 * 8, HSM_AES_MODE_CBC, out + IV_SIZE, in_len);
} }
return -1; return -1;
@@ -158,29 +195,36 @@ int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_l
int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) { int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out) {
if (protocol == 1) { if (protocol == 1) {
memcpy(out, in, in_len); memcpy(out, in, in_len);
return aes_decrypt(key, NULL, 32*8, HSM_AES_MODE_CBC, out, in_len); return aes_decrypt(key, NULL, 32 * 8, HSM_AES_MODE_CBC, out, in_len);
} }
else if (protocol == 2) { else if (protocol == 2) {
memcpy(out, in+IV_SIZE, in_len); memcpy(out, in + IV_SIZE, in_len);
return aes_decrypt(key+32, in, 32*8, HSM_AES_MODE_CBC, out, in_len-IV_SIZE); return aes_decrypt(key + 32, in, 32 * 8, HSM_AES_MODE_CBC, out, in_len - IV_SIZE);
} }
return -1; return -1;
} }
int authenticate(uint8_t protocol, const uint8_t *key, const uint8_t *data, size_t len, uint8_t *sign) { int authenticate(uint8_t protocol,
const uint8_t *key,
const uint8_t *data,
size_t len,
uint8_t *sign) {
uint8_t hmac[32]; uint8_t hmac[32];
int ret = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, 32, data, len, hmac); int ret =
if (ret != 0) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, 32, data, len, hmac);
if (ret != 0) {
return ret; return ret;
}
if (protocol == 1) { if (protocol == 1) {
memcpy(sign, hmac, 16); memcpy(sign, hmac, 16);
} }
else if (protocol == 2) { else if (protocol == 2) {
memcpy(sign, hmac, 32); memcpy(sign, hmac, 32);
} }
else else {
return -1; return -1;
}
return 0; return 0;
} }
@@ -188,13 +232,17 @@ int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, size_t len
uint8_t hmac[32]; uint8_t hmac[32];
//if (paut.in_use == false) //if (paut.in_use == false)
// return -2; // return -2;
int ret = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, 32, data, len, hmac); int ret =
if (ret != 0) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), key, 32, data, len, hmac);
if (ret != 0) {
return ret; return ret;
if (protocol == 1) }
if (protocol == 1) {
return memcmp(sign, hmac, 16); return memcmp(sign, hmac, 16);
else if (protocol == 2) }
else if (protocol == 2) {
return memcmp(sign, hmac, 32); return memcmp(sign, hmac, 32);
}
return -1; return -1;
} }
@@ -208,13 +256,17 @@ int getPublicKey() {
} }
int pinUvAuthTokenUsageTimerObserver() { int pinUvAuthTokenUsageTimerObserver() {
if (usage_timer == 0) if (usage_timer == 0) {
return -1; return -1;
if (usage_timer+max_usage_time_period > board_millis()) { }
if (user_present_time_limit == 0 || user_present_time_limit+TRANSPORT_TIME_LIMIT < board_millis()) if (usage_timer + max_usage_time_period > board_millis()) {
if (user_present_time_limit == 0 ||
user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) {
clearUserPresentFlag(); clearUserPresentFlag();
}
if (paut.in_use == true) { if (paut.in_use == true) {
if (initial_usage_time_limit == 0 || initial_usage_time_limit+TRANSPORT_TIME_LIMIT < board_millis()) { if (initial_usage_time_limit == 0 ||
initial_usage_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) {
stopUsingPinUvAuthToken(); stopUsingPinUvAuthToken();
return 1; return 1;
} }
@@ -234,20 +286,24 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CborEncoder encoder, mapEncoder; CborEncoder encoder, mapEncoder;
CborValue map; CborValue map;
CborError error = CborNoError; CborError error = CborNoError;
CborByteString pinUvAuthParam = {0}, newPinEnc = {0}, pinHashEnc = {0}, kax = {0}, kay = {0}; CborByteString pinUvAuthParam = { 0 }, newPinEnc = { 0 }, pinHashEnc = { 0 }, kax = { 0 },
CborCharString rpId = {0}; kay = { 0 };
CborCharString rpId = { 0 };
CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map));
uint64_t val_c = 1; uint64_t val_c = 1;
if (hkey_init == false) if (hkey_init == false) {
initialize(); initialize();
}
CBOR_PARSE_MAP_START(map, 1) CBOR_PARSE_MAP_START(map, 1)
{ {
uint64_t val_u = 0; uint64_t val_u = 0;
CBOR_FIELD_GET_UINT(val_u, 1); CBOR_FIELD_GET_UINT(val_u, 1);
if (val_c <= 2 && val_c != val_u) if (val_c <= 2 && val_c != val_u) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (val_u < val_c) }
if (val_u < val_c) {
CBOR_ERROR(CTAP2_ERR_INVALID_CBOR); CBOR_ERROR(CTAP2_ERR_INVALID_CBOR);
}
val_c = val_u + 1; val_c = val_u + 1;
if (val_u == 0x01) { if (val_u == 0x01) {
CBOR_FIELD_GET_UINT(pinUvAuthProtocol, 1); CBOR_FIELD_GET_UINT(pinUvAuthProtocol, 1);
@@ -257,7 +313,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
} }
else if (val_u == 0x03) { else if (val_u == 0x03) {
int64_t key = 0; int64_t key = 0;
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
CBOR_FIELD_GET_INT(key, 2); CBOR_FIELD_GET_INT(key, 2);
if (key == 1) { if (key == 1) {
CBOR_FIELD_GET_INT(kty, 2); CBOR_FIELD_GET_INT(kty, 2);
@@ -274,8 +331,9 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
else if (key == -3) { else if (key == -3) {
CBOR_FIELD_GET_BYTES(kay, 2); CBOR_FIELD_GET_BYTES(kay, 2);
} }
else else {
CBOR_ADVANCE(2); CBOR_ADVANCE(2);
}
} }
CBOR_PARSE_MAP_END(_f1, 2); CBOR_PARSE_MAP_END(_f1, 2);
} }
@@ -298,12 +356,13 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_PARSE_MAP_END(map, 1); CBOR_PARSE_MAP_END(map, 1);
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
if (subcommand == 0x0) if (subcommand == 0x0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
else if (subcommand == 0x1) { //getPINRetries else if (subcommand == 0x1) { //getPINRetries
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, needs_power_cycle ? 2 : 1)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, needs_power_cycle ? 2 : 1));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, (uint64_t)*file_get_data(ef_pin))); CBOR_CHECK(cbor_encode_uint(&mapEncoder, (uint64_t) *file_get_data(ef_pin)));
if (needs_power_cycle) { if (needs_power_cycle) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true)); CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));
@@ -331,20 +390,28 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, pkey, 32)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, pkey, 32));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
} }
else if (pinUvAuthProtocol == 0) else if (pinUvAuthProtocol == 0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
else }
else {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
} }
else if (subcommand == 0x3) { //setPIN else if (subcommand == 0x3) { //setPIN
if (kax.present == false || kay.present == false || pinUvAuthProtocol == 0 || newPinEnc.present == false || pinUvAuthParam.present == false || alg == 0) if (kax.present == false || kay.present == false || pinUvAuthProtocol == 0 ||
newPinEnc.present == false || pinUvAuthParam.present == false || alg == 0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) }
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if (file_has_data(ef_pin)) }
if (file_has_data(ef_pin)) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
if ((pinUvAuthProtocol == 1 && newPinEnc.len != 64) || (pinUvAuthProtocol == 2 && newPinEnc.len != 64+IV_SIZE)) }
if ((pinUvAuthProtocol == 1 && newPinEnc.len != 64) ||
(pinUvAuthProtocol == 2 && newPinEnc.len != 64 + IV_SIZE)) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (mbedtls_mpi_read_binary(&hkey.ctx.mbed_ecdh.Qp.X, kax.data, kax.len) != 0) { if (mbedtls_mpi_read_binary(&hkey.ctx.mbed_ecdh.Qp.X, kax.data, kax.len) != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
@@ -357,45 +424,60 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
if (verify(pinUvAuthProtocol, sharedSecret, newPinEnc.data, newPinEnc.len, pinUvAuthParam.data) != 0) { if (verify(pinUvAuthProtocol, sharedSecret, newPinEnc.data, newPinEnc.len,
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); pinUvAuthParam.data) != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
uint8_t paddedNewPin[64]; uint8_t paddedNewPin[64];
ret = decrypt(pinUvAuthProtocol, sharedSecret, newPinEnc.data, newPinEnc.len, paddedNewPin); ret = decrypt(pinUvAuthProtocol, sharedSecret, newPinEnc.data, newPinEnc.len, paddedNewPin);
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (ret != 0) if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (paddedNewPin[63] != 0) }
if (paddedNewPin[63] != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
}
uint8_t pin_len = 0; uint8_t pin_len = 0;
while (paddedNewPin[pin_len] != 0 && pin_len < sizeof(paddedNewPin)) while (paddedNewPin[pin_len] != 0 && pin_len < sizeof(paddedNewPin)) {
pin_len++; pin_len++;
}
uint8_t minPin = 4; uint8_t minPin = 4;
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) if (file_has_data(ef_minpin)) {
minPin = *file_get_data(ef_minpin); minPin = *file_get_data(ef_minpin);
if (pin_len < minPin) }
if (pin_len < minPin) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
}
uint8_t hsh[34]; uint8_t hsh[34];
hsh[0] = MAX_PIN_RETRIES; hsh[0] = MAX_PIN_RETRIES;
hsh[1] = pin_len; hsh[1] = pin_len;
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2); mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2);
flash_write_data_to_file(ef_pin, hsh, 2+16); flash_write_data_to_file(ef_pin, hsh, 2 + 16);
low_flash_available(); low_flash_available();
goto err; //No return goto err; //No return
} }
else if (subcommand == 0x4) { //changePIN else if (subcommand == 0x4) { //changePIN
if (kax.present == false || kay.present == false || pinUvAuthProtocol == 0 || newPinEnc.present == false || pinUvAuthParam.present == false || alg == 0 || pinHashEnc.present == false) if (kax.present == false || kay.present == false || pinUvAuthProtocol == 0 ||
newPinEnc.present == false || pinUvAuthParam.present == false || alg == 0 ||
pinHashEnc.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) }
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if (!file_has_data(ef_pin)) }
if (!file_has_data(ef_pin)) {
CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET); CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET);
if (*file_get_data(ef_pin) == 0) }
if (*file_get_data(ef_pin) == 0) {
CBOR_ERROR(CTAP2_ERR_PIN_BLOCKED); CBOR_ERROR(CTAP2_ERR_PIN_BLOCKED);
if ((pinUvAuthProtocol == 1 && (newPinEnc.len != 64 || pinHashEnc.len != 16)) || (pinUvAuthProtocol == 2 && (newPinEnc.len != 64+IV_SIZE || pinHashEnc.len != 16+IV_SIZE))) }
if ((pinUvAuthProtocol == 1 && (newPinEnc.len != 64 || pinHashEnc.len != 16)) ||
(pinUvAuthProtocol == 2 &&
(newPinEnc.len != 64 + IV_SIZE || pinHashEnc.len != 16 + IV_SIZE))) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (mbedtls_mpi_read_binary(&hkey.ctx.mbed_ecdh.Qp.X, kax.data, kax.len) != 0) { if (mbedtls_mpi_read_binary(&hkey.ctx.mbed_ecdh.Qp.X, kax.data, kax.len) != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
@@ -411,7 +493,8 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
uint8_t tmp[80 + 32]; uint8_t tmp[80 + 32];
memcpy(tmp, newPinEnc.data, newPinEnc.len); memcpy(tmp, newPinEnc.data, newPinEnc.len);
memcpy(tmp + newPinEnc.len, pinHashEnc.data, pinHashEnc.len); memcpy(tmp + newPinEnc.len, pinHashEnc.data, pinHashEnc.len);
if (verify(pinUvAuthProtocol, sharedSecret, tmp, newPinEnc.len+pinHashEnc.len, pinUvAuthParam.data) != 0) { if (verify(pinUvAuthProtocol, sharedSecret, tmp, newPinEnc.len + pinHashEnc.len,
pinUvAuthParam.data) != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
@@ -422,23 +505,25 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
low_flash_available(); low_flash_available();
uint8_t retries = pin_data[0]; uint8_t retries = pin_data[0];
uint8_t paddedNewPin[64]; uint8_t paddedNewPin[64];
ret = decrypt(pinUvAuthProtocol, sharedSecret, pinHashEnc.data, pinHashEnc.len, paddedNewPin); ret =
decrypt(pinUvAuthProtocol, sharedSecret, pinHashEnc.data, pinHashEnc.len, paddedNewPin);
if (ret != 0) { if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
if (memcmp(paddedNewPin, file_get_data(ef_pin)+2, 16) != 0) { if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) {
regenerate(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (retries == 0) { if (retries == 0) {
CBOR_ERROR(CTAP2_ERR_PIN_BLOCKED); CBOR_ERROR(CTAP2_ERR_PIN_BLOCKED);
} }
if (++new_pin_mismatches >= 3) { if (++new_pin_mismatches >= 3) {
needs_power_cycle = true; needs_power_cycle = true;
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_BLOCKED); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_BLOCKED);
} }
else else {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
}
} }
pin_data[0] = MAX_PIN_RETRIES; pin_data[0] = MAX_PIN_RETRIES;
flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data)); flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data));
@@ -449,26 +534,32 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
if (ret != 0) { if (ret != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
if (paddedNewPin[63] != 0) if (paddedNewPin[63] != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
uint8_t pin_len = 0; uint8_t pin_len = 0;
while (paddedNewPin[pin_len] != 0 && pin_len < sizeof(paddedNewPin)) while (paddedNewPin[pin_len] != 0 && pin_len < sizeof(paddedNewPin)) {
pin_len++; pin_len++;
}
uint8_t minPin = 4; uint8_t minPin = 4;
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) if (file_has_data(ef_minpin)) {
minPin = *file_get_data(ef_minpin); minPin = *file_get_data(ef_minpin);
if (pin_len < minPin) }
if (pin_len < minPin) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
}
uint8_t hsh[33]; uint8_t hsh[33];
hsh[0] = MAX_PIN_RETRIES; hsh[0] = MAX_PIN_RETRIES;
hsh[1] = pin_len; hsh[1] = pin_len;
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2); mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), paddedNewPin, pin_len, hsh + 2);
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 && memcmp(hsh+2, file_get_data(ef_pin)+2, 16) == 0) if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1 &&
memcmp(hsh + 2, file_get_data(ef_pin) + 2, 16) == 0) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
flash_write_data_to_file(ef_pin, hsh, 2+16); }
flash_write_data_to_file(ef_pin, hsh, 2 + 16);
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) { if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
uint8_t *tmp = (uint8_t *)calloc(1, file_get_size(ef_minpin)); uint8_t *tmp = (uint8_t *) calloc(1, file_get_size(ef_minpin));
memcpy(tmp, file_get_data(ef_minpin), file_get_size(ef_minpin)); memcpy(tmp, file_get_data(ef_minpin), file_get_size(ef_minpin));
tmp[1] = 0; tmp[1] = 0;
flash_write_data_to_file(ef_minpin, tmp, file_get_size(ef_minpin)); flash_write_data_to_file(ef_minpin, tmp, file_get_size(ef_minpin));
@@ -479,23 +570,31 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
goto err; // No return goto err; // No return
} }
else if (subcommand == 0x9 || subcommand == 0x5) { //getPinUvAuthTokenUsingPinWithPermissions else if (subcommand == 0x9 || subcommand == 0x5) { //getPinUvAuthTokenUsingPinWithPermissions
if (kax.present == false || kay.present == false || pinUvAuthProtocol == 0 || alg == 0 || pinHashEnc.present == false) if (kax.present == false || kay.present == false || pinUvAuthProtocol == 0 || alg == 0 ||
pinHashEnc.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) }
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if (subcommand == 0x5 && (permissions != 0 || rpId.present == true)) }
if (subcommand == 0x5 && (permissions != 0 || rpId.present == true)) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (subcommand == 0x9) { if (subcommand == 0x9) {
if (permissions == 0) if (permissions == 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if ((permissions & CTAP_PERMISSION_BE)) // Not supported yet }
if ((permissions & CTAP_PERMISSION_BE)) { // Not supported yet
CBOR_ERROR(CTAP2_ERR_UNAUTHORIZED_PERMISSION); CBOR_ERROR(CTAP2_ERR_UNAUTHORIZED_PERMISSION);
}
} }
if (!file_has_data(ef_pin)) if (!file_has_data(ef_pin)) {
CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET); CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET);
if (*file_get_data(ef_pin) == 0) }
if (*file_get_data(ef_pin) == 0) {
CBOR_ERROR(CTAP2_ERR_PIN_BLOCKED); CBOR_ERROR(CTAP2_ERR_PIN_BLOCKED);
}
if (mbedtls_mpi_read_binary(&hkey.ctx.mbed_ecdh.Qp.X, kax.data, kax.len) != 0) { if (mbedtls_mpi_read_binary(&hkey.ctx.mbed_ecdh.Qp.X, kax.data, kax.len) != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
@@ -514,51 +613,57 @@ int cbor_client_pin(const uint8_t *data, size_t len) {
flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data)); flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data));
low_flash_available(); low_flash_available();
uint8_t retries = pin_data[0]; uint8_t retries = pin_data[0];
uint8_t paddedNewPin[64], poff = (pinUvAuthProtocol-1)*IV_SIZE; uint8_t paddedNewPin[64], poff = (pinUvAuthProtocol - 1) * IV_SIZE;
ret = decrypt(pinUvAuthProtocol, sharedSecret, pinHashEnc.data, pinHashEnc.len, paddedNewPin); ret =
decrypt(pinUvAuthProtocol, sharedSecret, pinHashEnc.data, pinHashEnc.len, paddedNewPin);
if (ret != 0) { if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
} }
if (memcmp(paddedNewPin, file_get_data(ef_pin)+2, 16) != 0) { if (memcmp(paddedNewPin, file_get_data(ef_pin) + 2, 16) != 0) {
regenerate(); regenerate();
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
if (retries == 0) { if (retries == 0) {
CBOR_ERROR(CTAP2_ERR_PIN_BLOCKED); CBOR_ERROR(CTAP2_ERR_PIN_BLOCKED);
} }
if (++new_pin_mismatches >= 3) { if (++new_pin_mismatches >= 3) {
needs_power_cycle = true; needs_power_cycle = true;
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_BLOCKED); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_BLOCKED);
} }
else else {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
}
} }
pin_data[0] = MAX_PIN_RETRIES; pin_data[0] = MAX_PIN_RETRIES;
new_pin_mismatches = 0; new_pin_mismatches = 0;
flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data)); flash_write_data_to_file(ef_pin, pin_data, sizeof(pin_data));
low_flash_available(); low_flash_available();
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
CBOR_ERROR(CTAP2_ERR_PIN_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_INVALID);
}
resetPinUvAuthToken(); resetPinUvAuthToken();
beginUsingPinUvAuthToken(false); beginUsingPinUvAuthToken(false);
if (subcommand == 0x05) if (subcommand == 0x05) {
permissions = CTAP_PERMISSION_MC | CTAP_PERMISSION_GA; permissions = CTAP_PERMISSION_MC | CTAP_PERMISSION_GA;
}
paut.permissions = permissions; paut.permissions = permissions;
if (rpId.present == true) { if (rpId.present == true) {
mbedtls_sha256((uint8_t *)rpId.data, rpId.len, paut.rp_id_hash, 0); mbedtls_sha256((uint8_t *) rpId.data, rpId.len, paut.rp_id_hash, 0);
paut.has_rp_id = true; paut.has_rp_id = true;
} }
else else {
paut.has_rp_id = false; paut.has_rp_id = false;
}
uint8_t pinUvAuthToken_enc[32 + IV_SIZE]; uint8_t pinUvAuthToken_enc[32 + IV_SIZE];
encrypt(pinUvAuthProtocol, sharedSecret, paut.data, 32, pinUvAuthToken_enc); encrypt(pinUvAuthProtocol, sharedSecret, paut.data, 32, pinUvAuthToken_enc);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, pinUvAuthToken_enc, 32+poff)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, pinUvAuthToken_enc, 32 + poff));
} }
else else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
}
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1); resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
err: err:
@@ -569,8 +674,9 @@ err:
CBOR_FREE_BYTE_STRING(kay); CBOR_FREE_BYTE_STRING(kay);
CBOR_FREE_BYTE_STRING(rpId); CBOR_FREE_BYTE_STRING(rpId);
if (error != CborNoError) { if (error != CborNoError) {
if (error == CborErrorImproperValue) if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
return error; return error;
} }
res_APDU_size = resp_size; res_APDU_size = resp_size;

View File

@@ -36,8 +36,8 @@ int cbor_config(const uint8_t *data, size_t len) {
CborValue map; CborValue map;
CborError error = CborNoError; CborError error = CborNoError;
uint64_t subcommand = 0, pinUvAuthProtocol = 0, vendorCommandId = 0, newMinPinLength = 0; uint64_t subcommand = 0, pinUvAuthProtocol = 0, vendorCommandId = 0, newMinPinLength = 0;
CborByteString pinUvAuthParam = {0}, vendorAutCt = {0}; CborByteString pinUvAuthParam = { 0 }, vendorAutCt = { 0 };
CborCharString minPinLengthRPIDs[32] = {0}; CborCharString minPinLengthRPIDs[32] = { 0 };
size_t resp_size = 0, raw_subpara_len = 0, minPinLengthRPIDs_len = 0; size_t resp_size = 0, raw_subpara_len = 0, minPinLengthRPIDs_len = 0;
CborEncoder encoder, mapEncoder; CborEncoder encoder, mapEncoder;
uint8_t *raw_subpara = NULL; uint8_t *raw_subpara = NULL;
@@ -45,21 +45,25 @@ int cbor_config(const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map));
uint64_t val_c = 1; uint64_t val_c = 1;
CBOR_PARSE_MAP_START(map, 1) { CBOR_PARSE_MAP_START(map, 1)
{
uint64_t val_u = 0; uint64_t val_u = 0;
CBOR_FIELD_GET_UINT(val_u, 1); CBOR_FIELD_GET_UINT(val_u, 1);
if (val_c <= 1 && val_c != val_u) if (val_c <= 1 && val_c != val_u) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (val_u < val_c) }
if (val_u < val_c) {
CBOR_ERROR(CTAP2_ERR_INVALID_CBOR); CBOR_ERROR(CTAP2_ERR_INVALID_CBOR);
}
val_c = val_u + 1; val_c = val_u + 1;
if (val_u == 0x01) { if (val_u == 0x01) {
CBOR_FIELD_GET_UINT(subcommand, 1); CBOR_FIELD_GET_UINT(subcommand, 1);
} }
else if (val_u == 0x02) { else if (val_u == 0x02) {
uint64_t subpara = 0; uint64_t subpara = 0;
raw_subpara = (uint8_t *)cbor_value_get_next_byte(&_f1); raw_subpara = (uint8_t *) cbor_value_get_next_byte(&_f1);
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
if (subcommand == 0xff) { if (subcommand == 0xff) {
CBOR_FIELD_GET_UINT(subpara, 2); CBOR_FIELD_GET_UINT(subpara, 2);
if (subpara == 0x01) { if (subpara == 0x01) {
@@ -75,11 +79,13 @@ int cbor_config(const uint8_t *data, size_t len) {
CBOR_FIELD_GET_UINT(newMinPinLength, 2); CBOR_FIELD_GET_UINT(newMinPinLength, 2);
} }
else if (subpara == 0x02) { else if (subpara == 0x02) {
CBOR_PARSE_ARRAY_START(_f2, 3) { CBOR_PARSE_ARRAY_START(_f2, 3)
{
CBOR_FIELD_GET_TEXT(minPinLengthRPIDs[minPinLengthRPIDs_len], 3); CBOR_FIELD_GET_TEXT(minPinLengthRPIDs[minPinLengthRPIDs_len], 3);
minPinLengthRPIDs_len++; minPinLengthRPIDs_len++;
if (minPinLengthRPIDs_len >= 32) if (minPinLengthRPIDs_len >= 32) {
CBOR_ERROR(CTAP2_ERR_KEY_STORE_FULL); CBOR_ERROR(CTAP2_ERR_KEY_STORE_FULL);
}
} }
CBOR_PARSE_ARRAY_END(_f2, 3); CBOR_PARSE_ARRAY_END(_f2, 3);
} }
@@ -102,40 +108,52 @@ int cbor_config(const uint8_t *data, size_t len) {
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
if (pinUvAuthParam.present == false) if (pinUvAuthParam.present == false) {
CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED); CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED);
if (pinUvAuthProtocol == 0) }
if (pinUvAuthProtocol == 0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
uint8_t *verify_payload = (uint8_t *)calloc(1, 32 + 1 + 1 + raw_subpara_len); uint8_t *verify_payload = (uint8_t *) calloc(1, 32 + 1 + 1 + raw_subpara_len);
memset(verify_payload, 0xff, 32); memset(verify_payload, 0xff, 32);
verify_payload[32] = 0x0d; verify_payload[32] = 0x0d;
verify_payload[33] = subcommand; verify_payload[33] = subcommand;
memcpy(verify_payload + 34, raw_subpara, raw_subpara_len); memcpy(verify_payload + 34, raw_subpara, raw_subpara_len);
error = verify(pinUvAuthProtocol, paut.data, verify_payload, 32 + 1 + 1 + raw_subpara_len, pinUvAuthParam.data); error = verify(pinUvAuthProtocol,
paut.data,
verify_payload,
32 + 1 + 1 + raw_subpara_len,
pinUvAuthParam.data);
free(verify_payload); free(verify_payload);
if (error != CborNoError) if (error != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
if (!(paut.permissions & CTAP_PERMISSION_ACFG)) if (!(paut.permissions & CTAP_PERMISSION_ACFG)) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
if (subcommand == 0xff) { if (subcommand == 0xff) {
if (vendorCommandId == CTAP_CONFIG_AUT_DISABLE) { if (vendorCommandId == CTAP_CONFIG_AUT_DISABLE) {
if (!file_has_data(ef_keydev_enc)) if (!file_has_data(ef_keydev_enc)) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
if (has_keydev_dec == false) }
if (has_keydev_dec == false) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
flash_write_data_to_file(ef_keydev, keydev_dec, sizeof(keydev_dec)); flash_write_data_to_file(ef_keydev, keydev_dec, sizeof(keydev_dec));
mbedtls_platform_zeroize(keydev_dec, sizeof(keydev_dec)); mbedtls_platform_zeroize(keydev_dec, sizeof(keydev_dec));
flash_write_data_to_file(ef_keydev_enc, NULL, 0); // Set ef to 0 bytes flash_write_data_to_file(ef_keydev_enc, NULL, 0); // Set ef to 0 bytes
low_flash_available(); low_flash_available();
} }
else if (vendorCommandId == CTAP_CONFIG_AUT_ENABLE) { else if (vendorCommandId == CTAP_CONFIG_AUT_ENABLE) {
if (!file_has_data(ef_keydev)) if (!file_has_data(ef_keydev)) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
if (mse.init == false) }
if (mse.init == false) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
mbedtls_chachapoly_context chatx; mbedtls_chachapoly_context chatx;
int ret = mse_decrypt_ct(vendorAutCt.data, vendorAutCt.len); int ret = mse_decrypt_ct(vendorAutCt.data, vendorAutCt.len);
@@ -143,13 +161,20 @@ int cbor_config(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
uint8_t key_dev_enc[12+32+16]; uint8_t key_dev_enc[12 + 32 + 16];
random_gen(NULL, key_dev_enc, 12); random_gen(NULL, key_dev_enc, 12);
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, vendorAutCt.data); mbedtls_chachapoly_setkey(&chatx, vendorAutCt.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)); 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));
mbedtls_chachapoly_free(&chatx); mbedtls_chachapoly_free(&chatx);
if (ret != 0){ if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
@@ -167,21 +192,29 @@ int cbor_config(const uint8_t *data, size_t len) {
else if (subcommand == 0x03) { else if (subcommand == 0x03) {
uint8_t currentMinPinLen = 4; uint8_t currentMinPinLen = 4;
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) if (file_has_data(ef_minpin)) {
currentMinPinLen = *file_get_data(ef_minpin); currentMinPinLen = *file_get_data(ef_minpin);
if (newMinPinLength == 0) }
if (newMinPinLength == 0) {
newMinPinLength = currentMinPinLen; newMinPinLength = currentMinPinLen;
else if (newMinPinLength > 0 && newMinPinLength < currentMinPinLen) }
else if (newMinPinLength > 0 && newMinPinLength < currentMinPinLen) {
CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION); CBOR_ERROR(CTAP2_ERR_PIN_POLICY_VIOLATION);
if (forceChangePin == ptrue && !file_has_data(ef_pin)) }
if (forceChangePin == ptrue && !file_has_data(ef_pin)) {
CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET); CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET);
if (file_has_data(ef_pin) && file_get_data(ef_pin)[1] < newMinPinLength) }
if (file_has_data(ef_pin) && file_get_data(ef_pin)[1] < newMinPinLength) {
forceChangePin = ptrue; forceChangePin = ptrue;
uint8_t *data = (uint8_t *)calloc(1, 2 + minPinLengthRPIDs_len * 32); }
uint8_t *data = (uint8_t *) calloc(1, 2 + minPinLengthRPIDs_len * 32);
data[0] = newMinPinLength; data[0] = newMinPinLength;
data[1] = forceChangePin == ptrue ? 1 : 0; data[1] = forceChangePin == ptrue ? 1 : 0;
for (int m = 0; m < minPinLengthRPIDs_len; m++) { for (int m = 0; m < minPinLengthRPIDs_len; m++) {
mbedtls_sha256((uint8_t *)minPinLengthRPIDs[m].data, minPinLengthRPIDs[m].len, data + 2 + m*32, 0); mbedtls_sha256((uint8_t *) minPinLengthRPIDs[m].data,
minPinLengthRPIDs[m].len,
data + 2 + m * 32,
0);
} }
flash_write_data_to_file(ef_minpin, data, 2 + minPinLengthRPIDs_len * 32); flash_write_data_to_file(ef_minpin, data, 2 + minPinLengthRPIDs_len * 32);
low_flash_available(); low_flash_available();
@@ -191,12 +224,13 @@ int cbor_config(const uint8_t *data, size_t len) {
set_opts(get_opts() | FIDO2_OPT_EA); set_opts(get_opts() | FIDO2_OPT_EA);
goto err; goto err;
} }
else else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
}
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1); resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
err: err:
CBOR_FREE_BYTE_STRING(pinUvAuthParam); CBOR_FREE_BYTE_STRING(pinUvAuthParam);
CBOR_FREE_BYTE_STRING(vendorAutCt); CBOR_FREE_BYTE_STRING(vendorAutCt);
for (int i = 0; i < minPinLengthRPIDs_len; i++) { for (int i = 0; i < minPinLengthRPIDs_len; i++) {
@@ -204,8 +238,9 @@ int cbor_config(const uint8_t *data, size_t len) {
} }
if (error != CborNoError) { if (error != CborNoError) {
if (error == CborErrorImproperValue) if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
return error; return error;
} }
res_APDU_size = resp_size; res_APDU_size = resp_size;

View File

@@ -28,16 +28,16 @@ uint8_t rp_counter = 1;
uint8_t rp_total = 0; uint8_t rp_total = 0;
uint8_t cred_counter = 1; uint8_t cred_counter = 1;
uint8_t cred_total = 0; uint8_t cred_total = 0;
CborByteString rpIdHashx = {0}; CborByteString rpIdHashx = { 0 };
int cbor_cred_mgmt(const uint8_t *data, size_t len) { int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CborParser parser; CborParser parser;
CborValue map; CborValue map;
CborError error = CborNoError; CborError error = CborNoError;
uint64_t subcommand = 0, pinUvAuthProtocol = 0; uint64_t subcommand = 0, pinUvAuthProtocol = 0;
CborByteString pinUvAuthParam = {0}, rpIdHash = {0}; CborByteString pinUvAuthParam = { 0 }, rpIdHash = { 0 };
PublicKeyCredentialDescriptor credentialId = {0}; PublicKeyCredentialDescriptor credentialId = { 0 };
PublicKeyCredentialUserEntity user = {0}; PublicKeyCredentialUserEntity user = { 0 };
size_t resp_size = 0; size_t resp_size = 0;
CborEncoder encoder, mapEncoder, mapEncoder2; CborEncoder encoder, mapEncoder, mapEncoder2;
uint8_t *raw_subpara = NULL; uint8_t *raw_subpara = NULL;
@@ -46,34 +46,41 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map));
uint64_t val_c = 1; uint64_t val_c = 1;
CBOR_PARSE_MAP_START(map, 1) { CBOR_PARSE_MAP_START(map, 1)
{
uint64_t val_u = 0; uint64_t val_u = 0;
CBOR_FIELD_GET_UINT(val_u, 1); CBOR_FIELD_GET_UINT(val_u, 1);
if (val_c <= 1 && val_c != val_u) if (val_c <= 1 && val_c != val_u) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (val_u < val_c) }
if (val_u < val_c) {
CBOR_ERROR(CTAP2_ERR_INVALID_CBOR); CBOR_ERROR(CTAP2_ERR_INVALID_CBOR);
}
val_c = val_u + 1; val_c = val_u + 1;
if (val_u == 0x01) { if (val_u == 0x01) {
CBOR_FIELD_GET_UINT(subcommand, 1); CBOR_FIELD_GET_UINT(subcommand, 1);
} }
else if (val_u == 0x02) { else if (val_u == 0x02) {
uint64_t subpara = 0; uint64_t subpara = 0;
raw_subpara = (uint8_t *)cbor_value_get_next_byte(&_f1); raw_subpara = (uint8_t *) cbor_value_get_next_byte(&_f1);
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
CBOR_FIELD_GET_UINT(subpara, 2); CBOR_FIELD_GET_UINT(subpara, 2);
if (subpara == 0x01) { if (subpara == 0x01) {
CBOR_FIELD_GET_BYTES(rpIdHash, 2); CBOR_FIELD_GET_BYTES(rpIdHash, 2);
} }
else if (subpara == 0x02) { else if (subpara == 0x02) {
CBOR_PARSE_MAP_START(_f2, 3) { CBOR_PARSE_MAP_START(_f2, 3)
{
CBOR_FIELD_GET_KEY_TEXT(3); CBOR_FIELD_GET_KEY_TEXT(3);
CBOR_FIELD_KEY_TEXT_VAL_BYTES(3, "id", credentialId.id); CBOR_FIELD_KEY_TEXT_VAL_BYTES(3, "id", credentialId.id);
CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "type", credentialId.type); CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "type", credentialId.type);
if (strcmp(_fd3, "transports") == 0) { if (strcmp(_fd3, "transports") == 0) {
CBOR_PARSE_ARRAY_START(_f3, 4) { CBOR_PARSE_ARRAY_START(_f3, 4)
CBOR_FIELD_GET_TEXT(credentialId.transports[credentialId.transports_len], 4); {
CBOR_FIELD_GET_TEXT(credentialId.transports[credentialId.
transports_len], 4);
credentialId.transports_len++; credentialId.transports_len++;
} }
CBOR_PARSE_ARRAY_END(_f3, 4); CBOR_PARSE_ARRAY_END(_f3, 4);
@@ -82,7 +89,8 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_PARSE_MAP_END(_f2, 3); CBOR_PARSE_MAP_END(_f2, 3);
} }
else if (subpara == 0x03) { else if (subpara == 0x03) {
CBOR_PARSE_MAP_START(_f1, 3) { CBOR_PARSE_MAP_START(_f1, 3)
{
CBOR_FIELD_GET_KEY_TEXT(3); CBOR_FIELD_GET_KEY_TEXT(3);
CBOR_FIELD_KEY_TEXT_VAL_BYTES(3, "id", user.id); CBOR_FIELD_KEY_TEXT_VAL_BYTES(3, "id", user.id);
CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "name", user.parent.name); CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "name", user.parent.name);
@@ -104,82 +112,105 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_PARSE_MAP_END(map, 1); CBOR_PARSE_MAP_END(map, 1);
if (subcommand != 0x03 && subcommand != 0x05) { if (subcommand != 0x03 && subcommand != 0x05) {
if (pinUvAuthParam.present == false) if (pinUvAuthParam.present == false) {
CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED); CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED);
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) }
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
} }
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
if(subcommand == 0x01) { if (subcommand == 0x01) {
if (verify(pinUvAuthProtocol, paut.data, (const uint8_t *)"\x01", 1, pinUvAuthParam.data) != CborNoError) if (verify(pinUvAuthProtocol, paut.data, (const uint8_t *) "\x01", 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (is_preview == false && (!(paut.permissions & CTAP_PERMISSION_CM) || paut.has_rp_id == true)) }
if (is_preview == false &&
(!(paut.permissions & CTAP_PERMISSION_CM) || paut.has_rp_id == true)) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
uint8_t existing = 0; uint8_t existing = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
if (file_has_data(search_dynamic_file(EF_CRED + i))) if (file_has_data(search_dynamic_file(EF_CRED + i))) {
existing++; existing++;
}
} }
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 2)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 2));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, existing)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, existing));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_RESIDENT_CREDENTIALS-existing)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, MAX_RESIDENT_CREDENTIALS - existing));
} }
else if (subcommand == 0x02 || subcommand == 0x03) { else if (subcommand == 0x02 || subcommand == 0x03) {
file_t *rp_ef = NULL; file_t *rp_ef = NULL;
if (subcommand == 0x02) { if (subcommand == 0x02) {
if (verify(pinUvAuthProtocol, paut.data, (const uint8_t *)"\x02", 1, pinUvAuthParam.data) != CborNoError) if (verify(pinUvAuthProtocol, paut.data, (const uint8_t *) "\x02", 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (is_preview == false && (!(paut.permissions & CTAP_PERMISSION_CM) || paut.has_rp_id == true)) }
if (is_preview == false &&
(!(paut.permissions & CTAP_PERMISSION_CM) || paut.has_rp_id == true)) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
rp_counter = 1; rp_counter = 1;
rp_total = 0; rp_total = 0;
} }
else { else {
if (rp_counter > rp_total) if (rp_counter > rp_total) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
} }
uint8_t skip = 0; uint8_t skip = 0;
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *tef = search_dynamic_file(EF_RP + i); file_t *tef = search_dynamic_file(EF_RP + i);
if (file_has_data(tef) && *file_get_data(tef) > 0) { if (file_has_data(tef) && *file_get_data(tef) > 0) {
if (++skip == rp_counter) { if (++skip == rp_counter) {
if (rp_ef == NULL) if (rp_ef == NULL) {
rp_ef = tef; rp_ef = tef;
if (subcommand == 0x03) }
if (subcommand == 0x03) {
break; break;
}
} }
if (subcommand == 0x02) if (subcommand == 0x02) {
rp_total++; rp_total++;
}
} }
} }
if (rp_ef == NULL) if (rp_ef == NULL) {
CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS); CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS);
}
rp_counter++; rp_counter++;
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, subcommand == 0x02 ? 3 : 2)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, subcommand == 0x02 ? 3 : 2));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, 1)); CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, 1));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id"));
CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, (char *)file_get_data(rp_ef)+33, file_get_size(rp_ef)-33)); CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, (char *) file_get_data(rp_ef) + 33,
file_get_size(rp_ef) - 33));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(rp_ef)+1, 32)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(rp_ef) + 1, 32));
if (subcommand == 0x02) { if (subcommand == 0x02) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x05));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, rp_total)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, rp_total));
} }
} }
else if (subcommand == 0x04 || subcommand == 0x05) { else if (subcommand == 0x04 || subcommand == 0x05) {
if (subcommand == 0x04 && rpIdHash.present == false) if (subcommand == 0x04 && rpIdHash.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
if (subcommand == 0x04) { if (subcommand == 0x04) {
*(raw_subpara-1) = 0x04; *(raw_subpara - 1) = 0x04;
if (verify(pinUvAuthProtocol, paut.data, raw_subpara-1, raw_subpara_len+1, pinUvAuthParam.data) != CborNoError) if (verify(pinUvAuthProtocol, paut.data, raw_subpara - 1, raw_subpara_len + 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (is_preview == false && (!(paut.permissions & CTAP_PERMISSION_CM) || (paut.has_rp_id == true && memcmp(paut.rp_id_hash, rpIdHash.data, 32) != 0))) }
if (is_preview == false &&
(!(paut.permissions & CTAP_PERMISSION_CM) ||
(paut.has_rp_id == true && memcmp(paut.rp_id_hash, rpIdHash.data, 32) != 0))) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
cred_counter = 1; cred_counter = 1;
cred_total = 0; cred_total = 0;
} }
@@ -195,21 +226,27 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
file_t *tef = search_dynamic_file(EF_CRED + i); file_t *tef = search_dynamic_file(EF_CRED + i);
if (file_has_data(tef) && memcmp(file_get_data(tef), rpIdHash.data, 32) == 0) { if (file_has_data(tef) && memcmp(file_get_data(tef), rpIdHash.data, 32) == 0) {
if (++skip == cred_counter) { if (++skip == cred_counter) {
if (cred_ef == NULL) if (cred_ef == NULL) {
cred_ef = tef; cred_ef = tef;
if (subcommand == 0x05) }
if (subcommand == 0x05) {
break; break;
}
} }
if (subcommand == 0x04) if (subcommand == 0x04) {
cred_total++; cred_total++;
}
} }
} }
if (!file_has_data(cred_ef)) if (!file_has_data(cred_ef)) {
CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS); CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS);
}
Credential cred = {0}; Credential cred = { 0 };
if (credential_load(file_get_data(cred_ef)+32, file_get_size(cred_ef)-32, rpIdHash.data, &cred) != 0) if (credential_load(file_get_data(cred_ef) + 32, file_get_size(cred_ef) - 32, rpIdHash.data,
&cred) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
mbedtls_ecdsa_context key; mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
@@ -222,24 +259,30 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
cred_counter++; cred_counter++;
uint8_t l = 3; uint8_t l = 3;
if (subcommand == 0x04) if (subcommand == 0x04) {
l++; l++;
}
if (cred.extensions.present == true) { if (cred.extensions.present == true) {
if (cred.extensions.credProtect > 0) if (cred.extensions.credProtect > 0) {
l++; l++;
if (cred.extensions.largeBlobKey == ptrue) }
l++; if (cred.extensions.largeBlobKey == ptrue) {
l++;
}
} }
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x06)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x06));
l = 0; l = 0;
if (cred.userId.present == true) if (cred.userId.present == true) {
l++; l++;
if (cred.userName.present == true) }
if (cred.userName.present == true) {
l++; l++;
if (cred.userDisplayName.present == true) }
if (cred.userDisplayName.present == true) {
l++; l++;
}
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, l)); CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, l));
if (cred.userId.present == true) { if (cred.userId.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id"));
@@ -247,11 +290,13 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
} }
if (cred.userName.present == true) { if (cred.userName.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "name")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "name"));
CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, cred.userName.data, cred.userName.len)); CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, cred.userName.data,
cred.userName.len));
} }
if (cred.userDisplayName.present == true) { if (cred.userDisplayName.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "displayName")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "displayName"));
CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, cred.userDisplayName.data, cred.userDisplayName.len)); CBOR_CHECK(cbor_encode_text_string(&mapEncoder2, cred.userDisplayName.data,
cred.userDisplayName.len));
} }
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
@@ -300,7 +345,8 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_PROCESSING); CBOR_ERROR(CTAP2_ERR_PROCESSING);
} }
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0B));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, largeBlobKey, sizeof(largeBlobKey))); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, largeBlobKey,
sizeof(largeBlobKey)));
mbedtls_platform_zeroize(largeBlobKey, sizeof(largeBlobKey)); mbedtls_platform_zeroize(largeBlobKey, sizeof(largeBlobKey));
} }
} }
@@ -308,29 +354,41 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
} }
else if (subcommand == 0x06) { else if (subcommand == 0x06) {
if (credentialId.id.present == false) if (credentialId.id.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
*(raw_subpara - 1) = 0x06; *(raw_subpara - 1) = 0x06;
if (verify(pinUvAuthProtocol, paut.data, raw_subpara-1, raw_subpara_len+1, pinUvAuthParam.data) != CborNoError) if (verify(pinUvAuthProtocol, paut.data, raw_subpara - 1, raw_subpara_len + 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (is_preview == false && (!(paut.permissions & CTAP_PERMISSION_CM) || (paut.has_rp_id == true && memcmp(paut.rp_id_hash, rpIdHash.data, 32) != 0))) }
if (is_preview == false &&
(!(paut.permissions & CTAP_PERMISSION_CM) ||
(paut.has_rp_id == true && memcmp(paut.rp_id_hash, rpIdHash.data, 32) != 0))) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = search_dynamic_file(EF_CRED + i); file_t *ef = search_dynamic_file(EF_CRED + i);
if (file_has_data(ef) && memcmp(file_get_data(ef)+32, credentialId.id.data, MIN(file_get_size(ef)-32, credentialId.id.len)) == 0) { if (file_has_data(ef) &&
memcmp(file_get_data(ef) + 32, credentialId.id.data,
MIN(file_get_size(ef) - 32, credentialId.id.len)) == 0) {
uint8_t *rp_id_hash = file_get_data(ef); uint8_t *rp_id_hash = file_get_data(ef);
if (delete_file(ef) != 0) if (delete_file(ef) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
for (int j = 0; j < MAX_RESIDENT_CREDENTIALS; j++) { for (int j = 0; j < MAX_RESIDENT_CREDENTIALS; j++) {
file_t *rp_ef = search_dynamic_file(EF_RP + j); file_t *rp_ef = search_dynamic_file(EF_RP + j);
if (file_has_data(rp_ef) && memcmp(file_get_data(rp_ef)+1, rp_id_hash, 32) == 0) { if (file_has_data(rp_ef) &&
uint8_t *rp_data = (uint8_t *)calloc(1, file_get_size(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)); memcpy(rp_data, file_get_data(rp_ef), file_get_size(rp_ef));
rp_data[0] -= 1; rp_data[0] -= 1;
if (rp_data[0] == 0) if (rp_data[0] == 0) {
delete_file(rp_ef); delete_file(rp_ef);
else }
else {
flash_write_data_to_file(rp_ef, rp_data, file_get_size(rp_ef)); flash_write_data_to_file(rp_ef, rp_data, file_get_size(rp_ef));
}
free(rp_data); free(rp_data);
break; break;
} }
@@ -342,27 +400,41 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS); CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS);
} }
else if (subcommand == 0x07) { else if (subcommand == 0x07) {
if (credentialId.id.present == false || user.id.present == false) if (credentialId.id.present == false || user.id.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
*(raw_subpara - 1) = 0x07; *(raw_subpara - 1) = 0x07;
if (verify(pinUvAuthProtocol, paut.data, raw_subpara-1, raw_subpara_len+1, pinUvAuthParam.data) != CborNoError) if (verify(pinUvAuthProtocol, paut.data, raw_subpara - 1, raw_subpara_len + 1,
pinUvAuthParam.data) != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (is_preview == false && (!(paut.permissions & CTAP_PERMISSION_CM) || (paut.has_rp_id == true && memcmp(paut.rp_id_hash, rpIdHash.data, 32) != 0))) }
if (is_preview == false &&
(!(paut.permissions & CTAP_PERMISSION_CM) ||
(paut.has_rp_id == true && memcmp(paut.rp_id_hash, rpIdHash.data, 32) != 0))) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = search_dynamic_file(EF_CRED + i); file_t *ef = search_dynamic_file(EF_CRED + i);
if (file_has_data(ef) && memcmp(file_get_data(ef)+32, credentialId.id.data, MIN(file_get_size(ef)-32, credentialId.id.len)) == 0) { if (file_has_data(ef) &&
Credential cred = {0}; memcmp(file_get_data(ef) + 32, credentialId.id.data,
MIN(file_get_size(ef) - 32, credentialId.id.len)) == 0) {
Credential cred = { 0 };
uint8_t *rp_id_hash = file_get_data(ef); uint8_t *rp_id_hash = file_get_data(ef);
if (credential_load(rp_id_hash+32, file_get_size(ef)-32, rp_id_hash, &cred) != 0) if (credential_load(rp_id_hash + 32, file_get_size(ef) - 32, rp_id_hash,
&cred) != 0) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
if (memcmp(user.id.data, cred.userId.data, MIN(user.id.len, cred.userId.len)) != 0) { }
if (memcmp(user.id.data, cred.userId.data,
MIN(user.id.len, cred.userId.len)) != 0) {
credential_free(&cred); credential_free(&cred);
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
uint8_t newcred[MAX_CRED_ID_LENGTH]; uint8_t newcred[MAX_CRED_ID_LENGTH];
size_t newcred_len = 0; size_t newcred_len = 0;
if (credential_create(&cred.rpId, &cred.userId, &user.parent.name, &user.displayName, &cred.opts, &cred.extensions, cred.use_sign_count, cred.alg, cred.curve, newcred, &newcred_len) != 0) { if (credential_create(&cred.rpId, &cred.userId, &user.parent.name,
&user.displayName, &cred.opts, &cred.extensions,
cred.use_sign_count, cred.alg,
cred.curve, newcred, &newcred_len) != 0) {
credential_free(&cred); credential_free(&cred);
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
} }
@@ -378,7 +450,7 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
} }
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1); resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
err: err:
CBOR_FREE_BYTE_STRING(pinUvAuthParam); CBOR_FREE_BYTE_STRING(pinUvAuthParam);
if (asserted == false) { if (asserted == false) {
@@ -389,11 +461,12 @@ int cbor_cred_mgmt(const uint8_t *data, size_t len) {
CBOR_FREE_BYTE_STRING(user.parent.name); CBOR_FREE_BYTE_STRING(user.parent.name);
CBOR_FREE_BYTE_STRING(credentialId.type); CBOR_FREE_BYTE_STRING(credentialId.type);
for (int n = 0; n < credentialId.transports_len; n++) { for (int n = 0; n < credentialId.transports_len; n++) {
CBOR_FREE_BYTE_STRING(credentialId.transports[n]); CBOR_FREE_BYTE_STRING(credentialId.transports[n]);
} }
if (error != CborNoError) { if (error != CborNoError) {
if (error == CborErrorImproperValue) if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
return error; return error;
} }
res_APDU_size = resp_size; res_APDU_size = resp_size;

View File

@@ -34,7 +34,7 @@
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);
bool residentx = false; bool residentx = false;
Credential credsx[MAX_CREDENTIAL_COUNT_IN_LIST] = {0}; Credential credsx[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 };
uint8_t credentialCounter = 1; uint8_t credentialCounter = 1;
uint8_t numberOfCredentialsx = 0; uint8_t numberOfCredentialsx = 0;
uint8_t flagsx = 0; uint8_t flagsx = 0;
@@ -44,17 +44,20 @@ size_t lenx = 0;
int cbor_get_next_assertion(const uint8_t *data, size_t len) { int cbor_get_next_assertion(const uint8_t *data, size_t len) {
CborError error = CborNoError; CborError error = CborNoError;
if (credentialCounter >= numberOfCredentialsx) if (credentialCounter >= numberOfCredentialsx) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
if (timerx+30*1000 < board_millis()) }
if (timerx + 30 * 1000 < board_millis()) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
CBOR_CHECK(cbor_get_assertion(datax, lenx, true)); CBOR_CHECK(cbor_get_assertion(datax, lenx, true));
timerx = board_millis(); timerx = board_millis();
credentialCounter++; credentialCounter++;
err: err:
if (error != CborNoError || credentialCounter == numberOfCredentialsx) { if (error != CborNoError || credentialCounter == numberOfCredentialsx) {
for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
credential_free(&credsx[i]); credential_free(&credsx[i]);
}
if (datax) { if (datax) {
free(datax); free(datax);
datax = NULL; datax = NULL;
@@ -65,8 +68,9 @@ err:
flagsx = 0; flagsx = 0;
credentialCounter = 0; credentialCounter = 0;
numberOfCredentialsx = 0; numberOfCredentialsx = 0;
if (error == CborErrorImproperValue) if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
return error; return error;
} }
return 0; return 0;
@@ -75,32 +79,35 @@ err:
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) {
size_t resp_size = 0; size_t resp_size = 0;
uint64_t pinUvAuthProtocol = 0, hmacSecretPinUvAuthProtocol = 1; uint64_t pinUvAuthProtocol = 0, hmacSecretPinUvAuthProtocol = 1;
CredOptions options = {0}; CredOptions options = { 0 };
CredExtensions extensions = {0}; CredExtensions extensions = { 0 };
CborParser parser; CborParser parser;
CborEncoder encoder, mapEncoder, mapEncoder2; CborEncoder encoder, mapEncoder, mapEncoder2;
CborValue map; CborValue map;
CborError error = CborNoError; CborError error = CborNoError;
CborByteString pinUvAuthParam = {0}, clientDataHash = {0}; CborByteString pinUvAuthParam = { 0 }, clientDataHash = { 0 };
CborCharString rpId = {0}; CborCharString rpId = { 0 };
PublicKeyCredentialDescriptor allowList[MAX_CREDENTIAL_COUNT_IN_LIST] = {0}; PublicKeyCredentialDescriptor allowList[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 };
Credential creds[MAX_CREDENTIAL_COUNT_IN_LIST] = {0}; Credential creds[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 };
size_t allowList_len = 0, creds_len = 0; size_t allowList_len = 0, creds_len = 0;
uint8_t *aut_data = NULL; uint8_t *aut_data = NULL;
bool asserted = false, up = true, uv = false; bool asserted = false, up = true, uv = false;
int64_t kty = 2, alg = 0, crv = 0; int64_t kty = 2, alg = 0, crv = 0;
CborByteString kax = {0}, kay = {0}, salt_enc = {0}, salt_auth = {0}; CborByteString kax = { 0 }, kay = { 0 }, salt_enc = { 0 }, salt_auth = { 0 };
const bool *credBlob = NULL; const bool *credBlob = NULL;
CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map));
uint64_t val_c = 1; uint64_t val_c = 1;
CBOR_PARSE_MAP_START(map, 1) { CBOR_PARSE_MAP_START(map, 1)
{
uint64_t val_u = 0; uint64_t val_u = 0;
CBOR_FIELD_GET_UINT(val_u, 1); CBOR_FIELD_GET_UINT(val_u, 1);
if (val_c <= 2 && val_c != val_u) if (val_c <= 2 && val_c != val_u) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (val_u < val_c) }
if (val_u < val_c) {
CBOR_ERROR(CTAP2_ERR_INVALID_CBOR); CBOR_ERROR(CTAP2_ERR_INVALID_CBOR);
}
val_c = val_u + 1; val_c = val_u + 1;
if (val_u == 0x01) { if (val_u == 0x01) {
CBOR_FIELD_GET_TEXT(rpId, 1); CBOR_FIELD_GET_TEXT(rpId, 1);
@@ -109,14 +116,17 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_FIELD_GET_BYTES(clientDataHash, 1); CBOR_FIELD_GET_BYTES(clientDataHash, 1);
} }
else if (val_u == 0x03) { // excludeList else if (val_u == 0x03) { // excludeList
CBOR_PARSE_ARRAY_START(_f1, 2) { CBOR_PARSE_ARRAY_START(_f1, 2)
PublicKeyCredentialDescriptor *pc = &allowList[allowList_len]; {
CBOR_PARSE_MAP_START(_f2, 3) { PublicKeyCredentialDescriptor *pc = &allowList[allowList_len];
CBOR_PARSE_MAP_START(_f2, 3)
{
CBOR_FIELD_GET_KEY_TEXT(3); CBOR_FIELD_GET_KEY_TEXT(3);
CBOR_FIELD_KEY_TEXT_VAL_BYTES(3, "id", pc->id); CBOR_FIELD_KEY_TEXT_VAL_BYTES(3, "id", pc->id);
CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "type", pc->type); CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "type", pc->type);
if (strcmp(_fd3, "transports") == 0) { if (strcmp(_fd3, "transports") == 0) {
CBOR_PARSE_ARRAY_START(_f3, 4) { CBOR_PARSE_ARRAY_START(_f3, 4)
{
CBOR_FIELD_GET_TEXT(pc->transports[pc->transports_len], 4); CBOR_FIELD_GET_TEXT(pc->transports[pc->transports_len], 4);
pc->transports_len++; pc->transports_len++;
} }
@@ -130,16 +140,19 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
else if (val_u == 0x04) { // extensions else if (val_u == 0x04) { // extensions
extensions.present = true; extensions.present = true;
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
CBOR_FIELD_GET_KEY_TEXT(2); CBOR_FIELD_GET_KEY_TEXT(2);
if (strcmp(_fd2, "hmac-secret") == 0) { if (strcmp(_fd2, "hmac-secret") == 0) {
extensions.hmac_secret = ptrue; extensions.hmac_secret = ptrue;
uint64_t ukey = 0; uint64_t ukey = 0;
CBOR_PARSE_MAP_START(_f2, 3) { CBOR_PARSE_MAP_START(_f2, 3)
{
CBOR_FIELD_GET_UINT(ukey, 3); CBOR_FIELD_GET_UINT(ukey, 3);
if (ukey == 0x01) { if (ukey == 0x01) {
int64_t kkey = 0; int64_t kkey = 0;
CBOR_PARSE_MAP_START(_f3, 4) { CBOR_PARSE_MAP_START(_f3, 4)
{
CBOR_FIELD_GET_INT(kkey, 4); CBOR_FIELD_GET_INT(kkey, 4);
if (kkey == 1) { if (kkey == 1) {
CBOR_FIELD_GET_INT(kty, 4); CBOR_FIELD_GET_INT(kty, 4);
@@ -156,8 +169,9 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
else if (kkey == -3) { else if (kkey == -3) {
CBOR_FIELD_GET_BYTES(kay, 4); CBOR_FIELD_GET_BYTES(kay, 4);
} }
else else {
CBOR_ADVANCE(4); CBOR_ADVANCE(4);
}
} }
CBOR_PARSE_MAP_END(_f3, 4); CBOR_PARSE_MAP_END(_f3, 4);
} }
@@ -170,8 +184,9 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
else if (ukey == 0x04) { else if (ukey == 0x04) {
CBOR_FIELD_GET_UINT(hmacSecretPinUvAuthProtocol, 3); CBOR_FIELD_GET_UINT(hmacSecretPinUvAuthProtocol, 3);
} }
else else {
CBOR_ADVANCE(3); CBOR_ADVANCE(3);
}
} }
CBOR_PARSE_MAP_END(_f2, 3); CBOR_PARSE_MAP_END(_f2, 3);
continue; continue;
@@ -184,7 +199,8 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
else if (val_u == 0x05) { // options else if (val_u == 0x05) { // options
options.present = true; options.present = true;
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
CBOR_FIELD_GET_KEY_TEXT(2); CBOR_FIELD_GET_KEY_TEXT(2);
CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "rk", options.rk); CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "rk", options.rk);
CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "up", options.up); CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "up", options.up);
@@ -202,12 +218,13 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
CBOR_PARSE_MAP_END(map, 1); CBOR_PARSE_MAP_END(map, 1);
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);
}
uint8_t flags = 0; uint8_t flags = 0;
uint8_t rp_id_hash[32]; uint8_t rp_id_hash[32];
mbedtls_sha256((uint8_t *)rpId.data, rpId.len, rp_id_hash, 0); mbedtls_sha256((uint8_t *) rpId.data, rpId.len, rp_id_hash, 0);
bool resident = false; bool resident = false;
uint8_t numberOfCredentials = 0; uint8_t numberOfCredentials = 0;
@@ -215,18 +232,23 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
if (next == false) { if (next == false) {
if (pinUvAuthParam.present == true) { if (pinUvAuthParam.present == true) {
if (pinUvAuthParam.len == 0 || pinUvAuthParam.data == NULL) { if (pinUvAuthParam.len == 0 || pinUvAuthParam.data == NULL) {
if (check_user_presence() == false) if (check_user_presence() == false) {
CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED); CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED);
if (!file_has_data(ef_pin)) }
if (!file_has_data(ef_pin)) {
CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET); CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET);
else }
else {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
} }
else { else {
if (pinUvAuthProtocol == 0) if (pinUvAuthProtocol == 0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) }
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
} }
} }
if (options.present) { if (options.present) {
@@ -240,76 +262,109 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
} }
//else if (options.up == NULL) //5.7 //else if (options.up == NULL) //5.7
//rup = ptrue; //rup = ptrue;
if (options.uv != NULL) if (options.uv != NULL) {
uv = *options.uv; uv = *options.uv;
if (options.up != NULL) }
if (options.up != NULL) {
up = *options.up; up = *options.up;
}
} }
if (pinUvAuthParam.present == true) { //6.1 if (pinUvAuthParam.present == true) { //6.1
int ret = verify(pinUvAuthProtocol, paut.data, clientDataHash.data, clientDataHash.len, pinUvAuthParam.data); int ret = verify(pinUvAuthProtocol,
if (ret != CborNoError) paut.data,
clientDataHash.data,
clientDataHash.len,
pinUvAuthParam.data);
if (ret != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (getUserVerifiedFlagValue() == false) }
if (getUserVerifiedFlagValue() == false) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (!(paut.permissions & CTAP_PERMISSION_GA)) }
if (!(paut.permissions & CTAP_PERMISSION_GA)) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (paut.has_rp_id == true && memcmp(paut.rp_id_hash, rp_id_hash, 32) != 0) }
if (paut.has_rp_id == true && memcmp(paut.rp_id_hash, rp_id_hash, 32) != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
flags |= FIDO2_AUT_FLAG_UV; flags |= FIDO2_AUT_FLAG_UV;
// Check pinUvAuthToken permissions. See 6.2.2.4 // Check pinUvAuthToken permissions. See 6.2.2.4
} }
if (extensions.present == true && extensions.hmac_secret == ptrue) { if (extensions.present == true && extensions.hmac_secret == ptrue) {
if (kax.present == false || kay.present == false || crv == 0 || alg == 0 || salt_enc.present == false || salt_auth.present == false) if (kax.present == false || kay.present == false || crv == 0 || alg == 0 ||
salt_enc.present == false || salt_auth.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (salt_enc.len != 32+(hmacSecretPinUvAuthProtocol-1)*IV_SIZE && salt_enc.len != 64+(hmacSecretPinUvAuthProtocol-1)*IV_SIZE) }
if (salt_enc.len != 32 + (hmacSecretPinUvAuthProtocol - 1) * IV_SIZE &&
salt_enc.len != 64 + (hmacSecretPinUvAuthProtocol - 1) * IV_SIZE) {
CBOR_ERROR(CTAP1_ERR_INVALID_LEN); CBOR_ERROR(CTAP1_ERR_INVALID_LEN);
}
} }
if (allowList_len > 0) { if (allowList_len > 0) {
for (int e = 0; e < allowList_len; e++) { for (int e = 0; e < allowList_len; e++) {
if (allowList[e].type.present == false || allowList[e].id.present == false) if (allowList[e].type.present == false || allowList[e].id.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (strcmp(allowList[e].type.data, "public-key") != 0) }
if (strcmp(allowList[e].type.data, "public-key") != 0) {
continue; continue;
if (credential_load(allowList[e].id.data, allowList[e].id.len, rp_id_hash, &creds[creds_len]) != 0) { }
if (credential_load(allowList[e].id.data, allowList[e].id.len, rp_id_hash,
&creds[creds_len]) != 0) {
CBOR_FREE_BYTE_STRING(allowList[e].id); CBOR_FREE_BYTE_STRING(allowList[e].id);
credential_free(&creds[creds_len]); credential_free(&creds[creds_len]);
} }
else else {
creds_len++; creds_len++;
}
} }
} }
else { else {
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST; i++) { for (int i = 0;
i < MAX_RESIDENT_CREDENTIALS && creds_len < MAX_CREDENTIAL_COUNT_IN_LIST;
i++) {
file_t *ef = search_dynamic_file(EF_CRED + i); file_t *ef = search_dynamic_file(EF_CRED + i);
if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) if (!file_has_data(ef) || memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue; continue;
int ret = credential_load(file_get_data(ef) + 32, file_get_size(ef) - 32, rp_id_hash, &creds[creds_len]); }
if (ret != 0) int ret = credential_load(file_get_data(ef) + 32,
file_get_size(ef) - 32,
rp_id_hash,
&creds[creds_len]);
if (ret != 0) {
credential_free(&creds[creds_len]); credential_free(&creds[creds_len]);
else }
else {
creds_len++; creds_len++;
}
} }
resident = true; resident = true;
} }
for (int i = 0; i < creds_len; i++) { for (int i = 0; i < creds_len; i++) {
if (creds[i].present == true) { if (creds[i].present == true) {
if (creds[i].extensions.present == true) { if (creds[i].extensions.present == true) {
if (creds[i].extensions.credProtect == CRED_PROT_UV_REQUIRED && !(flags & FIDO2_AUT_FLAG_UV)) if (creds[i].extensions.credProtect == CRED_PROT_UV_REQUIRED &&
!(flags & FIDO2_AUT_FLAG_UV)) {
credential_free(&creds[i]); credential_free(&creds[i]);
else if (creds[i].extensions.credProtect == CRED_PROT_UV_OPTIONAL_WITH_LIST && resident == true && !(flags & FIDO2_AUT_FLAG_UV)) }
else if (creds[i].extensions.credProtect == CRED_PROT_UV_OPTIONAL_WITH_LIST &&
resident == true && !(flags & FIDO2_AUT_FLAG_UV)) {
credential_free(&creds[i]); credential_free(&creds[i]);
else }
else {
creds[numberOfCredentials++] = creds[i]; creds[numberOfCredentials++] = creds[i];
}
} }
else else {
creds[numberOfCredentials++] = creds[i]; creds[numberOfCredentials++] = creds[i];
}
} }
} }
if (numberOfCredentials == 0) if (numberOfCredentials == 0) {
CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS); CBOR_ERROR(CTAP2_ERR_NO_CREDENTIALS);
}
for (int i = 0; i < numberOfCredentials; i++) { for (int i = 0; i < numberOfCredentials; i++) {
for (int j = i + 1; j < numberOfCredentials; j++) { for (int j = i + 1; j < numberOfCredentials; j++) {
@@ -324,14 +379,16 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
if (options.up == ptrue || options.present == false || options.up == NULL) { //9.1 if (options.up == ptrue || options.present == false || options.up == NULL) { //9.1
if (pinUvAuthParam.present == true) { if (pinUvAuthParam.present == true) {
if (getUserPresentFlagValue() == false) { if (getUserPresentFlagValue() == false) {
if (check_user_presence() == false) if (check_user_presence() == false) {
CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED); CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED);
}
} }
} }
else { else {
if (!(flags & FIDO2_AUT_FLAG_UP)) { if (!(flags & FIDO2_AUT_FLAG_UP)) {
if (check_user_presence() == false) if (check_user_presence() == false) {
CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED); CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED);
}
} }
} }
flags |= FIDO2_AUT_FLAG_UP; flags |= FIDO2_AUT_FLAG_UP;
@@ -352,10 +409,11 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
if (numberOfCredentials > 1) { if (numberOfCredentials > 1) {
asserted = true; asserted = true;
residentx = resident; residentx = resident;
for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
credsx[i] = creds[i]; credsx[i] = creds[i];
}
numberOfCredentialsx = numberOfCredentials; numberOfCredentialsx = numberOfCredentials;
datax = (uint8_t *)calloc(1, len); datax = (uint8_t *) calloc(1, len);
memcpy(datax, data, len); memcpy(datax, data, len);
lenx = len; lenx = len;
flagsx = flags; flagsx = flags;
@@ -389,23 +447,29 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
} }
size_t ext_len = 0; size_t ext_len = 0;
uint8_t ext [512]; uint8_t ext[512];
if (extensions.present == true) { if (extensions.present == true) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0); cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
int l = 0; int l = 0;
if (options.up == pfalse) if (options.up == pfalse) {
extensions.hmac_secret = NULL; extensions.hmac_secret = NULL;
if (extensions.hmac_secret != NULL) }
if (extensions.hmac_secret != NULL) {
l++; l++;
if (credBlob == ptrue) }
if (credBlob == ptrue) {
l++; l++;
}
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
if (credBlob == ptrue) { if (credBlob == ptrue) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob"));
if (selcred->extensions.credBlob.present == true) if (selcred->extensions.credBlob.present == true) {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, selcred->extensions.credBlob.data, selcred->extensions.credBlob.len)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, selcred->extensions.credBlob.data,
else selcred->extensions.credBlob.len));
}
else {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, NULL, 0)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, NULL, 0));
}
} }
if (extensions.hmac_secret != NULL) { if (extensions.hmac_secret != NULL) {
@@ -429,12 +493,17 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
if (verify(hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, salt_enc.len, salt_auth.data) != 0) { if (verify(hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, salt_enc.len,
salt_auth.data) != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP2_ERR_EXTENSION_FIRST); CBOR_ERROR(CTAP2_ERR_EXTENSION_FIRST);
} }
uint8_t salt_dec[64], poff = (hmacSecretPinUvAuthProtocol-1)*IV_SIZE; uint8_t salt_dec[64], poff = (hmacSecretPinUvAuthProtocol - 1) * IV_SIZE;
ret = decrypt(hmacSecretPinUvAuthProtocol, sharedSecret, salt_enc.data, salt_enc.len, salt_dec); ret = decrypt(hmacSecretPinUvAuthProtocol,
sharedSecret,
salt_enc.data,
salt_enc.len,
salt_dec);
if (ret != 0) { if (ret != 0) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -445,15 +514,28 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret)); mbedtls_platform_zeroize(sharedSecret, sizeof(sharedSecret));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
if (flags & FIDO2_AUT_FLAG_UV) if (flags & FIDO2_AUT_FLAG_UV) {
crd = cred_random + 32; crd = cred_random + 32;
else }
else {
crd = cred_random; crd = cred_random;
}
uint8_t out1[64], hmac_res[80]; uint8_t out1[64], hmac_res[80];
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), crd, 32, salt_dec, 32, out1); mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
if (salt_enc.len == 64+poff) crd,
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), crd, 32, salt_dec+32, 32, out1+32); 32,
encrypt(hmacSecretPinUvAuthProtocol, sharedSecret, out1, salt_enc.len-poff, hmac_res); salt_dec,
32,
out1);
if (salt_enc.len == 64 + poff) {
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
crd,
32,
salt_dec + 32,
32,
out1 + 32);
}
encrypt(hmacSecretPinUvAuthProtocol, sharedSecret, out1, salt_enc.len - poff, hmac_res);
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, hmac_res, salt_enc.len)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, hmac_res, salt_enc.len));
} }
@@ -465,7 +547,7 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
uint32_t ctr = get_sign_counter(); uint32_t ctr = get_sign_counter();
size_t aut_data_len = 32 + 1 + 4 + ext_len; size_t aut_data_len = 32 + 1 + 4 + ext_len;
aut_data = (uint8_t *)calloc(1, aut_data_len + clientDataHash.len); aut_data = (uint8_t *) calloc(1, aut_data_len + clientDataHash.len);
uint8_t *pa = aut_data; uint8_t *pa = aut_data;
memcpy(pa, rp_id_hash, 32); pa += 32; memcpy(pa, rp_id_hash, 32); pa += 32;
*pa++ = flags; *pa++ = flags;
@@ -474,23 +556,38 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
*pa++ = ctr >> 8; *pa++ = ctr >> 8;
*pa++ = ctr & 0xff; *pa++ = ctr & 0xff;
memcpy(pa, ext, ext_len); pa += ext_len; memcpy(pa, ext, ext_len); pa += ext_len;
if (pa-aut_data != aut_data_len) if (pa - aut_data != aut_data_len) {
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
}
memcpy(pa, clientDataHash.data, clientDataHash.len); memcpy(pa, clientDataHash.data, clientDataHash.len);
uint8_t hash[32], sig[MBEDTLS_ECDSA_MAX_LEN]; uint8_t hash[32], sig[MBEDTLS_ECDSA_MAX_LEN];
ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), aut_data, aut_data_len+clientDataHash.len, hash); ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
aut_data,
aut_data_len + clientDataHash.len,
hash);
size_t olen = 0; size_t olen = 0;
ret = mbedtls_ecdsa_write_signature(&ekey, MBEDTLS_MD_SHA256, hash, 32, sig, sizeof(sig), &olen, random_gen, NULL); ret = mbedtls_ecdsa_write_signature(&ekey,
MBEDTLS_MD_SHA256,
hash,
32,
sig,
sizeof(sig),
&olen,
random_gen,
NULL);
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
uint8_t lfields = 3; uint8_t lfields = 3;
if (selcred->opts.present == true && selcred->opts.rk == ptrue) if (selcred->opts.present == true && selcred->opts.rk == ptrue) {
lfields++; lfields++;
if (numberOfCredentials > 1 && next == false) }
if (numberOfCredentials > 1 && next == false) {
lfields++; lfields++;
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) }
if (extensions.largeBlobKey == ptrue && selcred->extensions.largeBlobKey == ptrue) {
lfields++; lfields++;
}
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, lfields)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, lfields));
@@ -511,14 +608,17 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x04));
uint8_t lu = 1; uint8_t lu = 1;
if (numberOfCredentials > 1 && allowList_len == 0) { if (numberOfCredentials > 1 && allowList_len == 0) {
if (selcred->userName.present == true) if (selcred->userName.present == true) {
lu++; lu++;
if (selcred->userDisplayName.present == true) }
if (selcred->userDisplayName.present == true) {
lu++; lu++;
}
} }
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, lu)); CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, lu));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "id"));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, selcred->userId.data, selcred->userId.len)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, selcred->userId.data,
selcred->userId.len));
if (numberOfCredentials > 1 && allowList_len == 0) { if (numberOfCredentials > 1 && allowList_len == 0) {
if (selcred->userName.present == true) { if (selcred->userName.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "name")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "name"));
@@ -543,15 +643,16 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1); resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
ctr++; ctr++;
flash_write_data_to_file(ef_counter, (uint8_t *)&ctr, sizeof(ctr)); flash_write_data_to_file(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available(); low_flash_available();
err: err:
CBOR_FREE_BYTE_STRING(clientDataHash); CBOR_FREE_BYTE_STRING(clientDataHash);
CBOR_FREE_BYTE_STRING(pinUvAuthParam); CBOR_FREE_BYTE_STRING(pinUvAuthParam);
CBOR_FREE_BYTE_STRING(rpId); CBOR_FREE_BYTE_STRING(rpId);
if (asserted == false) { if (asserted == false) {
for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) for (int i = 0; i < MAX_CREDENTIAL_COUNT_IN_LIST; i++) {
credential_free(&creds[i]); credential_free(&creds[i]);
}
} }
for (int m = 0; m < allowList_len; m++) { for (int m = 0; m < allowList_len; m++) {
@@ -561,11 +662,13 @@ int cbor_get_assertion(const uint8_t *data, size_t len, bool next) {
CBOR_FREE_BYTE_STRING(allowList[m].transports[n]); CBOR_FREE_BYTE_STRING(allowList[m].transports[n]);
} }
} }
if (aut_data) if (aut_data) {
free(aut_data); free(aut_data);
}
if (error != CborNoError) { if (error != CborNoError) {
if (error == CborErrorImproperValue) if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
return error; return error;
} }
res_APDU_size = resp_size; res_APDU_size = resp_size;

View File

@@ -59,10 +59,12 @@ int cbor_get_info() {
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "authnrCfg")); CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "authnrCfg"));
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true)); CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true));
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "clientPin")); CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "clientPin"));
if (file_has_data(ef_pin)) if (file_has_data(ef_pin)) {
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true)); CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true));
else }
else {
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, false)); CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, false));
}
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "largeBlobs")); CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "largeBlobs"));
CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true)); CBOR_CHECK(cbor_encode_boolean(&arrayEncoder, true));
CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "pinUvAuthToken")); CBOR_CHECK(cbor_encode_text_stringz(&arrayEncoder, "pinUvAuthToken"));
@@ -113,16 +115,20 @@ int cbor_get_info() {
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0C)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0C));
if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) if (file_has_data(ef_minpin) && file_get_data(ef_minpin)[1] == 1) {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true)); CBOR_CHECK(cbor_encode_boolean(&mapEncoder, true));
else }
else {
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, false)); CBOR_CHECK(cbor_encode_boolean(&mapEncoder, false));
}
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0D)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0D));
if (file_has_data(ef_minpin)) if (file_has_data(ef_minpin)) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, *file_get_data(ef_minpin))); // minPINLength CBOR_CHECK(cbor_encode_uint(&mapEncoder, *file_get_data(ef_minpin))); // minPINLength
else }
else {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 4)); // minPINLength CBOR_CHECK(cbor_encode_uint(&mapEncoder, 4)); // minPINLength
}
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0E)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x0E));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, PICO_FIDO_VERSION)); // firmwareVersion CBOR_CHECK(cbor_encode_uint(&mapEncoder, PICO_FIDO_VERSION)); // firmwareVersion
@@ -136,9 +142,10 @@ int cbor_get_info() {
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &arrayEncoder));
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
err: err:
if (error != CborNoError) if (error != CborNoError) {
return -CTAP2_ERR_INVALID_CBOR; return -CTAP2_ERR_INVALID_CBOR;
}
res_APDU_size = cbor_encoder_get_buffer_size(&encoder, res_APDU + 1); res_APDU_size = cbor_encoder_get_buffer_size(&encoder, res_APDU + 1);
return 0; return 0;
} }

View File

@@ -33,17 +33,20 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
CborEncoder encoder, mapEncoder; CborEncoder encoder, mapEncoder;
CborError error = CborNoError; CborError error = CborNoError;
uint64_t get = 0, offset = UINT64_MAX, length = 0, pinUvAuthProtocol = 0; uint64_t get = 0, offset = UINT64_MAX, length = 0, pinUvAuthProtocol = 0;
CborByteString set = {0}, pinUvAuthParam = {0}; CborByteString set = { 0 }, pinUvAuthParam = { 0 };
CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map));
uint64_t val_c = 1; uint64_t val_c = 1;
CBOR_PARSE_MAP_START(map, 1) { CBOR_PARSE_MAP_START(map, 1)
{
uint64_t val_u = 0; uint64_t val_u = 0;
CBOR_FIELD_GET_UINT(val_u, 1); CBOR_FIELD_GET_UINT(val_u, 1);
if (val_c <= 0 && val_c != val_u) if (val_c <= 0 && val_c != val_u) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (val_u < val_c) }
if (val_u < val_c) {
CBOR_ERROR(CTAP2_ERR_INVALID_CBOR); CBOR_ERROR(CTAP2_ERR_INVALID_CBOR);
}
val_c = val_u + 1; val_c = val_u + 1;
if (val_u == 0x01) { if (val_u == 0x01) {
CBOR_FIELD_GET_UINT(get, 1); CBOR_FIELD_GET_UINT(get, 1);
@@ -66,31 +69,40 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
} }
CBOR_PARSE_MAP_END(map, 1); CBOR_PARSE_MAP_END(map, 1);
if (offset == UINT64_MAX) if (offset == UINT64_MAX) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if (get == 0 && set.present == false) }
if (get == 0 && set.present == false) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if (get != 0 && set.present == true) }
if (get != 0 && set.present == true) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
if (get > 0) { if (get > 0) {
if (length != 0) if (length != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if (length > MAX_FRAGMENT_LENGTH) }
if (length > MAX_FRAGMENT_LENGTH) {
CBOR_ERROR(CTAP1_ERR_INVALID_LEN); CBOR_ERROR(CTAP1_ERR_INVALID_LEN);
if (offset > file_get_size(ef_largeblob)) }
if (offset > file_get_size(ef_largeblob)) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(ef_largeblob)+offset, MIN(get, file_get_size(ef_largeblob)-offset))); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(ef_largeblob) + offset,
MIN(get, file_get_size(ef_largeblob) - offset)));
} }
else { else {
if (set.len > MAX_FRAGMENT_LENGTH) if (set.len > MAX_FRAGMENT_LENGTH) {
CBOR_ERROR(CTAP1_ERR_INVALID_LEN); CBOR_ERROR(CTAP1_ERR_INVALID_LEN);
}
if (offset == 0) { if (offset == 0) {
if (length == 0) if (length == 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
if (length > MAX_LARGE_BLOB_SIZE) { if (length > MAX_LARGE_BLOB_SIZE) {
CBOR_ERROR(CTAP2_ERR_LARGE_BLOB_STORAGE_FULL); CBOR_ERROR(CTAP2_ERR_LARGE_BLOB_STORAGE_FULL);
} }
@@ -101,38 +113,48 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
expectedNextOffset = 0; expectedNextOffset = 0;
} }
else { else {
if (length != 0) if (length != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
} }
if (offset != expectedNextOffset) if (offset != expectedNextOffset) {
CBOR_ERROR(CTAP1_ERR_INVALID_SEQ); CBOR_ERROR(CTAP1_ERR_INVALID_SEQ);
if (pinUvAuthParam.present == false) }
if (pinUvAuthParam.present == false) {
CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED); CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED);
if (pinUvAuthProtocol == 0) }
if (pinUvAuthProtocol == 0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
uint8_t verify_data[70] = {0}; }
uint8_t verify_data[70] = { 0 };
memset(verify_data, 0xff, 32); memset(verify_data, 0xff, 32);
verify_data[32] = 0x0C; verify_data[32] = 0x0C;
verify_data[34] = offset & 0xff; verify_data[34] = offset & 0xff;
verify_data[35] = offset >> 8; verify_data[35] = offset >> 8;
verify_data[36] = offset >> 16; verify_data[36] = offset >> 16;
verify_data[37] = offset >> 24; verify_data[37] = offset >> 24;
mbedtls_sha256(set.data, set.len, verify_data+38, 0); mbedtls_sha256(set.data, set.len, verify_data + 38, 0);
if (verify(pinUvAuthProtocol, paut.data, verify_data, sizeof(verify_data), pinUvAuthParam.data) != 0) if (verify(pinUvAuthProtocol, paut.data, verify_data, sizeof(verify_data),
pinUvAuthParam.data) != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (!(paut.permissions & CTAP_PERMISSION_LBW)) }
if (!(paut.permissions & CTAP_PERMISSION_LBW)) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (offset+set.len > expectedLength) }
if (offset + set.len > expectedLength) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
if (offset == 0) }
if (offset == 0) {
memset(temp_lba, 0, sizeof(temp_lba)); memset(temp_lba, 0, sizeof(temp_lba));
memcpy(temp_lba+expectedNextOffset, set.data, set.len); }
memcpy(temp_lba + expectedNextOffset, set.data, set.len);
expectedNextOffset += set.len; expectedNextOffset += set.len;
if (expectedNextOffset == expectedLength) { if (expectedNextOffset == expectedLength) {
uint8_t sha[32]; uint8_t sha[32];
mbedtls_sha256(temp_lba, expectedLength-16, sha, 0); mbedtls_sha256(temp_lba, expectedLength - 16, sha, 0);
if (expectedLength > 17 && memcmp(sha, temp_lba+expectedLength-16, 16) != 0) if (expectedLength > 17 && memcmp(sha, temp_lba + expectedLength - 16, 16) != 0) {
CBOR_ERROR(CTAP2_ERR_INTEGRITY_FAILURE); CBOR_ERROR(CTAP2_ERR_INTEGRITY_FAILURE);
}
flash_write_data_to_file(ef_largeblob, temp_lba, expectedLength); flash_write_data_to_file(ef_largeblob, temp_lba, expectedLength);
low_flash_available(); low_flash_available();
} }
@@ -140,11 +162,12 @@ int cbor_large_blobs(const uint8_t *data, size_t len) {
} }
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
err: err:
CBOR_FREE_BYTE_STRING(pinUvAuthParam); CBOR_FREE_BYTE_STRING(pinUvAuthParam);
CBOR_FREE_BYTE_STRING(set); CBOR_FREE_BYTE_STRING(set);
if (error != CborNoError) if (error != CborNoError) {
return -CTAP2_ERR_INVALID_CBOR; return -CTAP2_ERR_INVALID_CBOR;
}
res_APDU_size = cbor_encoder_get_buffer_size(&encoder, res_APDU + 1); res_APDU_size = cbor_encoder_get_buffer_size(&encoder, res_APDU + 1);
return 0; return 0;
} }

View File

@@ -31,18 +31,18 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CborParser parser; CborParser parser;
CborValue map; CborValue map;
CborError error = CborNoError; CborError error = CborNoError;
CborByteString clientDataHash = {0}, pinUvAuthParam = {0}; CborByteString clientDataHash = { 0 }, pinUvAuthParam = { 0 };
PublicKeyCredentialRpEntity rp = {0}; PublicKeyCredentialRpEntity rp = { 0 };
PublicKeyCredentialUserEntity user = {0}; PublicKeyCredentialUserEntity user = { 0 };
PublicKeyCredentialParameters pubKeyCredParams[MAX_CREDENTIAL_COUNT_IN_LIST] = {0}; PublicKeyCredentialParameters pubKeyCredParams[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 };
size_t pubKeyCredParams_len = 0; size_t pubKeyCredParams_len = 0;
PublicKeyCredentialDescriptor excludeList[MAX_CREDENTIAL_COUNT_IN_LIST] = {0}; PublicKeyCredentialDescriptor excludeList[MAX_CREDENTIAL_COUNT_IN_LIST] = { 0 };
size_t excludeList_len = 0; size_t excludeList_len = 0;
CredOptions options = {0}; CredOptions options = { 0 };
uint64_t pinUvAuthProtocol = 0, enterpriseAttestation = 0; uint64_t pinUvAuthProtocol = 0, enterpriseAttestation = 0;
uint8_t *aut_data = NULL; uint8_t *aut_data = NULL;
size_t resp_size = 0; size_t resp_size = 0;
CredExtensions extensions = {0}; CredExtensions extensions = { 0 };
//options.present = true; //options.present = true;
//options.up = ptrue; //options.up = ptrue;
//options.uv = pfalse; //options.uv = pfalse;
@@ -50,19 +50,23 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map));
uint64_t val_c = 1; uint64_t val_c = 1;
CBOR_PARSE_MAP_START(map, 1) { CBOR_PARSE_MAP_START(map, 1)
{
uint64_t val_u = 0; uint64_t val_u = 0;
CBOR_FIELD_GET_UINT(val_u, 1); CBOR_FIELD_GET_UINT(val_u, 1);
if (val_c <= 4 && val_c != val_u) if (val_c <= 4 && val_c != val_u) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (val_u < val_c) }
if (val_u < val_c) {
CBOR_ERROR(CTAP2_ERR_INVALID_CBOR); CBOR_ERROR(CTAP2_ERR_INVALID_CBOR);
}
val_c = val_u + 1; val_c = val_u + 1;
if (val_u == 0x01) { // clientDataHash if (val_u == 0x01) { // clientDataHash
CBOR_FIELD_GET_BYTES(clientDataHash, 1); CBOR_FIELD_GET_BYTES(clientDataHash, 1);
} }
else if (val_u == 0x02) { // rp else if (val_u == 0x02) { // rp
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
CBOR_FIELD_GET_KEY_TEXT(2); CBOR_FIELD_GET_KEY_TEXT(2);
CBOR_FIELD_KEY_TEXT_VAL_TEXT(2, "id", rp.id); CBOR_FIELD_KEY_TEXT_VAL_TEXT(2, "id", rp.id);
CBOR_FIELD_KEY_TEXT_VAL_TEXT(2, "name", rp.parent.name); CBOR_FIELD_KEY_TEXT_VAL_TEXT(2, "name", rp.parent.name);
@@ -70,7 +74,8 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_PARSE_MAP_END(_f1, 2); CBOR_PARSE_MAP_END(_f1, 2);
} }
else if (val_u == 0x03) { // user else if (val_u == 0x03) { // user
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
CBOR_FIELD_GET_KEY_TEXT(2); CBOR_FIELD_GET_KEY_TEXT(2);
CBOR_FIELD_KEY_TEXT_VAL_BYTES(2, "id", user.id); CBOR_FIELD_KEY_TEXT_VAL_BYTES(2, "id", user.id);
CBOR_FIELD_KEY_TEXT_VAL_TEXT(2, "name", user.parent.name); CBOR_FIELD_KEY_TEXT_VAL_TEXT(2, "name", user.parent.name);
@@ -80,9 +85,11 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_PARSE_MAP_END(_f1, 2); CBOR_PARSE_MAP_END(_f1, 2);
} }
else if (val_u == 0x04) { // pubKeyCredParams else if (val_u == 0x04) { // pubKeyCredParams
CBOR_PARSE_ARRAY_START(_f1, 2) { CBOR_PARSE_ARRAY_START(_f1, 2)
{
PublicKeyCredentialParameters *pk = &pubKeyCredParams[pubKeyCredParams_len]; PublicKeyCredentialParameters *pk = &pubKeyCredParams[pubKeyCredParams_len];
CBOR_PARSE_MAP_START(_f2, 3) { CBOR_PARSE_MAP_START(_f2, 3)
{
CBOR_FIELD_GET_KEY_TEXT(3); CBOR_FIELD_GET_KEY_TEXT(3);
CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "type", pk->type); CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "type", pk->type);
CBOR_FIELD_KEY_TEXT_VAL_INT(3, "alg", pk->alg); CBOR_FIELD_KEY_TEXT_VAL_INT(3, "alg", pk->alg);
@@ -93,14 +100,17 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_PARSE_ARRAY_END(_f1, 2); CBOR_PARSE_ARRAY_END(_f1, 2);
} }
else if (val_u == 0x05) { // excludeList else if (val_u == 0x05) { // excludeList
CBOR_PARSE_ARRAY_START(_f1, 2) { CBOR_PARSE_ARRAY_START(_f1, 2)
PublicKeyCredentialDescriptor *pc = &excludeList[excludeList_len]; {
CBOR_PARSE_MAP_START(_f2, 3) { PublicKeyCredentialDescriptor *pc = &excludeList[excludeList_len];
CBOR_PARSE_MAP_START(_f2, 3)
{
CBOR_FIELD_GET_KEY_TEXT(3); CBOR_FIELD_GET_KEY_TEXT(3);
CBOR_FIELD_KEY_TEXT_VAL_BYTES(3, "id", pc->id); CBOR_FIELD_KEY_TEXT_VAL_BYTES(3, "id", pc->id);
CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "type", pc->type); CBOR_FIELD_KEY_TEXT_VAL_TEXT(3, "type", pc->type);
if (strcmp(_fd3, "transports") == 0) { if (strcmp(_fd3, "transports") == 0) {
CBOR_PARSE_ARRAY_START(_f3, 4) { CBOR_PARSE_ARRAY_START(_f3, 4)
{
CBOR_FIELD_GET_TEXT(pc->transports[pc->transports_len], 4); CBOR_FIELD_GET_TEXT(pc->transports[pc->transports_len], 4);
pc->transports_len++; pc->transports_len++;
} }
@@ -114,7 +124,8 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
else if (val_u == 0x06) { // extensions else if (val_u == 0x06) { // extensions
extensions.present = true; extensions.present = true;
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
CBOR_FIELD_GET_KEY_TEXT(2); CBOR_FIELD_GET_KEY_TEXT(2);
CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "hmac-secret", extensions.hmac_secret); CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "hmac-secret", extensions.hmac_secret);
CBOR_FIELD_KEY_TEXT_VAL_UINT(2, "credProtect", extensions.credProtect); CBOR_FIELD_KEY_TEXT_VAL_UINT(2, "credProtect", extensions.credProtect);
@@ -127,7 +138,8 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
else if (val_u == 0x07) { // options else if (val_u == 0x07) { // options
options.present = true; options.present = true;
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
CBOR_FIELD_GET_KEY_TEXT(2); CBOR_FIELD_GET_KEY_TEXT(2);
CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "rk", options.rk); CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "rk", options.rk);
CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "up", options.up); CBOR_FIELD_KEY_TEXT_VAL_BOOL(2, "up", options.up);
@@ -150,51 +162,66 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
uint8_t flags = FIDO2_AUT_FLAG_AT; uint8_t flags = FIDO2_AUT_FLAG_AT;
uint8_t rp_id_hash[32]; uint8_t rp_id_hash[32];
mbedtls_sha256((uint8_t *)rp.id.data, rp.id.len, rp_id_hash, 0); mbedtls_sha256((uint8_t *) rp.id.data, rp.id.len, rp_id_hash, 0);
int curve = -1, alg = 0; int curve = -1, alg = 0;
if (pubKeyCredParams_len == 0) if (pubKeyCredParams_len == 0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
for (int i = 0; i < pubKeyCredParams_len; i++) { for (int i = 0; i < pubKeyCredParams_len; i++) {
if (pubKeyCredParams[i].type.present == false) if (pubKeyCredParams[i].type.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (strcmp(pubKeyCredParams[i].type.data, "public-key") != 0) }
if (strcmp(pubKeyCredParams[i].type.data, "public-key") != 0) {
continue; continue;
if (pubKeyCredParams[i].alg == FIDO2_ALG_ES256) }
if (pubKeyCredParams[i].alg == FIDO2_ALG_ES256) {
curve = FIDO2_CURVE_P256; curve = FIDO2_CURVE_P256;
else if (pubKeyCredParams[i].alg == FIDO2_ALG_ES384) }
else if (pubKeyCredParams[i].alg == FIDO2_ALG_ES384) {
curve = FIDO2_CURVE_P384; curve = FIDO2_CURVE_P384;
else if (pubKeyCredParams[i].alg == FIDO2_ALG_ES512) }
else if (pubKeyCredParams[i].alg == FIDO2_ALG_ES512) {
curve = FIDO2_CURVE_P521; curve = FIDO2_CURVE_P521;
else if (pubKeyCredParams[i].alg == 0) // no present }
else if (pubKeyCredParams[i].alg == 0) { // no present
curve = -1; curve = -1;
else }
else {
curve = 0; curve = 0;
}
if (curve > 0) { if (curve > 0) {
alg = pubKeyCredParams[i].alg; alg = pubKeyCredParams[i].alg;
break; break;
} }
} }
if (curve == 0) if (curve == 0) {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_ALGORITHM); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_ALGORITHM);
else if (curve == -1) }
else if (curve == -1) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
if (pinUvAuthParam.present == true) { if (pinUvAuthParam.present == true) {
if (pinUvAuthParam.len == 0 || pinUvAuthParam.data == NULL) { if (pinUvAuthParam.len == 0 || pinUvAuthParam.data == NULL) {
if (check_user_presence() == false) if (check_user_presence() == false) {
CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED); CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED);
if (!file_has_data(ef_pin)) }
if (!file_has_data(ef_pin)) {
CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET); CBOR_ERROR(CTAP2_ERR_PIN_NOT_SET);
else }
else {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
} }
else { else {
if (pinUvAuthProtocol == 0) if (pinUvAuthProtocol == 0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) }
if (pinUvAuthProtocol != 1 && pinUvAuthProtocol != 2) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
}
} }
} }
if (options.present) { if (options.present) {
@@ -205,7 +232,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP2_ERR_INVALID_OPTION); CBOR_ERROR(CTAP2_ERR_INVALID_OPTION);
} }
//else if (options.up == NULL) //5.7 //else if (options.up == NULL) //5.7
//rup = ptrue; //rup = ptrue;
} }
if (pinUvAuthParam.present == false && options.uv != ptrue && file_has_data(ef_pin)) { //8.1 if (pinUvAuthParam.present == false && options.uv != ptrue && file_has_data(ef_pin)) { //8.1
CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED); CBOR_ERROR(CTAP2_ERR_PUAT_REQUIRED);
@@ -220,15 +247,23 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
//Unfinished. See 6.1.2.9 //Unfinished. See 6.1.2.9
} }
if (pinUvAuthParam.present == true) { //11.1 if (pinUvAuthParam.present == true) { //11.1
int ret = verify(pinUvAuthProtocol, paut.data, clientDataHash.data, clientDataHash.len, pinUvAuthParam.data); int ret = verify(pinUvAuthProtocol,
if (ret != CborNoError) paut.data,
clientDataHash.data,
clientDataHash.len,
pinUvAuthParam.data);
if (ret != CborNoError) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (!(paut.permissions & CTAP_PERMISSION_MC)) }
if (!(paut.permissions & CTAP_PERMISSION_MC)) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (paut.has_rp_id == true && memcmp(paut.rp_id_hash, rp_id_hash, 32) != 0) }
if (paut.has_rp_id == true && memcmp(paut.rp_id_hash, rp_id_hash, 32) != 0) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
if (getUserVerifiedFlagValue() == false) }
if (getUserVerifiedFlagValue() == false) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
flags |= FIDO2_AUT_FLAG_UV; flags |= FIDO2_AUT_FLAG_UV;
if (paut.has_rp_id == false) { if (paut.has_rp_id == false) {
memcpy(paut.rp_id_hash, rp_id_hash, 32); memcpy(paut.rp_id_hash, rp_id_hash, 32);
@@ -237,24 +272,32 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
for (int e = 0; e < excludeList_len; e++) { //12.1 for (int e = 0; e < excludeList_len; e++) { //12.1
if (excludeList[e].type.present == false || excludeList[e].id.present == false) if (excludeList[e].type.present == false || excludeList[e].id.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (strcmp(excludeList[e].type.data, "public-key") != 0) }
if (strcmp(excludeList[e].type.data, "public-key") != 0) {
continue; continue;
}
Credential ecred; Credential ecred;
if (credential_load(excludeList[e].id.data, excludeList[e].id.len, rp_id_hash, &ecred) == 0 && (ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED || (flags & FIDO2_AUT_FLAG_UV))) if (credential_load(excludeList[e].id.data, excludeList[e].id.len, rp_id_hash,
CBOR_ERROR(CTAP2_ERR_CREDENTIAL_EXCLUDED); &ecred) == 0 &&
(ecred.extensions.credProtect != CRED_PROT_UV_REQUIRED ||
(flags & FIDO2_AUT_FLAG_UV))) {
CBOR_ERROR(CTAP2_ERR_CREDENTIAL_EXCLUDED);
}
} }
if (extensions.largeBlobKey == pfalse || (extensions.largeBlobKey == ptrue && options.rk != ptrue)) { if (extensions.largeBlobKey == pfalse ||
(extensions.largeBlobKey == ptrue && options.rk != ptrue)) {
CBOR_ERROR(CTAP2_ERR_INVALID_OPTION); CBOR_ERROR(CTAP2_ERR_INVALID_OPTION);
} }
if (options.up == ptrue || options.up == NULL) { //14.1 if (options.up == ptrue || options.up == NULL) { //14.1
if (pinUvAuthParam.present == true) { if (pinUvAuthParam.present == true) {
if (getUserPresentFlagValue() == false) { if (getUserPresentFlagValue() == false) {
if (check_user_presence() == false) if (check_user_presence() == false) {
CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED); CBOR_ERROR(CTAP2_ERR_OPERATION_DENIED);
}
} }
} }
flags |= FIDO2_AUT_FLAG_UP; flags |= FIDO2_AUT_FLAG_UP;
@@ -268,21 +311,26 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
uint8_t cred_id[MAX_CRED_ID_LENGTH]; uint8_t cred_id[MAX_CRED_ID_LENGTH];
size_t cred_id_len = 0; size_t cred_id_len = 0;
CBOR_CHECK(credential_create(&rp.id, &user.id, &user.parent.name, &user.displayName, &options, &extensions, (!ka || ka->use_sign_count == ptrue), alg, curve, cred_id, &cred_id_len)); CBOR_CHECK(credential_create(&rp.id, &user.id, &user.parent.name, &user.displayName, &options,
&extensions, (!ka || ka->use_sign_count == ptrue), alg, curve,
cred_id, &cred_id_len));
if (getUserVerifiedFlagValue()) if (getUserVerifiedFlagValue()) {
flags |= FIDO2_AUT_FLAG_UV; flags |= FIDO2_AUT_FLAG_UV;
}
size_t ext_len = 0; size_t ext_len = 0;
uint8_t ext [512]; uint8_t ext[512];
CborEncoder encoder, mapEncoder, mapEncoder2; CborEncoder encoder, mapEncoder, mapEncoder2;
if (extensions.present == true) { if (extensions.present == true) {
cbor_encoder_init(&encoder, ext, sizeof(ext), 0); cbor_encoder_init(&encoder, ext, sizeof(ext), 0);
int l = 0; int l = 0;
uint8_t minPinLen = 0; uint8_t minPinLen = 0;
if (extensions.hmac_secret != NULL) if (extensions.hmac_secret != NULL) {
l++; l++;
if (extensions.credProtect != 0) }
if (extensions.credProtect != 0) {
l++; l++;
}
if (extensions.minPinLength != NULL) { if (extensions.minPinLength != NULL) {
file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF); file_t *ef_minpin = search_by_fid(EF_MINPINLEN, NULL, SPECIFY_EF);
if (file_has_data(ef_minpin)) { if (file_has_data(ef_minpin)) {
@@ -290,19 +338,22 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
for (int o = 2; o < file_get_size(ef_minpin); o += 32) { for (int o = 2; o < file_get_size(ef_minpin); o += 32) {
if (memcmp(minpin_data + o, rp_id_hash, 32) == 0) { if (memcmp(minpin_data + o, rp_id_hash, 32) == 0) {
minPinLen = minpin_data[0]; minPinLen = minpin_data[0];
if (minPinLen > 0) if (minPinLen > 0) {
l++; l++;
}
break; break;
} }
} }
} }
} }
if (extensions.credBlob.present == true) if (extensions.credBlob.present == true) {
l++; l++;
}
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, l));
if (extensions.credBlob.present == true) { if (extensions.credBlob.present == true) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credBlob"));
CBOR_CHECK(cbor_encode_boolean(&mapEncoder, extensions.credBlob.len < MAX_CREDBLOB_LENGTH)); CBOR_CHECK(cbor_encode_boolean(&mapEncoder,
extensions.credBlob.len < MAX_CREDBLOB_LENGTH));
} }
if (extensions.credProtect != 0) { if (extensions.credProtect != 0) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credProtect")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "credProtect"));
@@ -358,7 +409,7 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
size_t rs = cbor_encoder_get_buffer_size(&encoder, cbor_buf); size_t rs = cbor_encoder_get_buffer_size(&encoder, cbor_buf);
size_t aut_data_len = 32 + 1 + 4 + (16 + 2 + cred_id_len + rs) + ext_len; size_t aut_data_len = 32 + 1 + 4 + (16 + 2 + cred_id_len + rs) + ext_len;
aut_data = (uint8_t *)calloc(1, aut_data_len + clientDataHash.len); aut_data = (uint8_t *) calloc(1, aut_data_len + clientDataHash.len);
uint8_t *pa = aut_data; uint8_t *pa = aut_data;
memcpy(pa, rp_id_hash, 32); pa += 32; memcpy(pa, rp_id_hash, 32); pa += 32;
*pa++ = flags; *pa++ = flags;
@@ -372,14 +423,17 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
memcpy(pa, cred_id, cred_id_len); pa += cred_id_len; memcpy(pa, cred_id, cred_id_len); pa += cred_id_len;
memcpy(pa, cbor_buf, rs); pa += rs; memcpy(pa, cbor_buf, rs); pa += rs;
memcpy(pa, ext, ext_len); pa += ext_len; memcpy(pa, ext, ext_len); pa += ext_len;
if (pa-aut_data != aut_data_len) { if (pa - aut_data != aut_data_len) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
} }
memcpy(pa, clientDataHash.data, clientDataHash.len); memcpy(pa, clientDataHash.data, clientDataHash.len);
uint8_t hash[32], sig[MBEDTLS_ECDSA_MAX_LEN]; uint8_t hash[32], sig[MBEDTLS_ECDSA_MAX_LEN];
ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), aut_data, aut_data_len+clientDataHash.len, hash); ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
aut_data,
aut_data_len + clientDataHash.len,
hash);
bool self_attestation = true; bool self_attestation = true;
if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) { if (enterpriseAttestation == 2 || (ka && ka->use_self_attestation == pfalse)) {
@@ -388,7 +442,15 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), 32); ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), 32);
self_attestation = false; self_attestation = false;
} }
ret = mbedtls_ecdsa_write_signature(&ekey, MBEDTLS_MD_SHA256, hash, 32, sig, sizeof(sig), &olen, random_gen, NULL); ret = mbedtls_ecdsa_write_signature(&ekey,
MBEDTLS_MD_SHA256,
hash,
32,
sig,
sizeof(sig),
&olen,
random_gen,
NULL);
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
uint8_t largeBlobKey[32]; uint8_t largeBlobKey[32];
@@ -400,7 +462,9 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
} }
cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0); cbor_encoder_init(&encoder, ctap_resp->init.data + 1, CTAP_MAX_PACKET_SIZE, 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, extensions.largeBlobKey == ptrue && options.rk == ptrue ? 5 : 4)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder,
extensions.largeBlobKey == ptrue &&
options.rk == ptrue ? 5 : 4));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "packed")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder, "packed"));
@@ -408,7 +472,8 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, aut_data, aut_data_len)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, aut_data, aut_data_len));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, self_attestation == false ? 3 : 2)); CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2,
self_attestation == false ? 3 : 2));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "alg")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "alg"));
CBOR_CHECK(cbor_encode_negative_int(&mapEncoder2, self_attestation ? -alg : -FIDO2_ALG_ES256)); CBOR_CHECK(cbor_encode_negative_int(&mapEncoder2, self_attestation ? -alg : -FIDO2_ALG_ES256));
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "sig")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "sig"));
@@ -416,13 +481,16 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
if (self_attestation == false) { if (self_attestation == false) {
CborEncoder arrEncoder; CborEncoder arrEncoder;
file_t *ef_cert = NULL; file_t *ef_cert = NULL;
if (enterpriseAttestation == 2) if (enterpriseAttestation == 2) {
ef_cert = search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF); ef_cert = search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
if (!file_has_data(ef_cert)) }
if (!file_has_data(ef_cert)) {
ef_cert = ef_certdev; ef_cert = ef_certdev;
}
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "x5c")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "x5c"));
CBOR_CHECK(cbor_encoder_create_array(&mapEncoder2, &arrEncoder, 1)); CBOR_CHECK(cbor_encoder_create_array(&mapEncoder2, &arrEncoder, 1));
CBOR_CHECK(cbor_encode_byte_string(&arrEncoder, file_get_data(ef_cert), file_get_size(ef_cert))); CBOR_CHECK(cbor_encode_byte_string(&arrEncoder, file_get_data(ef_cert),
file_get_size(ef_cert)));
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder2, &arrEncoder)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder2, &arrEncoder));
} }
CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2)); CBOR_CHECK(cbor_encoder_close_container(&mapEncoder, &mapEncoder2));
@@ -439,14 +507,15 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1); resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
if (options.rk == ptrue) { if (options.rk == ptrue) {
if (credential_store(cred_id, cred_id_len, rp_id_hash) != 0) if (credential_store(cred_id, cred_id_len, rp_id_hash) != 0) {
CBOR_ERROR(CTAP2_ERR_KEY_STORE_FULL); CBOR_ERROR(CTAP2_ERR_KEY_STORE_FULL);
}
} }
ctr++; ctr++;
flash_write_data_to_file(ef_counter, (uint8_t *)&ctr, sizeof(ctr)); flash_write_data_to_file(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available(); low_flash_available();
err: err:
CBOR_FREE_BYTE_STRING(clientDataHash); CBOR_FREE_BYTE_STRING(clientDataHash);
CBOR_FREE_BYTE_STRING(pinUvAuthParam); CBOR_FREE_BYTE_STRING(pinUvAuthParam);
CBOR_FREE_BYTE_STRING(rp.id); CBOR_FREE_BYTE_STRING(rp.id);
CBOR_FREE_BYTE_STRING(rp.parent.name); CBOR_FREE_BYTE_STRING(rp.parent.name);
@@ -464,14 +533,15 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
CBOR_FREE_BYTE_STRING(excludeList[m].transports[n]); CBOR_FREE_BYTE_STRING(excludeList[m].transports[n]);
} }
} }
if (aut_data) if (aut_data) {
free(aut_data); free(aut_data);
}
if (error != CborNoError) { if (error != CborNoError) {
if (error == CborErrorImproperValue) if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
return error; return error;
} }
res_APDU_size = resp_size; res_APDU_size = resp_size;
return 0; return 0;
} }

View File

@@ -20,19 +20,16 @@
#include "ctap2_cbor.h" #include "ctap2_cbor.h"
typedef struct PublicKeyCredentialEntity typedef struct PublicKeyCredentialEntity {
{
CborCharString name; CborCharString name;
} PublicKeyCredentialEntity; } PublicKeyCredentialEntity;
typedef struct PublicKeyCredentialRpEntity typedef struct PublicKeyCredentialRpEntity {
{
PublicKeyCredentialEntity parent; PublicKeyCredentialEntity parent;
CborCharString id; CborCharString id;
} PublicKeyCredentialRpEntity; } PublicKeyCredentialRpEntity;
typedef struct PublicKeyCredentialUserEntity typedef struct PublicKeyCredentialUserEntity {
{
PublicKeyCredentialEntity parent; PublicKeyCredentialEntity parent;
CborByteString id; CborByteString id;
CborCharString displayName; CborCharString displayName;

View File

@@ -1,4 +1,3 @@
/* /*
* This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido). * This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
@@ -27,12 +26,14 @@ extern void scan_all();
int cbor_reset() { int cbor_reset() {
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#if defined(ENABLE_POWER_ON_RESET) && ENABLE_POWER_ON_RESET==1 #if defined(ENABLE_POWER_ON_RESET) && ENABLE_POWER_ON_RESET == 1
if (board_millis() > 10000) if (board_millis() > 10000) {
return CTAP2_ERR_NOT_ALLOWED; return CTAP2_ERR_NOT_ALLOWED;
}
#endif #endif
if (wait_button_pressed() == true) if (wait_button_pressed() == true) {
return CTAP2_ERR_USER_ACTION_TIMEOUT; return CTAP2_ERR_USER_ACTION_TIMEOUT;
}
#endif #endif
initialize_flash(true); initialize_flash(true);
init_fido(); init_fido();

View File

@@ -1,4 +1,3 @@
/* /*
* This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido). * This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
@@ -20,7 +19,8 @@
#include "ctap.h" #include "ctap.h"
int cbor_selection() { int cbor_selection() {
if (wait_button_pressed() == true) if (wait_button_pressed() == true) {
return CTAP2_ERR_USER_ACTION_TIMEOUT; return CTAP2_ERR_USER_ACTION_TIMEOUT;
}
return CTAP2_OK; return CTAP2_OK;
} }

View File

@@ -31,13 +31,20 @@
extern uint8_t keydev_dec[32]; extern uint8_t keydev_dec[32];
extern bool has_keydev_dec; extern bool has_keydev_dec;
mse_t mse = {.init = false}; mse_t mse = { .init = false };
int mse_decrypt_ct(uint8_t *data, size_t len) { int mse_decrypt_ct(uint8_t *data, size_t len) {
mbedtls_chachapoly_context chatx; mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, mse.key_enc + 12); mbedtls_chachapoly_setkey(&chatx, mse.key_enc + 12);
int ret = mbedtls_chachapoly_auth_decrypt(&chatx, len - 16, mse.key_enc, mse.Qpt, 65, data + len - 16, data, data); int ret = mbedtls_chachapoly_auth_decrypt(&chatx,
len - 16,
mse.key_enc,
mse.Qpt,
65,
data + len - 16,
data,
data);
mbedtls_chachapoly_free(&chatx); mbedtls_chachapoly_free(&chatx);
return ret; return ret;
} }
@@ -46,7 +53,7 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
CborParser parser; CborParser parser;
CborValue map; CborValue map;
CborError error = CborNoError; CborError error = CborNoError;
CborByteString pinUvAuthParam = {0}, vendorParam = {0}, kax = {0}, kay = {0}; CborByteString pinUvAuthParam = { 0 }, vendorParam = { 0 }, kax = { 0 }, kay = { 0 };
size_t resp_size = 0; size_t resp_size = 0;
uint64_t vendorCmd = 0, pinUvAuthProtocol = 0; uint64_t vendorCmd = 0, pinUvAuthProtocol = 0;
int64_t kty = 0, alg = 0, crv = 0; int64_t kty = 0, alg = 0, crv = 0;
@@ -54,27 +61,32 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map)); CBOR_CHECK(cbor_parser_init(data, len, 0, &parser, &map));
uint64_t val_c = 1; uint64_t val_c = 1;
CBOR_PARSE_MAP_START(map, 1) { CBOR_PARSE_MAP_START(map, 1)
{
uint64_t val_u = 0; uint64_t val_u = 0;
CBOR_FIELD_GET_UINT(val_u, 1); CBOR_FIELD_GET_UINT(val_u, 1);
if (val_c <= 1 && val_c != val_u) if (val_c <= 1 && val_c != val_u) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
if (val_u < val_c) }
if (val_u < val_c) {
CBOR_ERROR(CTAP2_ERR_INVALID_CBOR); CBOR_ERROR(CTAP2_ERR_INVALID_CBOR);
}
val_c = val_u + 1; val_c = val_u + 1;
if (val_u == 0x01) { if (val_u == 0x01) {
CBOR_FIELD_GET_UINT(vendorCmd, 1); CBOR_FIELD_GET_UINT(vendorCmd, 1);
} }
else if (val_u == 0x02) { else if (val_u == 0x02) {
uint64_t subpara = 0; uint64_t subpara = 0;
CBOR_PARSE_MAP_START(_f1, 2) { CBOR_PARSE_MAP_START(_f1, 2)
{
CBOR_FIELD_GET_UINT(subpara, 2); CBOR_FIELD_GET_UINT(subpara, 2);
if (subpara == 0x01) { if (subpara == 0x01) {
CBOR_FIELD_GET_BYTES(vendorParam, 2); CBOR_FIELD_GET_BYTES(vendorParam, 2);
} }
else if (subpara == 0x02) { else if (subpara == 0x02) {
int64_t key = 0; int64_t key = 0;
CBOR_PARSE_MAP_START(_f2, 3) { CBOR_PARSE_MAP_START(_f2, 3)
{
CBOR_FIELD_GET_INT(key, 3); CBOR_FIELD_GET_INT(key, 3);
if (key == 1) { if (key == 1) {
CBOR_FIELD_GET_INT(kty, 3); CBOR_FIELD_GET_INT(kty, 3);
@@ -91,13 +103,15 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
else if (key == -3) { else if (key == -3) {
CBOR_FIELD_GET_BYTES(kay, 3); CBOR_FIELD_GET_BYTES(kay, 3);
} }
else else {
CBOR_ADVANCE(3); CBOR_ADVANCE(3);
}
} }
CBOR_PARSE_MAP_END(_f2, 3); CBOR_PARSE_MAP_END(_f2, 3);
} }
else else {
CBOR_ADVANCE(2); CBOR_ADVANCE(2);
}
} }
CBOR_PARSE_MAP_END(_f1, 2); CBOR_PARSE_MAP_END(_f1, 2);
} }
@@ -114,17 +128,20 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
if (cmd == CTAP_VENDOR_BACKUP) { if (cmd == CTAP_VENDOR_BACKUP) {
if (vendorCmd == 0x01) { if (vendorCmd == 0x01) {
if (has_keydev_dec == false) if (has_keydev_dec == false) {
CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID); CBOR_ERROR(CTAP2_ERR_PIN_AUTH_INVALID);
}
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x01));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(ef_keydev_enc), file_get_size(ef_keydev_enc))); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, file_get_data(ef_keydev_enc),
file_get_size(ef_keydev_enc)));
} }
else if (vendorCmd == 0x02) { else if (vendorCmd == 0x02) {
if (vendorParam.present == false) if (vendorParam.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
uint8_t zeros[32]; uint8_t zeros[32];
memset(zeros, 0, sizeof(zeros)); memset(zeros, 0, sizeof(zeros));
flash_write_data_to_file(ef_keydev_enc, vendorParam.data, vendorParam.len); flash_write_data_to_file(ef_keydev_enc, vendorParam.data, vendorParam.len);
@@ -139,13 +156,18 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
} }
else if (cmd == CTAP_VENDOR_MSE) { else if (cmd == CTAP_VENDOR_MSE) {
if (vendorCmd == 0x01) { // KeyAgreement if (vendorCmd == 0x01) { // KeyAgreement
if (kax.present == false || kay.present == false || alg == 0) if (kax.present == false || kay.present == false || alg == 0) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER);
}
mbedtls_ecdh_context hkey; mbedtls_ecdh_context hkey;
mbedtls_ecdh_init(&hkey); mbedtls_ecdh_init(&hkey);
mbedtls_ecdh_setup(&hkey, MBEDTLS_ECP_DP_SECP256R1); 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_gen,
NULL);
mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1); mbedtls_mpi_lset(&hkey.ctx.mbed_ecdh.Qp.Z, 1);
if (ret != 0) { if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
@@ -161,19 +183,37 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
uint8_t buf[MBEDTLS_ECP_MAX_BYTES]; uint8_t buf[MBEDTLS_ECP_MAX_BYTES];
size_t olen = 0; size_t olen = 0;
ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp, &hkey.ctx.mbed_ecdh.Qp, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, mse.Qpt, sizeof(mse.Qpt)); ret = mbedtls_ecp_point_write_binary(&hkey.ctx.mbed_ecdh.grp,
&hkey.ctx.mbed_ecdh.Qp,
MBEDTLS_ECP_PF_UNCOMPRESSED,
&olen,
mse.Qpt,
sizeof(mse.Qpt));
if (ret != 0) { if (ret != 0) {
mbedtls_ecdh_free(&hkey); mbedtls_ecdh_free(&hkey);
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); 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_gen,
NULL);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdh_free(&hkey); mbedtls_ecdh_free(&hkey);
mbedtls_platform_zeroize(buf, sizeof(buf)); mbedtls_platform_zeroize(buf, sizeof(buf));
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), NULL, 0, buf, olen, mse.Qpt, sizeof(mse.Qpt), mse.key_enc, sizeof(mse.key_enc)); ret = mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
NULL,
0,
buf,
olen,
mse.Qpt,
sizeof(mse.Qpt),
mse.key_enc,
sizeof(mse.key_enc));
mbedtls_platform_zeroize(buf, sizeof(buf)); mbedtls_platform_zeroize(buf, sizeof(buf));
if (ret != 0) { if (ret != 0) {
mbedtls_ecdh_free(&hkey); mbedtls_ecdh_free(&hkey);
@@ -203,8 +243,9 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
} }
} }
else if (cmd == CTAP_VENDOR_UNLOCK) { else if (cmd == CTAP_VENDOR_UNLOCK) {
if (mse.init == false) if (mse.init == false) {
CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED); CBOR_ERROR(CTAP2_ERR_NOT_ALLOWED);
}
mbedtls_chachapoly_context chatx; mbedtls_chachapoly_context chatx;
int ret = mse_decrypt_ct(vendorParam.data, vendorParam.len); int ret = mse_decrypt_ct(vendorParam.data, vendorParam.len);
@@ -212,16 +253,24 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
if (!file_has_data(ef_keydev_enc)) if (!file_has_data(ef_keydev_enc)) {
CBOR_ERROR(CTAP2_ERR_INTEGRITY_FAILURE); CBOR_ERROR(CTAP2_ERR_INTEGRITY_FAILURE);
}
uint8_t *keyenc = file_get_data(ef_keydev_enc); uint8_t *keyenc = file_get_data(ef_keydev_enc);
size_t keyenc_len = file_get_size(ef_keydev_enc); size_t keyenc_len = file_get_size(ef_keydev_enc);
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, vendorParam.data); mbedtls_chachapoly_setkey(&chatx, vendorParam.data);
ret = mbedtls_chachapoly_auth_decrypt(&chatx, sizeof(keydev_dec), keyenc, NULL, 0, keyenc + keyenc_len - 16, keyenc + 12, keydev_dec); ret = mbedtls_chachapoly_auth_decrypt(&chatx,
sizeof(keydev_dec),
keyenc,
NULL,
0,
keyenc + keyenc_len - 16,
keyenc + 12,
keydev_dec);
mbedtls_chachapoly_free(&chatx); mbedtls_chachapoly_free(&chatx);
if (ret != 0){ if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER); CBOR_ERROR(CTAP1_ERR_INVALID_PARAMETER);
} }
has_keydev_dec = true; has_keydev_dec = true;
@@ -232,7 +281,10 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
uint8_t buffer[1024]; uint8_t buffer[1024];
mbedtls_ecdsa_context ekey; mbedtls_ecdsa_context ekey;
mbedtls_ecdsa_init(&ekey); mbedtls_ecdsa_init(&ekey);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &ekey, file_get_data(ef_keydev), file_get_size(ef_keydev)); int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1,
&ekey,
file_get_data(ef_keydev),
file_get_size(ef_keydev));
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
CBOR_ERROR(CTAP2_ERR_PROCESSING); CBOR_ERROR(CTAP2_ERR_PROCESSING);
@@ -248,19 +300,34 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
#else #else
struct { struct {
uint8_t id[8]; uint8_t id[8];
} rpiid = {0}; } rpiid = { 0 };
#endif #endif
mbedtls_x509write_csr ctx; mbedtls_x509write_csr ctx;
mbedtls_x509write_csr_init(&ctx); mbedtls_x509write_csr_init(&ctx);
snprintf((char *)buffer, sizeof(buffer), "C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %02x%02x%02x%02x%02x%02x%02x%02x", rpiid.id[0], rpiid.id[1], rpiid.id[2], rpiid.id[3], rpiid.id[4], rpiid.id[5], rpiid.id[6], rpiid.id[7]); snprintf((char *) buffer,
mbedtls_x509write_csr_set_subject_name(&ctx, (char *)buffer); sizeof(buffer),
"C=ES,O=Pico Keys,OU=Authenticator Attestation,CN=Pico Fido EE Serial %02x%02x%02x%02x%02x%02x%02x%02x",
rpiid.id[0],
rpiid.id[1],
rpiid.id[2],
rpiid.id[3],
rpiid.id[4],
rpiid.id[5],
rpiid.id[6],
rpiid.id[7]);
mbedtls_x509write_csr_set_subject_name(&ctx, (char *) buffer);
mbedtls_pk_context key; mbedtls_pk_context key;
mbedtls_pk_init(&key); mbedtls_pk_init(&key);
mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)); mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
key.pk_ctx = &ekey; key.pk_ctx = &ekey;
mbedtls_x509write_csr_set_key(&ctx, &key); mbedtls_x509write_csr_set_key(&ctx, &key);
mbedtls_x509write_csr_set_md_alg(&ctx, MBEDTLS_MD_SHA256); 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)); 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_gen, NULL);
mbedtls_ecdsa_free(&ekey); mbedtls_ecdsa_free(&ekey);
if (ret <= 0) { if (ret <= 0) {
@@ -272,27 +339,31 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, buffer + sizeof(buffer) - ret, ret)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder, buffer + sizeof(buffer) - ret, ret));
} }
else if (vendorCmd == 0x02) { else if (vendorCmd == 0x02) {
if (vendorParam.present == false) if (vendorParam.present == false) {
CBOR_ERROR(CTAP2_ERR_MISSING_PARAMETER); 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 = search_by_fid(EF_EE_DEV_EA, NULL, SPECIFY_EF);
if (ef_ee_ea) if (ef_ee_ea) {
flash_write_data_to_file(ef_ee_ea, vendorParam.data, vendorParam.len); flash_write_data_to_file(ef_ee_ea, vendorParam.data, vendorParam.len);
}
low_flash_available(); low_flash_available();
goto err; goto err;
} }
} }
else else {
CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION); CBOR_ERROR(CTAP2_ERR_UNSUPPORTED_OPTION);
}
CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder)); CBOR_CHECK(cbor_encoder_close_container(&encoder, &mapEncoder));
resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1); resp_size = cbor_encoder_get_buffer_size(&encoder, ctap_resp->init.data + 1);
err: err:
CBOR_FREE_BYTE_STRING(pinUvAuthParam); CBOR_FREE_BYTE_STRING(pinUvAuthParam);
CBOR_FREE_BYTE_STRING(vendorParam); CBOR_FREE_BYTE_STRING(vendorParam);
if (error != CborNoError) { if (error != CborNoError) {
if (error == CborErrorImproperValue) if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
return error; return error;
} }
res_APDU_size = resp_size; res_APDU_size = resp_size;
@@ -300,9 +371,11 @@ int cbor_vendor_generic(uint8_t cmd, const uint8_t *data, size_t len) {
} }
int cbor_vendor(const uint8_t *data, size_t len) { int cbor_vendor(const uint8_t *data, size_t len) {
if (len == 0) if (len == 0) {
return CTAP1_ERR_INVALID_LEN; return CTAP1_ERR_INVALID_LEN;
if (data[0] >= CTAP_VENDOR_BACKUP) }
if (data[0] >= CTAP_VENDOR_BACKUP) {
return cbor_vendor_generic(data[0], data + 1, len - 1); return cbor_vendor_generic(data[0], data + 1, len - 1);
}
return CTAP2_ERR_INVALID_CBOR; return CTAP2_ERR_INVALID_CBOR;
} }

View File

@@ -24,21 +24,24 @@
#include "credential.h" #include "credential.h"
int cmd_authenticate() { int cmd_authenticate() {
CTAP_AUTHENTICATE_REQ *req = (CTAP_AUTHENTICATE_REQ *)apdu.data; CTAP_AUTHENTICATE_REQ *req = (CTAP_AUTHENTICATE_REQ *) apdu.data;
CTAP_AUTHENTICATE_RESP *resp = (CTAP_AUTHENTICATE_RESP *)res_APDU; CTAP_AUTHENTICATE_RESP *resp = (CTAP_AUTHENTICATE_RESP *) res_APDU;
//if (scan_files(true) != CCID_OK) //if (scan_files(true) != CCID_OK)
// return SW_EXEC_ERROR(); // return SW_EXEC_ERROR();
if (apdu.nc < CTAP_CHAL_SIZE+CTAP_APPID_SIZE+1+1) if (apdu.nc < CTAP_CHAL_SIZE + CTAP_APPID_SIZE + 1 + 1) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
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() == true) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
}
mbedtls_ecdsa_context key; mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
int ret = 0; int ret = 0;
uint8_t *tmp_kh = (uint8_t *)calloc(1, req->keyHandleLen); uint8_t *tmp_kh = (uint8_t *) calloc(1, req->keyHandleLen);
memcpy(tmp_kh, req->keyHandle, req->keyHandleLen); memcpy(tmp_kh, req->keyHandle, req->keyHandleLen);
if (credential_verify(tmp_kh, req->keyHandleLen, req->appId) == 0) { if (credential_verify(tmp_kh, req->keyHandleLen, req->appId) == 0) {
ret = fido_load_key(FIDO2_CURVE_P256, req->keyHandle, &key); ret = fido_load_key(FIDO2_CURVE_P256, req->keyHandle, &key);
@@ -68,23 +71,33 @@ int cmd_authenticate() {
resp->ctr[3] = ctr & 0xff; resp->ctr[3] = ctr & 0xff;
uint8_t hash[32], sig_base[CTAP_APPID_SIZE + 1 + 4 + CTAP_CHAL_SIZE]; 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, req->appId, CTAP_APPID_SIZE);
memcpy(sig_base+CTAP_APPID_SIZE, &resp->flags, sizeof(uint8_t)); memcpy(sig_base + CTAP_APPID_SIZE, &resp->flags, sizeof(uint8_t));
memcpy(sig_base + CTAP_APPID_SIZE + 1, resp->ctr, 4); memcpy(sig_base + CTAP_APPID_SIZE + 1, resp->ctr, 4);
memcpy(sig_base + CTAP_APPID_SIZE + 1 + 4, req->chal, CTAP_CHAL_SIZE); memcpy(sig_base + CTAP_APPID_SIZE + 1 + 4, req->chal, CTAP_CHAL_SIZE);
ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sig_base, sizeof(sig_base), hash); ret =
mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sig_base, sizeof(sig_base), hash);
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t olen = 0; 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_gen,
NULL);
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
if (ret != 0) if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
}
res_APDU_size = 1 + 4 + olen; res_APDU_size = 1 + 4 + olen;
ctr++; ctr++;
flash_write_data_to_file(ef_counter, (uint8_t *)&ctr, sizeof(ctr)); flash_write_data_to_file(ef_counter, (uint8_t *) &ctr, sizeof(ctr));
low_flash_available(); low_flash_available();
return SW_OK(); return SW_OK();
} }

View File

@@ -23,26 +23,31 @@
#include "files.h" #include "files.h"
#include "hid/ctap_hid.h" #include "hid/ctap_hid.h"
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"; const uint8_t *bogus_firefox =
const uint8_t *bogus_chrome = (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; (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";
const uint8_t *bogus_chrome = (const uint8_t *) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
extern int ctap_error(uint8_t error); extern int ctap_error(uint8_t error);
int cmd_register() { int cmd_register() {
CTAP_REGISTER_REQ *req = (CTAP_REGISTER_REQ *)apdu.data; CTAP_REGISTER_REQ *req = (CTAP_REGISTER_REQ *) apdu.data;
CTAP_REGISTER_RESP *resp = (CTAP_REGISTER_RESP *)res_APDU; CTAP_REGISTER_RESP *resp = (CTAP_REGISTER_RESP *) res_APDU;
resp->registerId = CTAP_REGISTER_ID; resp->registerId = CTAP_REGISTER_ID;
resp->keyHandleLen = KEY_HANDLE_LEN; resp->keyHandleLen = KEY_HANDLE_LEN;
//if (scan_files(true) != CCID_OK) //if (scan_files(true) != CCID_OK)
// return SW_EXEC_ERROR(); // return SW_EXEC_ERROR();
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() == true) {
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
if (memcmp(req->appId, bogus_firefox, CTAP_APPID_SIZE) == 0 || memcmp(req->appId, bogus_chrome, CTAP_APPID_SIZE) == 0) }
if (memcmp(req->appId, bogus_firefox,
CTAP_APPID_SIZE) == 0 || memcmp(req->appId, bogus_chrome, CTAP_APPID_SIZE) == 0)
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
return ctap_error(CTAP1_ERR_CHANNEL_BUSY); { return ctap_error(CTAP1_ERR_CHANNEL_BUSY); }
#else #else
return SW_DATA_INVALID(); { return SW_DATA_INVALID(); }
#endif #endif
mbedtls_ecdsa_context key; mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
@@ -52,32 +57,56 @@ int cmd_register() {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t olen = 0; size_t olen = 0;
ret = mbedtls_ecp_point_write_binary(&key.grp, &key.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, (uint8_t *)&resp->pubKey, CTAP_EC_POINT_SIZE); ret =
mbedtls_ecp_point_write_binary(&key.grp,
&key.Q,
MBEDTLS_ECP_PF_UNCOMPRESSED,
&olen,
(uint8_t *) &resp->pubKey,
CTAP_EC_POINT_SIZE);
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
if (ret != 0) { if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t ef_certdev_size = file_get_size(ef_certdev); size_t ef_certdev_size = file_get_size(ef_certdev);
memcpy(resp->keyHandleCertSig + KEY_HANDLE_LEN, file_get_data(ef_certdev), ef_certdev_size); memcpy(resp->keyHandleCertSig + KEY_HANDLE_LEN, file_get_data(ef_certdev), ef_certdev_size);
uint8_t hash[32], sign_base[1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN + CTAP_EC_POINT_SIZE]; uint8_t hash[32],
sign_base[1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN + CTAP_EC_POINT_SIZE];
sign_base[0] = CTAP_REGISTER_HASH_ID; sign_base[0] = CTAP_REGISTER_HASH_ID;
memcpy(sign_base + 1, req->appId, CTAP_APPID_SIZE); memcpy(sign_base + 1, req->appId, CTAP_APPID_SIZE);
memcpy(sign_base + 1 + CTAP_APPID_SIZE, req->chal, CTAP_CHAL_SIZE); memcpy(sign_base + 1 + CTAP_APPID_SIZE, req->chal, CTAP_CHAL_SIZE);
memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE, resp->keyHandleCertSig, KEY_HANDLE_LEN); memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE, resp->keyHandleCertSig,
memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN, (uint8_t *)&resp->pubKey, CTAP_EC_POINT_SIZE); KEY_HANDLE_LEN);
ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sign_base, sizeof(sign_base), hash); memcpy(sign_base + 1 + CTAP_APPID_SIZE + CTAP_CHAL_SIZE + KEY_HANDLE_LEN,
if (ret != 0) (uint8_t *) &resp->pubKey,
CTAP_EC_POINT_SIZE);
ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
sign_base,
sizeof(sign_base),
hash);
if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
}
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, file_get_data(ef_keydev), 32); ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, file_get_data(ef_keydev), 32);
if (ret != CCID_OK) { if (ret != CCID_OK) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return SW_EXEC_ERROR(); 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_gen,
NULL);
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
if (ret != 0) if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
res_APDU_size = sizeof(CTAP_REGISTER_RESP) - sizeof(resp->keyHandleCertSig) + KEY_HANDLE_LEN + ef_certdev_size + olen; }
res_APDU_size = sizeof(CTAP_REGISTER_RESP) - sizeof(resp->keyHandleCertSig) + KEY_HANDLE_LEN +
ef_certdev_size + olen;
return SW_OK(); return SW_OK();
} }

View File

@@ -31,25 +31,44 @@
int credential_derive_chacha_key(uint8_t *outk); int credential_derive_chacha_key(uint8_t *outk);
int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) { int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) {
if (cred_id_len < 4+12+16) if (cred_id_len < 4 + 12 + 16) {
return -1; return -1;
uint8_t key[32], *iv = cred_id + 4, *cipher = cred_id + 4 + 12, *tag = cred_id + cred_id_len - 16; }
uint8_t key[32], *iv = cred_id + 4, *cipher = cred_id + 4 + 12,
*tag = cred_id + cred_id_len - 16;
memset(key, 0, sizeof(key)); memset(key, 0, sizeof(key));
credential_derive_chacha_key(key); credential_derive_chacha_key(key);
mbedtls_chachapoly_context chatx; mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key); mbedtls_chachapoly_setkey(&chatx, key);
int ret = mbedtls_chachapoly_auth_decrypt(&chatx, cred_id_len - (4 + 12 + 16), iv, rp_id_hash, 32, tag, cipher, cipher); int ret = mbedtls_chachapoly_auth_decrypt(&chatx,
cred_id_len - (4 + 12 + 16),
iv,
rp_id_hash,
32,
tag,
cipher,
cipher);
mbedtls_chachapoly_free(&chatx); mbedtls_chachapoly_free(&chatx);
return ret; return ret;
} }
int credential_create(CborCharString *rpId, CborByteString *userId, CborCharString *userName, CborCharString *userDisplayName, CredOptions *opts, CredExtensions *extensions, bool use_sign_count, int alg, int curve, uint8_t *cred_id, size_t *cred_id_len) { int credential_create(CborCharString *rpId,
CborByteString *userId,
CborCharString *userName,
CborCharString *userDisplayName,
CredOptions *opts,
CredExtensions *extensions,
bool use_sign_count,
int alg,
int curve,
uint8_t *cred_id,
size_t *cred_id_len) {
CborEncoder encoder, mapEncoder, mapEncoder2; CborEncoder encoder, mapEncoder, mapEncoder2;
CborError error = CborNoError; CborError error = CborNoError;
uint8_t rp_id_hash[32]; uint8_t rp_id_hash[32];
mbedtls_sha256((uint8_t *)rpId->data, rpId->len, rp_id_hash, 0); mbedtls_sha256((uint8_t *) rpId->data, rpId->len, rp_id_hash, 0);
cbor_encoder_init(&encoder, cred_id+4+12, MAX_CRED_ID_LENGTH-(4+12+16), 0); cbor_encoder_init(&encoder, cred_id + 4 + 12, MAX_CRED_ID_LENGTH - (4 + 12 + 16), 0);
CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, CborIndefiniteLength)); CBOR_CHECK(cbor_encoder_create_map(&encoder, &mapEncoder, CborIndefiniteLength));
CBOR_APPEND_KEY_UINT_VAL_STRING(mapEncoder, 0x01, *rpId); CBOR_APPEND_KEY_UINT_VAL_STRING(mapEncoder, 0x01, *rpId);
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x02));
@@ -61,9 +80,11 @@ int credential_create(CborCharString *rpId, CborByteString *userId, CborCharStri
if (extensions->present == true) { if (extensions->present == true) {
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x07)); CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x07));
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, CborIndefiniteLength)); CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2, CborIndefiniteLength));
if (extensions->credBlob.present == true && extensions->credBlob.len < MAX_CREDBLOB_LENGTH) { if (extensions->credBlob.present == true &&
extensions->credBlob.len < MAX_CREDBLOB_LENGTH) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "credBlob")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "credBlob"));
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, extensions->credBlob.data, extensions->credBlob.len)); CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, extensions->credBlob.data,
extensions->credBlob.len));
} }
if (extensions->credProtect != 0) { if (extensions->credProtect != 0) {
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "credProtect")); CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "credProtect"));
@@ -105,7 +126,14 @@ int credential_create(CborCharString *rpId, CborByteString *userId, CborCharStri
mbedtls_chachapoly_context chatx; mbedtls_chachapoly_context chatx;
mbedtls_chachapoly_init(&chatx); mbedtls_chachapoly_init(&chatx);
mbedtls_chachapoly_setkey(&chatx, key); mbedtls_chachapoly_setkey(&chatx, key);
int ret = mbedtls_chachapoly_encrypt_and_tag(&chatx, rs, iv, rp_id_hash, 32, cred_id + 4 + 12, cred_id + 4 + 12, cred_id + 4 + 12 + rs); int ret = mbedtls_chachapoly_encrypt_and_tag(&chatx,
rs,
iv,
rp_id_hash,
32,
cred_id + 4 + 12,
cred_id + 4 + 12,
cred_id + 4 + 12 + rs);
mbedtls_chachapoly_free(&chatx); mbedtls_chachapoly_free(&chatx);
if (ret != 0) { if (ret != 0) {
CBOR_ERROR(CTAP1_ERR_OTHER); CBOR_ERROR(CTAP1_ERR_OTHER);
@@ -113,24 +141,29 @@ int credential_create(CborCharString *rpId, CborByteString *userId, CborCharStri
memcpy(cred_id, CRED_PROTO, 4); memcpy(cred_id, CRED_PROTO, 4);
memcpy(cred_id + 4, iv, 12); memcpy(cred_id + 4, iv, 12);
err: err:
if (error != CborNoError) { if (error != CborNoError) {
if (error == CborErrorImproperValue) if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
return error; return error;
} }
return 0; return 0;
} }
int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, Credential *cred) { int credential_load(const uint8_t *cred_id,
size_t cred_id_len,
const uint8_t *rp_id_hash,
Credential *cred) {
int ret = 0; int ret = 0;
CborError error = CborNoError; CborError error = CborNoError;
uint8_t *copy_cred_id = (uint8_t *)calloc(1, cred_id_len); uint8_t *copy_cred_id = (uint8_t *) calloc(1, cred_id_len);
memcpy(copy_cred_id, cred_id, cred_id_len); memcpy(copy_cred_id, cred_id, cred_id_len);
ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash); ret = credential_verify(copy_cred_id, cred_id_len, rp_id_hash);
if (ret != 0) { // U2F? if (ret != 0) { // U2F?
if (cred_id_len != KEY_HANDLE_LEN || verify_key(rp_id_hash, cred_id, NULL) != 0) if (cred_id_len != KEY_HANDLE_LEN || verify_key(rp_id_hash, cred_id, NULL) != 0) {
CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL); CBOR_ERROR(CTAP2_ERR_INVALID_CREDENTIAL);
}
} }
else { else {
CborParser parser; CborParser parser;
@@ -138,8 +171,10 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r
memset(cred, 0, sizeof(Credential)); memset(cred, 0, sizeof(Credential));
cred->curve = FIDO2_CURVE_P256; cred->curve = FIDO2_CURVE_P256;
cred->alg = FIDO2_ALG_ES256; cred->alg = FIDO2_ALG_ES256;
CBOR_CHECK(cbor_parser_init(copy_cred_id + 4 + 12, cred_id_len - (4 + 12 + 16), 0, &parser, &map)); CBOR_CHECK(cbor_parser_init(copy_cred_id + 4 + 12, cred_id_len - (4 + 12 + 16), 0, &parser,
CBOR_PARSE_MAP_START(map, 1) { &map));
CBOR_PARSE_MAP_START(map, 1)
{
uint64_t val_u = 0; uint64_t val_u = 0;
CBOR_FIELD_GET_UINT(val_u, 1); CBOR_FIELD_GET_UINT(val_u, 1);
if (val_u == 0x01) { if (val_u == 0x01) {
@@ -195,15 +230,16 @@ int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *r
} }
} }
cred->id.present = true; cred->id.present = true;
cred->id.data = (uint8_t *)calloc(1, cred_id_len); cred->id.data = (uint8_t *) calloc(1, cred_id_len);
memcpy(cred->id.data, cred_id, cred_id_len); memcpy(cred->id.data, cred_id, cred_id_len);
cred->id.len = cred_id_len; cred->id.len = cred_id_len;
cred->present = true; cred->present = true;
err: err:
free(copy_cred_id); free(copy_cred_id);
if (error != CborNoError) { if (error != CborNoError) {
if (error == CborErrorImproperValue) if (error == CborErrorImproperValue) {
return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
}
return error; return error;
} }
return 0; return 0;
@@ -222,7 +258,7 @@ void credential_free(Credential *cred) {
int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) { int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash) {
int sloti = -1; int sloti = -1;
Credential cred = {0}; Credential cred = { 0 };
int ret = 0; int ret = 0;
bool new_record = true; bool new_record = true;
ret = credential_load(cred_id, cred_id_len, rp_id_hash, &cred); ret = credential_load(cred_id, cred_id_len, rp_id_hash, &cred);
@@ -232,20 +268,23 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
} }
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
file_t *ef = search_dynamic_file(EF_CRED + i); file_t *ef = search_dynamic_file(EF_CRED + i);
Credential rcred = {0}; Credential rcred = { 0 };
if (!file_has_data(ef)) { if (!file_has_data(ef)) {
if (sloti == -1) if (sloti == -1) {
sloti = i; sloti = i;
}
continue; continue;
} }
if (memcmp(file_get_data(ef), rp_id_hash, 32) != 0) if (memcmp(file_get_data(ef), rp_id_hash, 32) != 0) {
continue; continue;
ret = credential_load(file_get_data(ef) + 32, file_get_size(ef)-32, rp_id_hash, &rcred); }
ret = credential_load(file_get_data(ef) + 32, file_get_size(ef) - 32, rp_id_hash, &rcred);
if (ret != 0) { if (ret != 0) {
credential_free(&rcred); credential_free(&rcred);
continue; continue;
} }
if (memcmp(rcred.userId.data, cred.userId.data, MIN(rcred.userId.len, cred.userId.len)) == 0) { if (memcmp(rcred.userId.data, cred.userId.data,
MIN(rcred.userId.len, cred.userId.len)) == 0) {
sloti = i; sloti = i;
credential_free(&rcred); credential_free(&rcred);
new_record = false; new_record = false;
@@ -253,12 +292,13 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
} }
credential_free(&rcred); credential_free(&rcred);
} }
if (sloti == -1) if (sloti == -1) {
return -1; return -1;
uint8_t *data = (uint8_t *)calloc(1, cred_id_len+32); }
uint8_t *data = (uint8_t *) calloc(1, cred_id_len + 32);
memcpy(data, rp_id_hash, 32); memcpy(data, rp_id_hash, 32);
memcpy(data + 32, cred_id, cred_id_len); memcpy(data + 32, cred_id, cred_id_len);
file_t *ef = file_new(EF_CRED+sloti); file_t *ef = file_new(EF_CRED + sloti);
flash_write_data_to_file(ef, data, cred_id_len + 32); flash_write_data_to_file(ef, data, cred_id_len + 32);
free(data); free(data);
@@ -267,30 +307,32 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) { for (int i = 0; i < MAX_RESIDENT_CREDENTIALS; i++) {
ef = search_dynamic_file(EF_RP + i); ef = search_dynamic_file(EF_RP + i);
if (!file_has_data(ef)) { if (!file_has_data(ef)) {
if (sloti == -1) if (sloti == -1) {
sloti = i; sloti = i;
}
continue; continue;
} }
if (memcmp(file_get_data(ef)+1, rp_id_hash, 32) == 0) { if (memcmp(file_get_data(ef) + 1, rp_id_hash, 32) == 0) {
sloti = i; sloti = i;
break; break;
} }
} }
if (sloti == -1) if (sloti == -1) {
return -1; return -1;
}
ef = search_dynamic_file(EF_RP + sloti); ef = search_dynamic_file(EF_RP + sloti);
if (file_has_data(ef)) { if (file_has_data(ef)) {
data = (uint8_t *)calloc(1, file_get_size(ef)); data = (uint8_t *) calloc(1, file_get_size(ef));
memcpy(data, file_get_data(ef), file_get_size(ef)); memcpy(data, file_get_data(ef), file_get_size(ef));
data[0] += 1; data[0] += 1;
flash_write_data_to_file(ef, data, file_get_size(ef)); flash_write_data_to_file(ef, data, file_get_size(ef));
free(data); free(data);
} }
else { else {
ef = file_new(EF_RP+sloti); ef = file_new(EF_RP + sloti);
data = (uint8_t *)calloc(1, 1 + 32 + cred.rpId.len); data = (uint8_t *) calloc(1, 1 + 32 + cred.rpId.len);
data[0] = 1; data[0] = 1;
memcpy(data+1, rp_id_hash, 32); memcpy(data + 1, rp_id_hash, 32);
memcpy(data + 1 + 32, cred.rpId.data, cred.rpId.len); memcpy(data + 1 + 32, cred.rpId.data, cred.rpId.len);
flash_write_data_to_file(ef, data, 1 + 32 + cred.rpId.len); flash_write_data_to_file(ef, data, 1 + 32 + cred.rpId.len);
free(data); free(data);
@@ -304,13 +346,14 @@ int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *
int credential_derive_hmac_key(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk) { int credential_derive_hmac_key(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk) {
memset(outk, 0, 64); memset(outk, 0, 64);
int r = 0; int r = 0;
if ((r = load_keydev(outk)) != 0) if ((r = load_keydev(outk)) != 0) {
return r; return r;
}
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *)"SLIP-0022", 9, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *)CRED_PROTO, 4, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) CRED_PROTO, 4, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *)"hmac-secret", 11, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "hmac-secret", 11, outk);
mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk); mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk);
return 0; return 0;
} }
@@ -318,26 +361,28 @@ int credential_derive_hmac_key(const uint8_t *cred_id, size_t cred_id_len, uint8
int credential_derive_chacha_key(uint8_t *outk) { int credential_derive_chacha_key(uint8_t *outk) {
memset(outk, 0, 32); memset(outk, 0, 32);
int r = 0; int r = 0;
if ((r = load_keydev(outk)) != 0) if ((r = load_keydev(outk)) != 0) {
return r; return r;
}
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *)"SLIP-0022", 9, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *)CRED_PROTO, 4, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) CRED_PROTO, 4, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *)"Encryption key", 14, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "Encryption key", 14, outk);
return 0; return 0;
} }
int credential_derive_large_blob_key(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk) { int credential_derive_large_blob_key(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk) {
memset(outk, 0, 32); memset(outk, 0, 32);
int r = 0; int r = 0;
if ((r = load_keydev(outk)) != 0) if ((r = load_keydev(outk)) != 0) {
return r; return r;
}
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *)"SLIP-0022", 9, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "SLIP-0022", 9, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *)CRED_PROTO, 4, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) CRED_PROTO, 4, outk);
mbedtls_md_hmac(md_info, outk, 32, (uint8_t *)"largeBlobKey", 12, outk); mbedtls_md_hmac(md_info, outk, 32, (uint8_t *) "largeBlobKey", 12, outk);
mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk); mbedtls_md_hmac(md_info, outk, 32, cred_id, cred_id_len, outk);
return 0; return 0;
} }

View File

@@ -36,8 +36,7 @@ typedef struct CredExtensions {
bool present; bool present;
} CredExtensions; } CredExtensions;
typedef struct Credential typedef struct Credential {
{
CborCharString rpId; CborCharString rpId;
CborByteString userId; CborByteString userId;
CborCharString userName; CborCharString userName;
@@ -59,11 +58,26 @@ typedef struct Credential
#define CRED_PROTO "\xf1\xd0\x02\x01" #define CRED_PROTO "\xf1\xd0\x02\x01"
extern int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash); extern int credential_verify(uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash);
extern int credential_create(CborCharString *rpId, CborByteString *userId, CborCharString *userName, CborCharString *userDisplayName, CredOptions *opts, CredExtensions *extensions, bool use_sign_count, int alg, int curve, uint8_t *cred_id, size_t *cred_id_len); extern int credential_create(CborCharString *rpId,
CborByteString *userId,
CborCharString *userName,
CborCharString *userDisplayName,
CredOptions *opts,
CredExtensions *extensions,
bool use_sign_count,
int alg,
int curve,
uint8_t *cred_id,
size_t *cred_id_len);
extern void credential_free(Credential *cred); extern void credential_free(Credential *cred);
extern int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash); extern int credential_store(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash);
extern int credential_load(const uint8_t *cred_id, size_t cred_id_len, const uint8_t *rp_id_hash, Credential *cred); extern int credential_load(const uint8_t *cred_id,
size_t cred_id_len,
const uint8_t *rp_id_hash,
Credential *cred);
extern int credential_derive_hmac_key(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk); extern int credential_derive_hmac_key(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk);
extern int credential_derive_large_blob_key(const uint8_t *cred_id, size_t cred_id_len, uint8_t *outk); extern int credential_derive_large_blob_key(const uint8_t *cred_id,
size_t cred_id_len,
uint8_t *outk);
#endif // _CREDENTIAL_H_ #endif // _CREDENTIAL_H_

View File

@@ -46,9 +46,9 @@ extern const bool _btrue, _bfalse;
if (x) \ if (x) \
{ \ { \
free(x); \ free(x); \
x = NULL;\ x = NULL; \
} \ } \
} while(0) } while (0)
#define CBOR_ERROR(e) \ #define CBOR_ERROR(e) \
do \ do \
@@ -56,7 +56,7 @@ extern const bool _btrue, _bfalse;
error = e; \ error = e; \
printf("Cbor ERROR [%s:%d]: %d\n", __FILE__, __LINE__, e); \ printf("Cbor ERROR [%s:%d]: %d\n", __FILE__, __LINE__, e); \
goto err; \ goto err; \
} while(0) } while (0)
#define CBOR_ASSERT(c) \ #define CBOR_ASSERT(c) \
do \ do \
@@ -67,7 +67,7 @@ extern const bool _btrue, _bfalse;
printf("Cbor ASSERT [%s:%d]: %s\n", __FILE__, __LINE__, #c); \ printf("Cbor ASSERT [%s:%d]: %s\n", __FILE__, __LINE__, #c); \
goto err; \ goto err; \
} \ } \
} while(0) } while (0)
#define PINUVAUTHTOKEN_MC 0x1 #define PINUVAUTHTOKEN_MC 0x1
#define PINUVAUTHTOKEN_GA 0x2 #define PINUVAUTHTOKEN_GA 0x2
@@ -94,20 +94,20 @@ typedef struct CborCharString {
do \ do \
{ \ { \
if ((v).nofree != true) \ if ((v).nofree != true) \
CBOR_FREE((v).data); \ CBOR_FREE((v).data); \
else \ else \
(v).data = NULL; \ (v).data = NULL; \
(v).len = 0; \ (v).len = 0; \
(v).present = false; \ (v).present = false; \
} while(0) } while (0)
#define CBOR_PARSE_MAP_START(_p,_n) \ #define CBOR_PARSE_MAP_START(_p, _n) \
CBOR_ASSERT(cbor_value_is_map(&(_p)) == true); \ CBOR_ASSERT(cbor_value_is_map(&(_p)) == true); \
CborValue _f##_n; \ CborValue _f##_n; \
CBOR_CHECK(cbor_value_enter_container(&(_p), &(_f##_n))); \ CBOR_CHECK(cbor_value_enter_container(&(_p), &(_f##_n))); \
while (cbor_value_at_end(&(_f##_n)) == false) while (cbor_value_at_end(&(_f##_n)) == false)
#define CBOR_PARSE_ARRAY_START(_p,_n) \ #define CBOR_PARSE_ARRAY_START(_p, _n) \
CBOR_ASSERT(cbor_value_is_array(&(_p)) == true); \ CBOR_ASSERT(cbor_value_is_array(&(_p)) == true); \
CborValue _f##_n; \ CborValue _f##_n; \
CBOR_CHECK(cbor_value_enter_container(&(_p), &(_f##_n))); \ CBOR_CHECK(cbor_value_enter_container(&(_p), &(_f##_n))); \
@@ -118,14 +118,14 @@ typedef struct CborCharString {
CBOR_ASSERT(cbor_value_is_unsigned_integer(&(_f##_n)) == true); \ CBOR_ASSERT(cbor_value_is_unsigned_integer(&(_f##_n)) == true); \
CBOR_CHECK(cbor_value_get_uint64(&(_f##_n), &(v))); \ CBOR_CHECK(cbor_value_get_uint64(&(_f##_n), &(v))); \
CBOR_CHECK(cbor_value_advance_fixed(&(_f##_n))); \ CBOR_CHECK(cbor_value_advance_fixed(&(_f##_n))); \
} while(0) } while (0)
#define CBOR_FIELD_GET_INT(v, _n) \ #define CBOR_FIELD_GET_INT(v, _n) \
do { \ do { \
CBOR_ASSERT(cbor_value_is_integer(&(_f##_n)) == true); \ CBOR_ASSERT(cbor_value_is_integer(&(_f##_n)) == true); \
CBOR_CHECK(cbor_value_get_int64(&(_f##_n), &(v))); \ CBOR_CHECK(cbor_value_get_int64(&(_f##_n), &(v))); \
CBOR_CHECK(cbor_value_advance_fixed(&(_f##_n))); \ CBOR_CHECK(cbor_value_advance_fixed(&(_f##_n))); \
} while(0) } while (0)
#define CBOR_FIELD_GET_BYTES(v, _n) \ #define CBOR_FIELD_GET_BYTES(v, _n) \
do { \ do { \
@@ -148,7 +148,7 @@ typedef struct CborCharString {
CBOR_CHECK(cbor_value_get_boolean(&(_f##_n), &val)); \ CBOR_CHECK(cbor_value_get_boolean(&(_f##_n), &val)); \
v = (val == true ? ptrue : pfalse); \ v = (val == true ? ptrue : pfalse); \
CBOR_CHECK(cbor_value_advance_fixed(&(_f##_n))); \ CBOR_CHECK(cbor_value_advance_fixed(&(_f##_n))); \
} while(0) } while (0)
#define CBOR_FIELD_GET_KEY_TEXT(_n) \ #define CBOR_FIELD_GET_KEY_TEXT(_n) \
CBOR_ASSERT(cbor_value_is_text_string(&(_f##_n)) == true); \ CBOR_ASSERT(cbor_value_is_text_string(&(_f##_n)) == true); \
@@ -174,26 +174,26 @@ typedef struct CborCharString {
#define CBOR_FIELD_KEY_TEXT_VAL_INT(_n, _t, _v) \ #define CBOR_FIELD_KEY_TEXT_VAL_INT(_n, _t, _v) \
if (strcmp(_fd##_n, _t) == 0) { \ if (strcmp(_fd##_n, _t) == 0) { \
CBOR_FIELD_GET_INT(_v, _n);\ CBOR_FIELD_GET_INT(_v, _n); \
continue; \ continue; \
} }
#define CBOR_FIELD_KEY_TEXT_VAL_UINT(_n, _t, _v) \ #define CBOR_FIELD_KEY_TEXT_VAL_UINT(_n, _t, _v) \
if (strcmp(_fd##_n, _t) == 0) { \ if (strcmp(_fd##_n, _t) == 0) { \
CBOR_FIELD_GET_UINT(_v, _n);\ CBOR_FIELD_GET_UINT(_v, _n); \
continue; \ continue; \
} }
#define CBOR_FIELD_KEY_TEXT_VAL_BOOL(_n, _t, _v) \ #define CBOR_FIELD_KEY_TEXT_VAL_BOOL(_n, _t, _v) \
if (strcmp(_fd##_n, _t) == 0) { \ if (strcmp(_fd##_n, _t) == 0) { \
CBOR_FIELD_GET_BOOL(_v, _n);\ CBOR_FIELD_GET_BOOL(_v, _n); \
continue; \ continue; \
} }
#define CBOR_PARSE_MAP_END(_p,_n) \ #define CBOR_PARSE_MAP_END(_p, _n) \
CBOR_CHECK(cbor_value_leave_container(&(_p), &(_f##_n))) CBOR_CHECK(cbor_value_leave_container(&(_p), &(_f##_n)))
#define CBOR_PARSE_ARRAY_END(_p,_n) CBOR_PARSE_MAP_END(_p, _n) #define CBOR_PARSE_ARRAY_END(_p, _n) CBOR_PARSE_MAP_END(_p, _n)
#define CBOR_ADVANCE(_n) CBOR_CHECK(cbor_value_advance(&_f##_n)); #define CBOR_ADVANCE(_n) CBOR_CHECK(cbor_value_advance(&_f##_n));
@@ -202,39 +202,39 @@ typedef struct CborCharString {
if ((v).data && (v).len > 0) { \ if ((v).data && (v).len > 0) { \
CBOR_CHECK(cbor_encode_uint(&(p), (k))); \ CBOR_CHECK(cbor_encode_uint(&(p), (k))); \
CBOR_CHECK(cbor_encode_byte_string(&(p), (v).data, (v).len)); \ CBOR_CHECK(cbor_encode_byte_string(&(p), (v).data, (v).len)); \
} } while(0) } } while (0)
#define CBOR_APPEND_KEY_UINT_VAL_STRING(p, k, v) \ #define CBOR_APPEND_KEY_UINT_VAL_STRING(p, k, v) \
do { \ do { \
if ((v).data && (v).len > 0) { \ if ((v).data && (v).len > 0) { \
CBOR_CHECK(cbor_encode_uint(&(p), (k))); \ CBOR_CHECK(cbor_encode_uint(&(p), (k))); \
CBOR_CHECK(cbor_encode_text_stringz(&(p), (v).data)); \ CBOR_CHECK(cbor_encode_text_stringz(&(p), (v).data)); \
} } while(0) } } while (0)
#define CBOR_APPEND_KEY_UINT_VAL_UINT(p, k, v) \ #define CBOR_APPEND_KEY_UINT_VAL_UINT(p, k, v) \
do { \ do { \
CBOR_CHECK(cbor_encode_uint(&(p), (k))); \ CBOR_CHECK(cbor_encode_uint(&(p), (k))); \
CBOR_CHECK(cbor_encode_uint(&(p), (v))); \ CBOR_CHECK(cbor_encode_uint(&(p), (v))); \
} while(0) } while (0)
#define CBOR_APPEND_KEY_UINT_VAL_INT(p, k, v) \ #define CBOR_APPEND_KEY_UINT_VAL_INT(p, k, v) \
do { \ do { \
CBOR_CHECK(cbor_encode_int(&(p), (k))); \ CBOR_CHECK(cbor_encode_int(&(p), (k))); \
CBOR_CHECK(cbor_encode_int(&(p), (v))); \ CBOR_CHECK(cbor_encode_int(&(p), (v))); \
} while(0) } while (0)
#define CBOR_APPEND_KEY_UINT_VAL_BOOL(p, k, v) \ #define CBOR_APPEND_KEY_UINT_VAL_BOOL(p, k, v) \
do { \ do { \
CBOR_CHECK(cbor_encode_uint(&(p), (k))); \ CBOR_CHECK(cbor_encode_uint(&(p), (k))); \
CBOR_CHECK(cbor_encode_boolean(&(p), (v))); \ CBOR_CHECK(cbor_encode_boolean(&(p), (v))); \
} while(0) } while (0)
#define CBOR_APPEND_KEY_UINT_VAL_PBOOL(p, k, v) \ #define CBOR_APPEND_KEY_UINT_VAL_PBOOL(p, k, v) \
do { \ do { \
if (v != NULL) {\ if (v != NULL) { \
CBOR_CHECK(cbor_encode_uint(&(p), (k))); \ CBOR_CHECK(cbor_encode_uint(&(p), (k))); \
CBOR_CHECK(cbor_encode_boolean(&(p), v == ptrue ? true : false)); \ CBOR_CHECK(cbor_encode_boolean(&(p), v == ptrue ? true : false)); \
} } while(0) } } while (0)
#endif //_CTAP2_CBOR_H_ #endif //_CTAP2_CBOR_H_

View File

@@ -35,7 +35,7 @@
int fido_process_apdu(); int fido_process_apdu();
int fido_unload(); int fido_unload();
pinUvAuthToken_t paut = {0}; pinUvAuthToken_t paut = { 0 };
uint8_t keydev_dec[32]; uint8_t keydev_dec[32];
bool has_keydev_dec = false; bool has_keydev_dec = false;
@@ -47,11 +47,12 @@ const uint8_t fido_aid[] = {
const uint8_t atr_fido[] = { const uint8_t atr_fido[] = {
23, 23,
0x3b, 0xfd, 0x13, 0x00, 0x00, 0x81, 0x31, 0xfe, 0x15, 0x80, 0x73, 0xc0, 0x21, 0xc0, 0x57, 0x59, 0x75, 0x62, 0x69, 0x4b, 0x65, 0x79, 0x40 0x3b, 0xfd, 0x13, 0x00, 0x00, 0x81, 0x31, 0xfe, 0x15, 0x80, 0x73, 0xc0, 0x21, 0xc0, 0x57, 0x59,
0x75, 0x62, 0x69, 0x4b, 0x65, 0x79, 0x40
}; };
app_t *fido_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { app_t *fido_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
if (!memcmp(aid, fido_aid+1, MIN(aid_len,fido_aid[0]))) { if (!memcmp(aid, fido_aid + 1, MIN(aid_len, fido_aid[0]))) {
a->aid = fido_aid; a->aid = fido_aid;
a->process_apdu = fido_process_apdu; a->process_apdu = fido_process_apdu;
a->unload = fido_unload; a->unload = fido_unload;
@@ -60,7 +61,7 @@ app_t *fido_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
return NULL; return NULL;
} }
void __attribute__ ((constructor)) fido_ctor() { void __attribute__((constructor)) fido_ctor() {
#if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION) #if defined(USB_ITF_CCID) || defined(ENABLE_EMULATION)
ccid_atr = atr_fido; ccid_atr = atr_fido;
#endif #endif
@@ -72,30 +73,38 @@ int fido_unload() {
} }
mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) { mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve) {
if (curve == FIDO2_CURVE_P256) if (curve == FIDO2_CURVE_P256) {
return MBEDTLS_ECP_DP_SECP256R1; return MBEDTLS_ECP_DP_SECP256R1;
else if (curve == FIDO2_CURVE_P384) }
else if (curve == FIDO2_CURVE_P384) {
return MBEDTLS_ECP_DP_SECP384R1; return MBEDTLS_ECP_DP_SECP384R1;
else if (curve == FIDO2_CURVE_P521) }
else if (curve == FIDO2_CURVE_P521) {
return MBEDTLS_ECP_DP_SECP521R1; return MBEDTLS_ECP_DP_SECP521R1;
else if (curve == FIDO2_CURVE_P256K1) }
else if (curve == FIDO2_CURVE_P256K1) {
return MBEDTLS_ECP_DP_SECP256K1; return MBEDTLS_ECP_DP_SECP256K1;
else if (curve == FIDO2_CURVE_X25519) }
else if (curve == FIDO2_CURVE_X25519) {
return MBEDTLS_ECP_DP_CURVE25519; return MBEDTLS_ECP_DP_CURVE25519;
else if (curve == FIDO2_CURVE_X448) }
else if (curve == FIDO2_CURVE_X448) {
return MBEDTLS_ECP_DP_CURVE448; return MBEDTLS_ECP_DP_CURVE448;
}
return MBEDTLS_ECP_DP_NONE; return MBEDTLS_ECP_DP_NONE;
} }
int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key) { int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key) {
mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve); mbedtls_ecp_group_id mbedtls_curve = fido_curve_to_mbedtls(curve);
if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) if (mbedtls_curve == MBEDTLS_ECP_DP_NONE) {
return CTAP2_ERR_UNSUPPORTED_ALGORITHM; return CTAP2_ERR_UNSUPPORTED_ALGORITHM;
}
uint8_t key_path[KEY_PATH_LEN]; uint8_t key_path[KEY_PATH_LEN];
memcpy(key_path, cred_id, KEY_PATH_LEN); memcpy(key_path, cred_id, KEY_PATH_LEN);
*(uint32_t *)key_path = 0x80000000 | 10022; *(uint32_t *) key_path = 0x80000000 | 10022;
for (int i = 1; i < KEY_PATH_ENTRIES; i++) for (int i = 1; i < KEY_PATH_ENTRIES; i++) {
*(uint32_t *)(key_path+i*sizeof(uint32_t)) |= 0x80000000; *(uint32_t *) (key_path + i * sizeof(uint32_t)) |= 0x80000000;
}
return derive_key(NULL, false, key_path, mbedtls_curve, key); return derive_key(NULL, false, key_path, mbedtls_curve, key);
} }
@@ -103,7 +112,7 @@ int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffe
mbedtls_x509write_cert ctx; mbedtls_x509write_cert ctx;
mbedtls_x509write_crt_init(&ctx); mbedtls_x509write_crt_init(&ctx);
mbedtls_x509write_crt_set_version(&ctx, MBEDTLS_X509_CRT_VERSION_3); mbedtls_x509write_crt_set_version(&ctx, MBEDTLS_X509_CRT_VERSION_3);
mbedtls_x509write_crt_set_validity(&ctx, "20220901000000", "20320831235959" ); mbedtls_x509write_crt_set_validity(&ctx, "20220901000000", "20320831235959");
mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO"); 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"); mbedtls_x509write_crt_set_subject_name(&ctx, "C=ES,O=Pico HSM,CN=Pico FIDO");
mbedtls_mpi serial; mbedtls_mpi serial;
@@ -120,7 +129,9 @@ int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffe
mbedtls_x509write_crt_set_basic_constraints(&ctx, 0, 0); mbedtls_x509write_crt_set_basic_constraints(&ctx, 0, 0);
mbedtls_x509write_crt_set_subject_key_identifier(&ctx); mbedtls_x509write_crt_set_subject_key_identifier(&ctx);
mbedtls_x509write_crt_set_authority_key_identifier(&ctx); mbedtls_x509write_crt_set_authority_key_identifier(&ctx);
mbedtls_x509write_crt_set_key_usage(&ctx, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN); 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_gen, NULL);
/* pk cannot be freed, as it is freed later */ /* pk cannot be freed, as it is freed later */
//mbedtls_pk_free(&key); //mbedtls_pk_free(&key);
@@ -128,19 +139,22 @@ int x509_create_cert(mbedtls_ecdsa_context *ecdsa, uint8_t *buffer, size_t buffe
} }
int load_keydev(uint8_t *key) { int load_keydev(uint8_t *key) {
if (has_keydev_dec == false && !file_has_data(ef_keydev)) if (has_keydev_dec == false && !file_has_data(ef_keydev)) {
return CCID_ERR_MEMORY_FATAL; return CCID_ERR_MEMORY_FATAL;
if (has_keydev_dec == true) }
if (has_keydev_dec == true) {
memcpy(key, keydev_dec, sizeof(keydev_dec)); memcpy(key, keydev_dec, sizeof(keydev_dec));
else }
else {
memcpy(key, file_get_data(ef_keydev), file_get_size(ef_keydev)); memcpy(key, file_get_data(ef_keydev), file_get_size(ef_keydev));
}
//return mkek_decrypt(key, file_get_size(ef_keydev)); //return mkek_decrypt(key, file_get_size(ef_keydev));
return CCID_OK; return CCID_OK;
} }
int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *key) { int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *key) {
for (int i = 0; i < KEY_PATH_ENTRIES; i++) { for (int i = 0; i < KEY_PATH_ENTRIES; i++) {
uint32_t k = *(uint32_t *)&keyHandle[i*sizeof(uint32_t)]; uint32_t k = *(uint32_t *) &keyHandle[i * sizeof(uint32_t)];
if (!(k & 0x80000000)) { if (!(k & 0x80000000)) {
return -1; return -1;
} }
@@ -149,40 +163,61 @@ int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_con
if (key == NULL) { if (key == NULL) {
mbedtls_ecdsa_init(&ctx); mbedtls_ecdsa_init(&ctx);
key = &ctx; key = &ctx;
if (derive_key(appId, false, (uint8_t *)keyHandle, MBEDTLS_ECP_DP_SECP256R1, &ctx) != 0) { if (derive_key(appId, false, (uint8_t *) keyHandle, MBEDTLS_ECP_DP_SECP256R1, &ctx) != 0) {
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
return -3; return -3;
} }
} }
uint8_t hmac[32], d[32]; uint8_t hmac[32], d[32];
int ret = mbedtls_ecp_write_key(key, d, sizeof(d)); int ret = mbedtls_ecp_write_key(key, d, sizeof(d));
if (key == NULL) if (key == NULL) {
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
if (ret != 0) }
if (ret != 0) {
return -2; return -2;
}
uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN]; uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN];
memcpy(key_base, appId, CTAP_APPID_SIZE); memcpy(key_base, appId, CTAP_APPID_SIZE);
memcpy(key_base + CTAP_APPID_SIZE, keyHandle, KEY_PATH_LEN); memcpy(key_base + CTAP_APPID_SIZE, keyHandle, KEY_PATH_LEN);
ret = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), d, 32, key_base, sizeof(key_base), hmac); ret =
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
d,
32,
key_base,
sizeof(key_base),
hmac);
mbedtls_platform_zeroize(d, sizeof(d)); mbedtls_platform_zeroize(d, sizeof(d));
return memcmp(keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac)); return memcmp(keyHandle + KEY_PATH_LEN, hmac, sizeof(hmac));
} }
int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int curve, mbedtls_ecdsa_context *key) { int derive_key(const uint8_t *app_id,
uint8_t outk[64] = {0}; bool new_key,
uint8_t *key_handle,
int curve,
mbedtls_ecdsa_context *key) {
uint8_t outk[64] = { 0 };
int r = 0; int r = 0;
memset(outk, 0, sizeof(outk)); memset(outk, 0, sizeof(outk));
if ((r = load_keydev(outk)) != CCID_OK) if ((r = load_keydev(outk)) != CCID_OK) {
return r; return r;
}
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
for (int i = 0; i < KEY_PATH_ENTRIES; i++) { for (int i = 0; i < KEY_PATH_ENTRIES; i++) {
if (new_key == true) { if (new_key == true) {
uint32_t val = 0; uint32_t val = 0;
random_gen(NULL, (uint8_t *) &val, sizeof(val)); random_gen(NULL, (uint8_t *) &val, sizeof(val));
val |= 0x80000000; val |= 0x80000000;
memcpy(&key_handle[i*sizeof(uint32_t)], &val, sizeof(uint32_t)); memcpy(&key_handle[i * sizeof(uint32_t)], &val, sizeof(uint32_t));
} }
r = mbedtls_hkdf(md_info, &key_handle[i * sizeof(uint32_t)], sizeof(uint32_t), outk, 32, outk + 32, 32, outk, sizeof(outk)); r = mbedtls_hkdf(md_info,
&key_handle[i * sizeof(uint32_t)],
sizeof(uint32_t),
outk,
32,
outk + 32,
32,
outk,
sizeof(outk));
if (r != 0) { if (r != 0) {
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));
return r; return r;
@@ -192,8 +227,9 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN]; uint8_t key_base[CTAP_APPID_SIZE + KEY_PATH_LEN];
memcpy(key_base, app_id, CTAP_APPID_SIZE); memcpy(key_base, app_id, CTAP_APPID_SIZE);
memcpy(key_base + CTAP_APPID_SIZE, key_handle, KEY_PATH_LEN); memcpy(key_base + CTAP_APPID_SIZE, key_handle, KEY_PATH_LEN);
if ((r = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), outk, 32, key_base, sizeof(key_base), key_handle + 32)) != 0) if ((r =
{ mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), outk, 32, key_base,
sizeof(key_base), key_handle + 32)) != 0) {
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));
return r; return r;
} }
@@ -201,12 +237,14 @@ int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int cur
if (key != NULL) { if (key != NULL) {
mbedtls_ecp_group_load(&key->grp, curve); mbedtls_ecp_group_load(&key->grp, curve);
const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(curve); const mbedtls_ecp_curve_info *cinfo = mbedtls_ecp_curve_info_from_grp_id(curve);
if (cinfo == NULL) if (cinfo == NULL) {
return 1; return 1;
r = mbedtls_ecp_read_key(curve, key, outk, ceil((float)cinfo->bit_size/8)); }
r = mbedtls_ecp_read_key(curve, key, outk, ceil((float) cinfo->bit_size / 8));
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));
if (r != 0) if (r != 0) {
return r; return r;
}
return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL); return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, random_gen, NULL);
} }
mbedtls_platform_zeroize(outk, sizeof(outk)); mbedtls_platform_zeroize(outk, sizeof(outk));
@@ -248,7 +286,10 @@ int scan_files() {
uint8_t cert[4096]; uint8_t cert[4096];
mbedtls_ecdsa_context key; mbedtls_ecdsa_context key;
mbedtls_ecdsa_init(&key); mbedtls_ecdsa_init(&key);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1, &key, file_get_data(ef_keydev), file_get_size(ef_keydev)); int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256R1,
&key,
file_get_data(ef_keydev),
file_get_size(ef_keydev));
if (ret != 0) { if (ret != 0) {
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
return ret; return ret;
@@ -260,8 +301,9 @@ int scan_files() {
} }
ret = x509_create_cert(&key, cert, sizeof(cert)); ret = x509_create_cert(&key, cert, sizeof(cert));
mbedtls_ecdsa_free(&key); mbedtls_ecdsa_free(&key);
if (ret <= 0) if (ret <= 0) {
return ret; return ret;
}
flash_write_data_to_file(ef_certdev, cert + sizeof(cert) - ret, ret); flash_write_data_to_file(ef_certdev, cert + sizeof(cert) - ret, ret);
} }
} }
@@ -272,7 +314,7 @@ int scan_files() {
if (ef_counter) { if (ef_counter) {
if (!file_has_data(ef_counter)) { if (!file_has_data(ef_counter)) {
uint32_t v = 0; uint32_t v = 0;
flash_write_data_to_file(ef_counter, (uint8_t *)&v, sizeof(v)); flash_write_data_to_file(ef_counter, (uint8_t *) &v, sizeof(v));
} }
} }
else { else {
@@ -294,7 +336,9 @@ int scan_files() {
} }
ef_largeblob = search_by_fid(EF_LARGEBLOB, NULL, SPECIFY_EF); ef_largeblob = search_by_fid(EF_LARGEBLOB, NULL, SPECIFY_EF);
if (!file_has_data(ef_largeblob)) { if (!file_has_data(ef_largeblob)) {
flash_write_data_to_file(ef_largeblob, (const uint8_t *)"\x80\x76\xbe\x8b\x52\x8d\x00\x75\xf7\xaa\xe9\x8d\x6f\xa5\x7a\x6d\x3c", 17); flash_write_data_to_file(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(); low_flash_available();
return CCID_OK; return CCID_OK;
@@ -312,23 +356,25 @@ void init_fido() {
bool wait_button_pressed() { bool wait_button_pressed() {
uint32_t val = EV_PRESS_BUTTON; uint32_t val = EV_PRESS_BUTTON;
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
#if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON==1 #if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON == 1
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);
#endif #endif
#endif #endif
return (val == EV_BUTTON_TIMEOUT); return val == EV_BUTTON_TIMEOUT;
} }
uint32_t user_present_time_limit = 0; uint32_t user_present_time_limit = 0;
bool check_user_presence() { bool check_user_presence() {
#if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON==1 #if defined(ENABLE_UP_BUTTON) && ENABLE_UP_BUTTON == 1
if (user_present_time_limit == 0 || user_present_time_limit+TRANSPORT_TIME_LIMIT < board_millis()) { if (user_present_time_limit == 0 ||
if (wait_button_pressed() == true) //timeout user_present_time_limit + TRANSPORT_TIME_LIMIT < board_millis()) {
if (wait_button_pressed() == true) { //timeout
return false; return false;
}
//user_present_time_limit = board_millis(); //user_present_time_limit = board_millis();
} }
#endif #endif
@@ -342,8 +388,9 @@ uint32_t get_sign_counter() {
uint8_t get_opts() { uint8_t get_opts() {
file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF); file_t *ef = search_by_fid(EF_OPTS, NULL, SPECIFY_EF);
if (file_has_data(ef)) if (file_has_data(ef)) {
return *file_get_data(ef); return *file_get_data(ef);
}
return 0; return 0;
} }
@@ -361,14 +408,14 @@ static const cmd_t cmds[] = {
{ CTAP_REGISTER, cmd_register }, { CTAP_REGISTER, cmd_register },
{ CTAP_AUTHENTICATE, cmd_authenticate }, { CTAP_AUTHENTICATE, cmd_authenticate },
{ CTAP_VERSION, cmd_version }, { CTAP_VERSION, cmd_version },
{ 0x00, 0x0} { 0x00, 0x0 }
}; };
int fido_process_apdu() { int fido_process_apdu() {
if (CLA(apdu) != 0x00) if (CLA(apdu) != 0x00) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) }
{ for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
if (cmd->ins == INS(apdu)) { if (cmd->ins == INS(apdu)) {
int r = cmd->cmd_handler(); int r = cmd->cmd_handler();
return r; return r;

View File

@@ -36,15 +36,27 @@
#define KEY_HANDLE_LEN (KEY_PATH_LEN + SHA256_DIGEST_LENGTH) #define KEY_HANDLE_LEN (KEY_PATH_LEN + SHA256_DIGEST_LENGTH)
extern int scan_files(); extern int scan_files();
extern int derive_key(const uint8_t *app_id, bool new_key, uint8_t *key_handle, int, mbedtls_ecdsa_context *key); extern int derive_key(const uint8_t *app_id,
bool new_key,
uint8_t *key_handle,
int,
mbedtls_ecdsa_context *key);
extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *); extern int verify_key(const uint8_t *appId, const uint8_t *keyHandle, mbedtls_ecdsa_context *);
extern bool wait_button_pressed(); extern bool wait_button_pressed();
extern void init_fido(); extern void init_fido();
extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve); extern mbedtls_ecp_group_id fido_curve_to_mbedtls(int curve);
extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key); extern int fido_load_key(int curve, const uint8_t *cred_id, mbedtls_ecdsa_context *key);
extern int load_keydev(uint8_t *key); extern int load_keydev(uint8_t *key);
extern int encrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out); extern int encrypt(uint8_t protocol,
extern int decrypt(uint8_t protocol, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out); const uint8_t *key,
const uint8_t *in,
size_t in_len,
uint8_t *out);
extern int decrypt(uint8_t protocol,
const uint8_t *key,
const uint8_t *in,
size_t in_len,
uint8_t *out);
extern int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret); extern int ecdh(uint8_t protocol, const mbedtls_ecp_point *Q, uint8_t *sharedSecret);
#define FIDO2_ALG_ES256 -7 //ECDSA-SHA256 P256 #define FIDO2_ALG_ES256 -7 //ECDSA-SHA256 P256
@@ -96,7 +108,7 @@ typedef struct known_app {
extern const known_app_t *find_app_by_rp_id_hash(const uint8_t *rp_id_hash); extern const known_app_t *find_app_by_rp_id_hash(const uint8_t *rp_id_hash);
#define TRANSPORT_TIME_LIMIT (30*1000) //USB #define TRANSPORT_TIME_LIMIT (30 * 1000) //USB
bool check_user_presence(); bool check_user_presence();
@@ -114,6 +126,10 @@ typedef struct pinUvAuthToken {
extern uint32_t user_present_time_limit; extern uint32_t user_present_time_limit;
extern pinUvAuthToken_t paut; extern pinUvAuthToken_t paut;
extern int verify(uint8_t protocol, const uint8_t *key, const uint8_t *data, size_t len, uint8_t *sign); extern int verify(uint8_t protocol,
const uint8_t *key,
const uint8_t *data,
size_t len,
uint8_t *sign);
#endif //_FIDO_H #endif //_FIDO_H

View File

@@ -18,22 +18,40 @@
#include "files.h" #include "files.h"
file_t file_entries[] = { file_t file_entries[] = {
{.fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0}}, // MF { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL,
{.fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // Device Key .ef_structure = 0, .acl = { 0 } }, // MF
{.fid = EF_KEY_DEV_ENC, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // Device Key Enc { .fid = EF_KEY_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
{.fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // End Entity Certificate Device .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key
{.fid = EF_EE_DEV_EA, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // End Entity Enterprise Attestation Certificate { .fid = EF_KEY_DEV_ENC, .parent = 0, .name = NULL,
{.fid = EF_COUNTER, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // Global counter .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
{.fid = EF_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // PIN .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Device Key Enc
{.fid = EF_AUTHTOKEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // AUTH TOKEN { .fid = EF_EE_DEV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
{.fid = EF_MINPINLEN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // MIN PIN LENGTH .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Certificate Device
{.fid = EF_OPTS, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // Global options { .fid = EF_EE_DEV_EA, .parent = 0, .name = NULL,
{.fid = EF_LARGEBLOB, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}}, // Large Blob .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // End Entity Enterprise Attestation Certificate
{ .fid = EF_COUNTER, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global counter
{ .fid = EF_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // PIN
{ .fid = EF_AUTHTOKEN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // AUTH TOKEN
{ .fid = EF_MINPINLEN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // MIN PIN LENGTH
{ .fid = EF_OPTS, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Global options
{ .fid = EF_LARGEBLOB, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Large Blob
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL,
.ef_structure = 0, .acl = { 0 } } //end
}; };
const file_t *MF = &file_entries[0]; const file_t *MF = &file_entries[0];
const file_t *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1]; const file_t *file_last = &file_entries[sizeof(file_entries) / sizeof(file_t) - 1];
file_t *ef_keydev = NULL; file_t *ef_keydev = NULL;
file_t *ef_certdev = NULL; file_t *ef_certdev = NULL;
file_t *ef_counter = NULL; file_t *ef_counter = NULL;

View File

@@ -20,274 +20,354 @@
static const known_app_t kapps[] = { static const known_app_t kapps[] = {
{ {
.rp_id_hash = (const uint8_t *)"\x96\x89\x78\xa2\x99\x53\xde\x52\xd3\xef\x0f\x0c\x71\xb7\xb7\xb6\xb1\xaf\x9f\x08\xe2\x57\x89\x6a\x8d\x81\x26\x91\x85\x30\x29\x3b", .rp_id_hash =
(const uint8_t *)
"\x96\x89\x78\xa2\x99\x53\xde\x52\xd3\xef\x0f\x0c\x71\xb7\xb7\xb6\xb1\xaf\x9f\x08\xe2\x57\x89\x6a\x8d\x81\x26\x91\x85\x30\x29\x3b",
.label = "aws.amazon.com", .label = "aws.amazon.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xc3\x40\x8c\x04\x47\x88\xae\xa5\xb3\xdf\x30\x89\x52\xfd\x8c\xa3\xc7\x0e\x21\xfe\xf4\xf6\xc1\xc2\x37\x4c\xaa\x1d\xf9\xb2\x8d\xdd", .rp_id_hash =
(const uint8_t *)
"\xc3\x40\x8c\x04\x47\x88\xae\xa5\xb3\xdf\x30\x89\x52\xfd\x8c\xa3\xc7\x0e\x21\xfe\xf4\xf6\xc1\xc2\x37\x4c\xaa\x1d\xf9\xb2\x8d\xdd",
.label = "www.binance.com", .label = "www.binance.com",
.use_sign_count = pfalse, .use_sign_count = pfalse,
.use_self_attestation = ptrue, .use_self_attestation = ptrue,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x20\xf6\x61\xb1\x94\x0c\x34\x70\xac\x54\xfa\x2e\xb4\x99\x90\xfd\x33\xb5\x6d\xe8\xde\x60\x18\x70\xff\x02\xa8\x06\x0f\x3b\x7c\x58", .rp_id_hash =
(const uint8_t *)
"\x20\xf6\x61\xb1\x94\x0c\x34\x70\xac\x54\xfa\x2e\xb4\x99\x90\xfd\x33\xb5\x6d\xe8\xde\x60\x18\x70\xff\x02\xa8\x06\x0f\x3b\x7c\x58",
.label = "binance.com", .label = "binance.com",
.use_sign_count = pfalse, .use_sign_count = pfalse,
.use_self_attestation = ptrue, .use_self_attestation = ptrue,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x12\x74\x3b\x92\x12\x97\xb7\x7f\x11\x35\xe4\x1f\xde\xdd\x4a\x84\x6a\xfe\x82\xe1\xf3\x69\x32\xa9\x91\x2f\x3b\x0d\x8d\xfb\x7d\x0e", .rp_id_hash =
(const uint8_t *)
"\x12\x74\x3b\x92\x12\x97\xb7\x7f\x11\x35\xe4\x1f\xde\xdd\x4a\x84\x6a\xfe\x82\xe1\xf3\x69\x32\xa9\x91\x2f\x3b\x0d\x8d\xfb\x7d\x0e",
//U2F key for Bitbucket //U2F key for Bitbucket
.label = "bitbucket.org", .label = "bitbucket.org",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x30\x2f\xd5\xb4\x49\x2a\x07\xb9\xfe\xbb\x30\xe7\x32\x69\xec\xa5\x01\x20\x5c\xcf\xe0\xc2\x0b\xf7\xb4\x72\xfa\x2d\x31\xe2\x1e\x63", .rp_id_hash =
(const uint8_t *)
"\x30\x2f\xd5\xb4\x49\x2a\x07\xb9\xfe\xbb\x30\xe7\x32\x69\xec\xa5\x01\x20\x5c\xcf\xe0\xc2\x0b\xf7\xb4\x72\xfa\x2d\x31\xe2\x1e\x63",
//U2F key for Bitfinex //U2F key for Bitfinex
.label = "www.bitfinex.com", .label = "www.bitfinex.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xa3\x4d\x30\x9f\xfa\x28\xc1\x24\x14\xb8\xba\x6c\x07\xee\x1e\xfa\xe1\xa8\x5e\x8a\x04\x61\x48\x59\xa6\x7c\x04\x93\xb6\x95\x61\x90", .rp_id_hash =
(const uint8_t *)
"\xa3\x4d\x30\x9f\xfa\x28\xc1\x24\x14\xb8\xba\x6c\x07\xee\x1e\xfa\xe1\xa8\x5e\x8a\x04\x61\x48\x59\xa6\x7c\x04\x93\xb6\x95\x61\x90",
//U2F key for Bitwarden //U2F key for Bitwarden
.label = "vault.bitwarden.com", .label = "vault.bitwarden.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x19\x81\x5c\xb9\xa5\xfb\x25\xd8\x05\xde\xbd\x7b\x32\x53\x7e\xd5\x78\x63\x9b\x3e\xd1\x08\xec\x7c\x5b\xb9\xe8\xf0\xdf\xb1\x68\x73", .rp_id_hash =
(const uint8_t *)
"\x19\x81\x5c\xb9\xa5\xfb\x25\xd8\x05\xde\xbd\x7b\x32\x53\x7e\xd5\x78\x63\x9b\x3e\xd1\x08\xec\x7c\x5b\xb9\xe8\xf0\xdf\xb1\x68\x73",
//WebAuthn key for Cloudflare //WebAuthn key for Cloudflare
.label = "dash.cloudflare.com", .label = "dash.cloudflare.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xe2\x7d\x61\xb4\xe9\x9d\xe0\xed\x98\x16\x3c\xb3\x8b\x7a\xf9\x33\xc6\x66\x5e\x55\x09\xe8\x49\x08\x37\x05\x58\x13\x77\x8e\x23\x6a", .rp_id_hash =
(const uint8_t *)
"\xe2\x7d\x61\xb4\xe9\x9d\xe0\xed\x98\x16\x3c\xb3\x8b\x7a\xf9\x33\xc6\x66\x5e\x55\x09\xe8\x49\x08\x37\x05\x58\x13\x77\x8e\x23\x6a",
//WebAuthn key for Coinbase //WebAuthn key for Coinbase
.label = "coinbase.com", .label = "coinbase.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x68\x20\x19\x15\xd7\x4c\xb4\x2a\xf5\xb3\xcc\x5c\x95\xb9\x55\x3e\x3e\x3a\x83\xb4\xd2\xa9\x3b\x45\xfb\xad\xaa\x84\x69\xff\x8e\x6e", .rp_id_hash =
(const uint8_t *)
"\x68\x20\x19\x15\xd7\x4c\xb4\x2a\xf5\xb3\xcc\x5c\x95\xb9\x55\x3e\x3e\x3a\x83\xb4\xd2\xa9\x3b\x45\xfb\xad\xaa\x84\x69\xff\x8e\x6e",
//U2F key for Dashlane //U2F key for Dashlane
.label = "www.dashlane.com", .label = "www.dashlane.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xc5\x0f\x8a\x7b\x70\x8e\x92\xf8\x2e\x7a\x50\xe2\xbd\xc5\x5d\x8f\xd9\x1a\x22\xfe\x6b\x29\xc0\xcd\xf7\x80\x55\x30\x84\x2a\xf5\x81", .rp_id_hash =
(const uint8_t *)
"\xc5\x0f\x8a\x7b\x70\x8e\x92\xf8\x2e\x7a\x50\xe2\xbd\xc5\x5d\x8f\xd9\x1a\x22\xfe\x6b\x29\xc0\xcd\xf7\x80\x55\x30\x84\x2a\xf5\x81",
//U2F key for Dropbox //U2F key for Dropbox
.label = "www.dropbox.com", .label = "www.dropbox.com",
.use_sign_count = pfalse, .use_sign_count = pfalse,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x82\xf4\xa8\xc9\x5f\xec\x94\xb2\x6b\xaf\x9e\x37\x25\x0e\x95\x63\xd9\xa3\x66\xc7\xbe\x26\x1c\xa4\xdd\x01\x01\xf4\xd5\xef\xcb\x83", .rp_id_hash =
(const uint8_t *)
"\x82\xf4\xa8\xc9\x5f\xec\x94\xb2\x6b\xaf\x9e\x37\x25\x0e\x95\x63\xd9\xa3\x66\xc7\xbe\x26\x1c\xa4\xdd\x01\x01\xf4\xd5\xef\xcb\x83",
//WebAuthn key for Dropbox //WebAuthn key for Dropbox
.label = "www.dropbox.com", .label = "www.dropbox.com",
.use_sign_count = pfalse, .use_sign_count = pfalse,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xf3\xe2\x04\x2f\x94\x60\x7d\xa0\xa9\xc1\xf3\xb9\x5e\x0d\x2f\x2b\xb2\xe0\x69\xc5\xbb\x4f\xa7\x64\xaf\xfa\x64\x7d\x84\x7b\x7e\xd6", .rp_id_hash =
(const uint8_t *)
"\xf3\xe2\x04\x2f\x94\x60\x7d\xa0\xa9\xc1\xf3\xb9\x5e\x0d\x2f\x2b\xb2\xe0\x69\xc5\xbb\x4f\xa7\x64\xaf\xfa\x64\x7d\x84\x7b\x7e\xd6",
//U2F key for Duo //U2F key for Duo
.label = "duosecurity.com", .label = "duosecurity.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x31\x19\x33\x28\xf8\xe2\x1d\xfb\x6c\x99\xf3\x22\xd2\x2d\x7b\x0b\x50\x87\x78\xe6\x4f\xfb\xba\x86\xe5\x22\x93\x37\x90\x31\xb8\x74", .rp_id_hash =
(const uint8_t *)
"\x31\x19\x33\x28\xf8\xe2\x1d\xfb\x6c\x99\xf3\x22\xd2\x2d\x7b\x0b\x50\x87\x78\xe6\x4f\xfb\xba\x86\xe5\x22\x93\x37\x90\x31\xb8\x74",
//WebAuthn key for Facebook //WebAuthn key for Facebook
.label = "facebook.com", .label = "facebook.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x69\x66\xab\xe3\x67\x4e\xa2\xf5\x30\x79\xeb\x71\x01\x97\x84\x8c\x9b\xe6\xf3\x63\x99\x2f\xd0\x29\xe9\x89\x84\x47\xcb\x9f\x00\x84", .rp_id_hash =
(const uint8_t *)
"\x69\x66\xab\xe3\x67\x4e\xa2\xf5\x30\x79\xeb\x71\x01\x97\x84\x8c\x9b\xe6\xf3\x63\x99\x2f\xd0\x29\xe9\x89\x84\x47\xcb\x9f\x00\x84",
//U2F key for FastMail //U2F key for FastMail
.label = "www.fastmail.com", .label = "www.fastmail.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x3f\xcb\x82\x82\xb8\x46\x76\xeb\xee\x71\x40\xe3\x9e\xca\xe1\x6e\xeb\x19\x90\x64\xc7\xc7\xe4\x43\x2e\x28\xc9\xb5\x7e\x4b\x60\x39", .rp_id_hash =
(const uint8_t *)
"\x3f\xcb\x82\x82\xb8\x46\x76\xeb\xee\x71\x40\xe3\x9e\xca\xe1\x6e\xeb\x19\x90\x64\xc7\xc7\xe4\x43\x2e\x28\xc9\xb5\x7e\x4b\x60\x39",
.label = "fastmail.com", .label = "fastmail.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x9d\x61\x44\x2f\x5c\xe1\x33\xbd\x46\x54\x4f\xc4\x2f\x0a\x6d\x54\xc0\xde\xb8\x88\x40\xca\xc2\xb6\xae\xfa\x65\x14\xf8\x93\x49\xe9", .rp_id_hash =
(const uint8_t *)
"\x9d\x61\x44\x2f\x5c\xe1\x33\xbd\x46\x54\x4f\xc4\x2f\x0a\x6d\x54\xc0\xde\xb8\x88\x40\xca\xc2\xb6\xae\xfa\x65\x14\xf8\x93\x49\xe9",
.label = "fedoraproject.org", .label = "fedoraproject.org",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xa4\xe2\x2d\xca\xfe\xa7\xe9\x0e\x12\x89\x50\x11\x39\x89\xfc\x45\x97\x8d\xc9\xfb\x87\x76\x75\x60\x51\x6c\x1c\x69\xdf\xdf\xd1\x96", .rp_id_hash =
(const uint8_t *)
"\xa4\xe2\x2d\xca\xfe\xa7\xe9\x0e\x12\x89\x50\x11\x39\x89\xfc\x45\x97\x8d\xc9\xfb\x87\x76\x75\x60\x51\x6c\x1c\x69\xdf\xdf\xd1\x96",
.label = "gandi.net", .label = "gandi.net",
.use_sign_count = pfalse, .use_sign_count = pfalse,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x54\xce\x65\x1e\xd7\x15\xb4\xaa\xa7\x55\xee\xce\xbd\x4e\xa0\x95\x08\x15\xb3\x34\xbd\x07\xd1\x09\x89\x3e\x96\x30\x18\xcd\xdb\xd9", .rp_id_hash =
(const uint8_t *)
"\x54\xce\x65\x1e\xd7\x15\xb4\xaa\xa7\x55\xee\xce\xbd\x4e\xa0\x95\x08\x15\xb3\x34\xbd\x07\xd1\x09\x89\x3e\x96\x30\x18\xcd\xdb\xd9",
//WebAuthn key for Gandi //WebAuthn key for Gandi
.label = "gandi.net", .label = "gandi.net",
.use_sign_count = pfalse, .use_sign_count = pfalse,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x86\x06\xc1\x68\xe5\x1f\xc1\x31\xe5\x46\xad\x57\xa1\x9f\x32\x97\xb1\x1e\x0e\x5c\xe8\x3e\x8e\x89\x31\xb2\x85\x08\x11\xcf\xa8\x81", .rp_id_hash =
(const uint8_t *)
"\x86\x06\xc1\x68\xe5\x1f\xc1\x31\xe5\x46\xad\x57\xa1\x9f\x32\x97\xb1\x1e\x0e\x5c\xe8\x3e\x8e\x89\x31\xb2\x85\x08\x11\xcf\xa8\x81",
//WebAuthn key for Gemini //WebAuthn key for Gemini
.label = "gemini.com", .label = "gemini.com",
.use_sign_count = pfalse, .use_sign_count = pfalse,
.use_self_attestation = ptrue, .use_self_attestation = ptrue,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x70\x61\x7d\xfe\xd0\x65\x86\x3a\xf4\x7c\x15\x55\x6c\x91\x79\x88\x80\x82\x8c\xc4\x07\xfd\xf7\x0a\xe8\x50\x11\x56\x94\x65\xa0\x75", .rp_id_hash =
(const uint8_t *)
"\x70\x61\x7d\xfe\xd0\x65\x86\x3a\xf4\x7c\x15\x55\x6c\x91\x79\x88\x80\x82\x8c\xc4\x07\xfd\xf7\x0a\xe8\x50\x11\x56\x94\x65\xa0\x75",
//U2F key for GitHub //U2F key for GitHub
.label = "github.com", .label = "github.com",
.use_sign_count = ptrue, .use_sign_count = ptrue,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x3a\xeb\x00\x24\x60\x38\x1c\x6f\x25\x8e\x83\x95\xd3\x02\x6f\x57\x1f\x0d\x9a\x76\x48\x8d\xcd\x83\x76\x39\xb1\x3a\xed\x31\x65\x60", .rp_id_hash =
(const uint8_t *)
"\x3a\xeb\x00\x24\x60\x38\x1c\x6f\x25\x8e\x83\x95\xd3\x02\x6f\x57\x1f\x0d\x9a\x76\x48\x8d\xcd\x83\x76\x39\xb1\x3a\xed\x31\x65\x60",
//WebAuthn key for GitHub //WebAuthn key for GitHub
.label = "github.com", .label = "github.com",
.use_sign_count = ptrue, .use_sign_count = ptrue,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xe7\xbe\x96\xa5\x1b\xd0\x19\x2a\x72\x84\x0d\x2e\x59\x09\xf7\x2b\xa8\x2a\x2f\xe9\x3f\xaa\x62\x4f\x03\x39\x6b\x30\xe4\x94\xc8\x04", .rp_id_hash =
(const uint8_t *)
"\xe7\xbe\x96\xa5\x1b\xd0\x19\x2a\x72\x84\x0d\x2e\x59\x09\xf7\x2b\xa8\x2a\x2f\xe9\x3f\xaa\x62\x4f\x03\x39\x6b\x30\xe4\x94\xc8\x04",
//U2F key for GitLab //U2F key for GitLab
.label = "gitlab.com", .label = "gitlab.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xa5\x46\x72\xb2\x22\xc4\xcf\x95\xe1\x51\xed\x8d\x4d\x3c\x76\x7a\x6c\xc3\x49\x43\x59\x43\x79\x4e\x88\x4f\x3d\x02\x3a\x82\x29\xfd", .rp_id_hash =
(const uint8_t *)
"\xa5\x46\x72\xb2\x22\xc4\xcf\x95\xe1\x51\xed\x8d\x4d\x3c\x76\x7a\x6c\xc3\x49\x43\x59\x43\x79\x4e\x88\x4f\x3d\x02\x3a\x82\x29\xfd",
//U2F key for Google //U2F key for Google
.label = "google.com", .label = "google.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xd4\xc9\xd9\x02\x73\x26\x27\x1a\x89\xce\x51\xfc\xaf\x32\x8e\xd6\x73\xf1\x7b\xe3\x34\x69\xff\x97\x9e\x8a\xb8\xdd\x50\x1e\x66\x4f", .rp_id_hash =
(const uint8_t *)
"\xd4\xc9\xd9\x02\x73\x26\x27\x1a\x89\xce\x51\xfc\xaf\x32\x8e\xd6\x73\xf1\x7b\xe3\x34\x69\xff\x97\x9e\x8a\xb8\xdd\x50\x1e\x66\x4f",
//WebAuthn key for Google //WebAuthn key for Google
.label = "google.com", .label = "google.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x53\xa1\x5b\xa4\x2a\x7c\x03\x25\xb8\xdb\xee\x28\x96\x34\xa4\x8f\x58\xae\xa3\x24\x66\x45\xd5\xff\x41\x8f\x9b\xb8\x81\x98\x85\xa9", .rp_id_hash =
(const uint8_t *)
"\x53\xa1\x5b\xa4\x2a\x7c\x03\x25\xb8\xdb\xee\x28\x96\x34\xa4\x8f\x58\xae\xa3\x24\x66\x45\xd5\xff\x41\x8f\x9b\xb8\x81\x98\x85\xa9",
//U2F key for Keeper //U2F key for Keeper
.label = "keepersecurity.com", .label = "keepersecurity.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xd6\x5f\x00\x5e\xf4\xde\xa9\x32\x0c\x99\x73\x05\x3c\x95\xff\x60\x20\x11\x5d\x5f\xec\x1b\x7f\xee\x41\xa5\x78\xe1\x8d\xf9\xca\x8c", .rp_id_hash =
(const uint8_t *)
"\xd6\x5f\x00\x5e\xf4\xde\xa9\x32\x0c\x99\x73\x05\x3c\x95\xff\x60\x20\x11\x5d\x5f\xec\x1b\x7f\xee\x41\xa5\x78\xe1\x8d\xf9\xca\x8c",
//U2F key for Keeper //U2F key for Keeper
.label = "keepersecurity.eu", .label = "keepersecurity.eu",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x3f\x37\x50\x85\x33\x2c\xac\x4f\xad\xf9\xe5\xdd\x28\xcd\x54\x69\x8f\xab\x98\x4b\x75\xd9\xc3\x6a\x07\x2c\xb1\x60\x77\x3f\x91\x52", .rp_id_hash =
(const uint8_t *)
"\x3f\x37\x50\x85\x33\x2c\xac\x4f\xad\xf9\xe5\xdd\x28\xcd\x54\x69\x8f\xab\x98\x4b\x75\xd9\xc3\x6a\x07\x2c\xb1\x60\x77\x3f\x91\x52",
//WebAuthn key for Kraken //WebAuthn key for Kraken
.label = "kraken.com", .label = "kraken.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xf8\x3f\xc3\xa1\xb2\x89\xa0\xde\xc5\xc1\xc8\xaa\x07\xe9\xb5\xdd\x9c\xbb\x76\xf6\xb2\xf5\x60\x60\x17\x66\x72\x68\xe5\xb9\xc4\x5e", .rp_id_hash =
(const uint8_t *)
"\xf8\x3f\xc3\xa1\xb2\x89\xa0\xde\xc5\xc1\xc8\xaa\x07\xe9\xb5\xdd\x9c\xbb\x76\xf6\xb2\xf5\x60\x60\x17\x66\x72\x68\xe5\xb9\xc4\x5e",
//WebAuthn key for login.gov //WebAuthn key for login.gov
.label = "secure.login.gov", .label = "secure.login.gov",
.use_sign_count = pfalse, .use_sign_count = pfalse,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x35\x6c\x9e\xd4\xa0\x93\x21\xb9\x69\x5f\x1e\xaf\x91\x82\x03\xf1\xb5\x5f\x68\x9d\xa6\x1f\xbc\x96\x18\x4c\x15\x7d\xda\x68\x0c\x81", .rp_id_hash =
(const uint8_t *)
"\x35\x6c\x9e\xd4\xa0\x93\x21\xb9\x69\x5f\x1e\xaf\x91\x82\x03\xf1\xb5\x5f\x68\x9d\xa6\x1f\xbc\x96\x18\x4c\x15\x7d\xda\x68\x0c\x81",
//WebAuthn key for Microsoft //WebAuthn key for Microsoft
.label = "login.microsoft.com", .label = "login.microsoft.com",
.use_sign_count = pfalse, .use_sign_count = pfalse,
.use_self_attestation = pfalse, .use_self_attestation = pfalse,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xab\x2d\xaf\x07\x43\xde\x78\x2a\x70\x18\x9a\x0f\x5e\xfc\x30\x90\x2f\x92\x5b\x9f\x9a\x18\xc5\xd7\x14\x1b\x7b\x12\xf8\xa0\x10\x0c", .rp_id_hash =
(const uint8_t *)
"\xab\x2d\xaf\x07\x43\xde\x78\x2a\x70\x18\x9a\x0f\x5e\xfc\x30\x90\x2f\x92\x5b\x9f\x9a\x18\xc5\xd7\x14\x1b\x7b\x12\xf8\xa0\x10\x0c",
//WebAuthn key for mojeID //WebAuthn key for mojeID
.label = "mojeid.cz", .label = "mojeid.cz",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x85\x71\x01\x36\x1b\x20\xa9\x54\x4c\xdb\x9b\xef\x65\x85\x8b\x6b\xac\x70\x13\x55\x0d\x8f\x84\xf7\xef\xee\x25\x2b\x96\xfa\x7c\x1e", .rp_id_hash =
(const uint8_t *)
"\x85\x71\x01\x36\x1b\x20\xa9\x54\x4c\xdb\x9b\xef\x65\x85\x8b\x6b\xac\x70\x13\x55\x0d\x8f\x84\xf7\xef\xee\x25\x2b\x96\xfa\x7c\x1e",
//WebAuthn key for Namecheap //WebAuthn key for Namecheap
.label = "www.namecheap.com", .label = "www.namecheap.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x08\xb2\xa3\xd4\x19\x39\xaa\x31\x66\x84\x93\xcb\x36\xcd\xcc\x4f\x16\xc4\xd9\xb4\xc8\x23\x8b\x73\xc2\xf6\x72\xc0\x33\x00\x71\x97", .rp_id_hash =
(const uint8_t *)
"\x08\xb2\xa3\xd4\x19\x39\xaa\x31\x66\x84\x93\xcb\x36\xcd\xcc\x4f\x16\xc4\xd9\xb4\xc8\x23\x8b\x73\xc2\xf6\x72\xc0\x33\x00\x71\x97",
//U2F key for Slush Pool //U2F key for Slush Pool
.label = "slushpool.com", .label = "slushpool.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x38\x80\x4f\x2e\xff\x74\xf2\x28\xb7\x41\x51\xc2\x01\xaa\x82\xe7\xe8\xee\xfc\xac\xfe\xcf\x23\xfa\x14\x6b\x13\xa3\x76\x66\x31\x4f", .rp_id_hash =
(const uint8_t *)
"\x38\x80\x4f\x2e\xff\x74\xf2\x28\xb7\x41\x51\xc2\x01\xaa\x82\xe7\xe8\xee\xfc\xac\xfe\xcf\x23\xfa\x14\x6b\x13\xa3\x76\x66\x31\x4f",
//U2F key for Slush Pool //U2F key for Slush Pool
.label = "slushpool.com", .label = "slushpool.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x2a\xc6\xad\x09\xa6\xd0\x77\x2c\x44\xda\x73\xa6\x07\x2f\x9d\x24\x0f\xc6\x85\x4a\x70\xd7\x9c\x10\x24\xff\x7c\x75\x59\x59\x32\x92", .rp_id_hash =
(const uint8_t *)
"\x2a\xc6\xad\x09\xa6\xd0\x77\x2c\x44\xda\x73\xa6\x07\x2f\x9d\x24\x0f\xc6\x85\x4a\x70\xd7\x9c\x10\x24\xff\x7c\x75\x59\x59\x32\x92",
//U2F key for Stripe //U2F key for Stripe
.label = "stripe.com", .label = "stripe.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xfa\xbe\xec\xe3\x98\x2f\xad\x9d\xdc\xc9\x8f\x91\xbd\x2e\x75\xaf\xc7\xd1\xf4\xca\x54\x49\x29\xb2\xd0\xd0\x42\x12\xdf\xfa\x30\xfa", .rp_id_hash =
(const uint8_t *)
"\xfa\xbe\xec\xe3\x98\x2f\xad\x9d\xdc\xc9\x8f\x91\xbd\x2e\x75\xaf\xc7\xd1\xf4\xca\x54\x49\x29\xb2\xd0\xd0\x42\x12\xdf\xfa\x30\xfa",
//U2F key for Tutanota //U2F key for Tutanota
.label = "tutanota.com", .label = "tutanota.com",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x1b\x3c\x16\xdd\x2f\x7c\x46\xe2\xb4\xc2\x89\xdc\x16\x74\x6b\xcc\x60\xdf\xcf\x0f\xb8\x18\xe1\x32\x15\x52\x6e\x14\x08\xe7\xf4\x68", .rp_id_hash =
(const uint8_t *)
"\x1b\x3c\x16\xdd\x2f\x7c\x46\xe2\xb4\xc2\x89\xdc\x16\x74\x6b\xcc\x60\xdf\xcf\x0f\xb8\x18\xe1\x32\x15\x52\x6e\x14\x08\xe7\xf4\x68",
//U2F key for u2f.bin.coffee //U2F key for u2f.bin.coffee
.label = "u2f.bin.coffee", .label = "u2f.bin.coffee",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xa6\x42\xd2\x1b\x7c\x6d\x55\xe1\xce\x23\xc5\x39\x98\x28\xd2\xc7\x49\xbf\x6a\x6e\xf2\xfe\x03\xcc\x9e\x10\xcd\xf4\xed\x53\x08\x8b", .rp_id_hash =
(const uint8_t *)
"\xa6\x42\xd2\x1b\x7c\x6d\x55\xe1\xce\x23\xc5\x39\x98\x28\xd2\xc7\x49\xbf\x6a\x6e\xf2\xfe\x03\xcc\x9e\x10\xcd\xf4\xed\x53\x08\x8b",
//WebAuthn key for webauthn.bin.coffee //WebAuthn key for webauthn.bin.coffee
.label = "webauthn.bin.coffee", .label = "webauthn.bin.coffee",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\x74\xa6\xea\x92\x13\xc9\x9c\x2f\x74\xb2\x24\x92\xb3\x20\xcf\x40\x26\x2a\x94\xc1\xa9\x50\xa0\x39\x7f\x29\x25\x0b\x60\x84\x1e\xf0", .rp_id_hash =
(const uint8_t *)
"\x74\xa6\xea\x92\x13\xc9\x9c\x2f\x74\xb2\x24\x92\xb3\x20\xcf\x40\x26\x2a\x94\xc1\xa9\x50\xa0\x39\x7f\x29\x25\x0b\x60\x84\x1e\xf0",
//WebAuthn key for WebAuthn.io //WebAuthn key for WebAuthn.io
.label = "webauthn.io", .label = "webauthn.io",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xf9\x5b\xc7\x38\x28\xee\x21\x0f\x9f\xd3\xbb\xe7\x2d\x97\x90\x80\x13\xb0\xa3\x75\x9e\x9a\xea\x3d\x0a\xe3\x18\x76\x6c\xd2\xe1\xad", .rp_id_hash =
(const uint8_t *)
"\xf9\x5b\xc7\x38\x28\xee\x21\x0f\x9f\xd3\xbb\xe7\x2d\x97\x90\x80\x13\xb0\xa3\x75\x9e\x9a\xea\x3d\x0a\xe3\x18\x76\x6c\xd2\xe1\xad",
//WebAuthn key for WebAuthn.me //WebAuthn key for WebAuthn.me
.label = "webauthn.me", .label = "webauthn.me",
.use_sign_count = NULL, .use_sign_count = NULL,
.use_self_attestation = NULL, .use_self_attestation = NULL,
}, },
{ {
.rp_id_hash = (const uint8_t *)"\xc4\x6c\xef\x82\xad\x1b\x54\x64\x77\x59\x1d\x00\x8b\x08\x75\x9e\xc3\xe6\xd2\xec\xb4\xf3\x94\x74\xbf\xea\x69\x69\x92\x5d\x03\xb7", .rp_id_hash =
(const uint8_t *)
"\xc4\x6c\xef\x82\xad\x1b\x54\x64\x77\x59\x1d\x00\x8b\x08\x75\x9e\xc3\xe6\xd2\xec\xb4\xf3\x94\x74\xbf\xea\x69\x69\x92\x5d\x03\xb7",
//WebAuthn key for demo.yubico.com //WebAuthn key for demo.yubico.com
.label = "demo.yubico.com", .label = "demo.yubico.com",
.use_sign_count = NULL, .use_sign_count = NULL,
@@ -303,8 +383,9 @@ static const known_app_t kapps[] = {
const known_app_t *find_app_by_rp_id_hash(const uint8_t *rp_id_hash) { const known_app_t *find_app_by_rp_id_hash(const uint8_t *rp_id_hash) {
for (const known_app_t *ka = &kapps[0]; ka->rp_id_hash != NULL; ka++) { for (const known_app_t *ka = &kapps[0]; ka->rp_id_hash != NULL; ka++) {
if (memcmp(rp_id_hash, ka->rp_id_hash, 32) == 0) if (memcmp(rp_id_hash, ka->rp_id_hash, 32) == 0) {
return ka; return ka;
}
} }
return NULL; return NULL;
} }

View File

@@ -55,7 +55,7 @@ int oath_process_apdu();
int oath_unload(); int oath_unload();
static bool validated = true; static bool validated = true;
static uint8_t challenge[CHALLENGE_LEN] = {0}; static uint8_t challenge[CHALLENGE_LEN] = { 0 };
const uint8_t oath_aid[] = { const uint8_t oath_aid[] = {
7, 7,
@@ -63,7 +63,7 @@ const uint8_t oath_aid[] = {
}; };
app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
if (!memcmp(aid, oath_aid+1, MIN(aid_len,oath_aid[0]))) { if (!memcmp(aid, oath_aid + 1, MIN(aid_len, oath_aid[0]))) {
a->aid = oath_aid; a->aid = oath_aid;
a->process_apdu = oath_process_apdu; a->process_apdu = oath_process_apdu;
a->unload = oath_unload; a->unload = oath_unload;
@@ -76,14 +76,16 @@ app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
res_APDU[res_APDU_size++] = TAG_NAME; res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = 8; res_APDU[res_APDU_size++] = 8;
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
pico_get_unique_board_id((pico_unique_board_id_t *)(res_APDU+res_APDU_size)); res_APDU_size += 8; pico_get_unique_board_id((pico_unique_board_id_t *) (res_APDU + res_APDU_size));
res_APDU_size += 8;
#else #else
memset(res_APDU+res_APDU_size,0,8); res_APDU_size += 8; memset(res_APDU + res_APDU_size, 0, 8); res_APDU_size += 8;
#endif #endif
if (file_has_data(search_dynamic_file(EF_OATH_CODE)) == true) { if (file_has_data(search_dynamic_file(EF_OATH_CODE)) == true) {
res_APDU[res_APDU_size++] = TAG_CHALLENGE; res_APDU[res_APDU_size++] = TAG_CHALLENGE;
res_APDU[res_APDU_size++] = sizeof(challenge); res_APDU[res_APDU_size++] = sizeof(challenge);
memcpy(res_APDU+res_APDU_size, challenge, sizeof(challenge)); res_APDU_size += sizeof(challenge); memcpy(res_APDU + res_APDU_size, challenge, sizeof(challenge));
res_APDU_size += sizeof(challenge);
} }
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return a; return a;
@@ -91,7 +93,7 @@ app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
return NULL; return NULL;
} }
void __attribute__ ((constructor)) oath_ctor() { void __attribute__((constructor)) oath_ctor() {
register_app(oath_select); register_app(oath_select);
} }
@@ -104,7 +106,10 @@ file_t *find_oath_cred(const uint8_t *name, size_t name_len) {
uint8_t *ef_tag_data = NULL; uint8_t *ef_tag_data = NULL;
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file(EF_OATH_CRED + i); file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
if (file_has_data(ef) && asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_NAME, &ef_tag_len, &ef_tag_data) == true && ef_tag_len == name_len && memcmp(ef_tag_data, name, name_len) == 0) { if (file_has_data(ef) &&
asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_NAME, &ef_tag_len,
&ef_tag_data) == true && ef_tag_len == name_len &&
memcmp(ef_tag_data, name, name_len) == 0) {
return ef; return ef;
} }
} }
@@ -112,14 +117,17 @@ file_t *find_oath_cred(const uint8_t *name, size_t name_len) {
} }
int cmd_put() { int cmd_put() {
if (validated == false) if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
}
size_t key_len = 0, imf_len = 0, name_len = 0; size_t key_len = 0, imf_len = 0, name_len = 0;
uint8_t *key = NULL, *imf = NULL, *name = NULL; uint8_t *key = NULL, *imf = NULL, *name = NULL;
if (asn1_find_tag(apdu.data, apdu.nc, TAG_KEY, &key_len, &key) == false) if (asn1_find_tag(apdu.data, apdu.nc, TAG_KEY, &key_len, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &name_len, &name) == false) }
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &name_len, &name) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (asn1_find_tag(apdu.data, apdu.nc, TAG_IMF, &imf_len, &imf) == false) { if (asn1_find_tag(apdu.data, apdu.nc, TAG_IMF, &imf_len, &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);
@@ -127,10 +135,10 @@ int cmd_put() {
} }
else { //prepend zero-valued bytes else { //prepend zero-valued bytes
if (imf_len < 8) { if (imf_len < 8) {
memmove(imf+(8-imf_len), imf, imf_len); memmove(imf + (8 - imf_len), imf, imf_len);
memset(imf, 0, 8-imf_len); memset(imf, 0, 8 - imf_len);
*(imf-1) = 8; *(imf - 1) = 8;
apdu.nc += (8-imf_len); apdu.nc += (8 - imf_len);
} }
} }
@@ -159,8 +167,9 @@ int cmd_put() {
int cmd_delete() { int cmd_delete() {
size_t tag_len = 0; size_t tag_len = 0;
uint8_t *tag_data = NULL; uint8_t *tag_data = NULL;
if (validated == false) if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &tag_len, &tag_data) == true) { if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &tag_len, &tag_data) == true) {
file_t *ef = find_oath_cred(tag_data, tag_len); file_t *ef = find_oath_cred(tag_data, tag_len);
if (ef) { if (ef) {
@@ -173,18 +182,22 @@ int cmd_delete() {
} }
const mbedtls_md_info_t *get_oath_md_info(uint8_t alg) { const mbedtls_md_info_t *get_oath_md_info(uint8_t alg) {
if ((alg & ALG_MASK) == ALG_HMAC_SHA1) if ((alg & ALG_MASK) == ALG_HMAC_SHA1) {
return mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); return mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
else if ((alg & ALG_MASK) == ALG_HMAC_SHA256) }
else if ((alg & ALG_MASK) == ALG_HMAC_SHA256) {
return mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); return mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
else if ((alg & ALG_MASK) == ALG_HMAC_SHA512) }
else if ((alg & ALG_MASK) == ALG_HMAC_SHA512) {
return mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); return mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
}
return NULL; return NULL;
} }
int cmd_set_code() { int cmd_set_code() {
if (validated == false) if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (apdu.nc == 0) { if (apdu.nc == 0) {
delete_file(search_dynamic_file(EF_OATH_CODE)); delete_file(search_dynamic_file(EF_OATH_CODE));
validated = true; validated = true;
@@ -192,27 +205,33 @@ int cmd_set_code() {
} }
size_t key_len = 0, chal_len = 0, resp_len = 0; size_t key_len = 0, chal_len = 0, resp_len = 0;
uint8_t *key = NULL, *chal = NULL, *resp = NULL; uint8_t *key = NULL, *chal = NULL, *resp = NULL;
if (asn1_find_tag(apdu.data, apdu.nc, TAG_KEY, &key_len, &key) == false) if (asn1_find_tag(apdu.data, apdu.nc, TAG_KEY, &key_len, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
if (key_len == 0) { if (key_len == 0) {
delete_file(search_dynamic_file(EF_OATH_CODE)); delete_file(search_dynamic_file(EF_OATH_CODE));
validated = true; validated = true;
return SW_OK(); return SW_OK();
} }
if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
if (asn1_find_tag(apdu.data, apdu.nc, TAG_RESPONSE, &resp_len, &resp) == false) }
if (asn1_find_tag(apdu.data, apdu.nc, TAG_RESPONSE, &resp_len, &resp) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
const mbedtls_md_info_t *md_info = get_oath_md_info(key[0]); const mbedtls_md_info_t *md_info = get_oath_md_info(key[0]);
if (md_info == NULL) if (md_info == NULL) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
uint8_t hmac[64]; uint8_t hmac[64];
int r = mbedtls_md_hmac(md_info, key+1, key_len-1, chal, chal_len, hmac); int r = mbedtls_md_hmac(md_info, key + 1, key_len - 1, chal, chal_len, hmac);
if (r != 0) if (r != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
if (memcmp(hmac, resp, resp_len) != 0) }
if (memcmp(hmac, resp, resp_len) != 0) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
}
random_gen(NULL, challenge, sizeof(challenge)); random_gen(NULL, challenge, sizeof(challenge));
file_t *ef = file_new(EF_OATH_CODE); file_t *ef = file_new(EF_OATH_CODE);
flash_write_data_to_file(ef, key, key_len); flash_write_data_to_file(ef, key, key_len);
@@ -222,8 +241,9 @@ int cmd_set_code() {
} }
int cmd_reset() { int cmd_reset() {
if (P1(apdu) != 0xde || P2(apdu) != 0xad) if (P1(apdu) != 0xde || P2(apdu) != 0xad) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
}
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file(EF_OATH_CRED + i); file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
if (file_has_data(ef)) { if (file_has_data(ef)) {
@@ -238,18 +258,21 @@ int cmd_reset() {
int cmd_list() { int cmd_list() {
size_t name_len = 0, key_len = 0; size_t name_len = 0, key_len = 0;
uint8_t *name = NULL, *key = NULL; uint8_t *name = NULL, *key = NULL;
if (validated == false) if (validated == false) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
}
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file(EF_OATH_CRED + i); file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
if (file_has_data(ef)) { if (file_has_data(ef)) {
uint8_t *data = file_get_data(ef); uint8_t *data = file_get_data(ef);
size_t data_len = file_get_size(ef); size_t data_len = file_get_size(ef);
if (asn1_find_tag(data, data_len, TAG_NAME, &name_len, &name) == true && asn1_find_tag(data, data_len, TAG_KEY, &key_len, &key) == true) { if (asn1_find_tag(data, data_len, TAG_NAME, &name_len,
&name) == true &&
asn1_find_tag(data, data_len, TAG_KEY, &key_len, &key) == true) {
res_APDU[res_APDU_size++] = TAG_NAME_LIST; res_APDU[res_APDU_size++] = TAG_NAME_LIST;
res_APDU[res_APDU_size++] = name_len + 1; res_APDU[res_APDU_size++] = name_len + 1;
res_APDU[res_APDU_size++] = key[0]; res_APDU[res_APDU_size++] = key[0];
memcpy(res_APDU+res_APDU_size, name, name_len); res_APDU_size += name_len; memcpy(res_APDU + res_APDU_size, name, name_len); res_APDU_size += name_len;
} }
} }
} }
@@ -260,10 +283,12 @@ int cmd_list() {
int cmd_validate() { int cmd_validate() {
size_t chal_len = 0, resp_len = 0, key_len = 0; size_t chal_len = 0, resp_len = 0, key_len = 0;
uint8_t *chal = NULL, *resp = NULL, *key = NULL; uint8_t *chal = NULL, *resp = NULL, *key = NULL;
if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
if (asn1_find_tag(apdu.data, apdu.nc, TAG_RESPONSE, &resp_len, &resp) == false) }
if (asn1_find_tag(apdu.data, apdu.nc, TAG_RESPONSE, &resp_len, &resp) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
file_t *ef = search_dynamic_file(EF_OATH_CODE); file_t *ef = search_dynamic_file(EF_OATH_CODE);
if (file_has_data(ef) == false) { if (file_has_data(ef) == false) {
validated = true; validated = true;
@@ -272,47 +297,58 @@ int cmd_validate() {
key = file_get_data(ef); key = file_get_data(ef);
key_len = file_get_size(ef); key_len = file_get_size(ef);
const mbedtls_md_info_t *md_info = get_oath_md_info(key[0]); const mbedtls_md_info_t *md_info = get_oath_md_info(key[0]);
if (md_info == NULL) if (md_info == NULL) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
uint8_t hmac[64]; uint8_t hmac[64];
int ret = mbedtls_md_hmac(md_info, key+1, key_len-1, challenge, sizeof(challenge), hmac); int ret = mbedtls_md_hmac(md_info, key + 1, key_len - 1, challenge, sizeof(challenge), hmac);
if (ret != 0) if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
if (memcmp(hmac, resp, resp_len) != 0) }
if (memcmp(hmac, resp, resp_len) != 0) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
ret = mbedtls_md_hmac(md_info, key+1, key_len-1, chal, chal_len, hmac); }
if (ret != 0) ret = mbedtls_md_hmac(md_info, key + 1, key_len - 1, chal, chal_len, hmac);
if (ret != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
}
validated = true; validated = true;
res_APDU[res_APDU_size++] = TAG_RESPONSE; res_APDU[res_APDU_size++] = TAG_RESPONSE;
res_APDU[res_APDU_size++] = mbedtls_md_get_size(md_info); res_APDU[res_APDU_size++] = mbedtls_md_get_size(md_info);
memcpy(res_APDU+res_APDU_size, hmac, mbedtls_md_get_size(md_info)); res_APDU_size += mbedtls_md_get_size(md_info); memcpy(res_APDU + res_APDU_size, hmac, mbedtls_md_get_size(md_info));
res_APDU_size += mbedtls_md_get_size(md_info);
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return SW_OK(); return SW_OK();
} }
int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const uint8_t *chal, size_t chal_len) { int calculate_oath(uint8_t truncate,
const uint8_t *key,
size_t key_len,
const uint8_t *chal,
size_t chal_len) {
const mbedtls_md_info_t *md_info = get_oath_md_info(key[0]); const mbedtls_md_info_t *md_info = get_oath_md_info(key[0]);
if (md_info == NULL) if (md_info == NULL) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
uint8_t hmac[64]; uint8_t hmac[64];
int r = mbedtls_md_hmac(md_info, key+2, key_len-2, chal, chal_len, hmac); 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); size_t hmac_size = mbedtls_md_get_size(md_info);
if (r != 0) if (r != 0) {
return CCID_EXEC_ERROR; return CCID_EXEC_ERROR;
}
if (truncate == 0x01) { if (truncate == 0x01) {
res_APDU[res_APDU_size++] = 4+1; res_APDU[res_APDU_size++] = 4 + 1;
res_APDU[res_APDU_size++] = key[1]; res_APDU[res_APDU_size++] = key[1];
uint8_t offset = hmac[hmac_size-1] & 0x0f; uint8_t offset = hmac[hmac_size - 1] & 0x0f;
res_APDU[res_APDU_size++] = hmac[offset] & 0x7f; res_APDU[res_APDU_size++] = hmac[offset] & 0x7f;
res_APDU[res_APDU_size++] = hmac[offset+1]; res_APDU[res_APDU_size++] = hmac[offset + 1];
res_APDU[res_APDU_size++] = hmac[offset+2]; res_APDU[res_APDU_size++] = hmac[offset + 2];
res_APDU[res_APDU_size++] = hmac[offset+3]; res_APDU[res_APDU_size++] = hmac[offset + 3];
} }
else { else {
res_APDU[res_APDU_size++] = hmac_size+1; res_APDU[res_APDU_size++] = hmac_size + 1;
res_APDU[res_APDU_size++] = key[1]; res_APDU[res_APDU_size++] = key[1];
memcpy(res_APDU+res_APDU_size, hmac, hmac_size); res_APDU_size += hmac_size; memcpy(res_APDU + res_APDU_size, hmac, hmac_size); res_APDU_size += hmac_size;
} }
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return CCID_OK; return CCID_OK;
@@ -321,36 +357,55 @@ int calculate_oath(uint8_t truncate, const uint8_t *key, size_t key_len, const u
int cmd_calculate() { int cmd_calculate() {
size_t chal_len = 0, name_len = 0, key_len = 0; size_t chal_len = 0, name_len = 0, key_len = 0;
uint8_t *chal = NULL, *name = NULL, *key = NULL; uint8_t *chal = NULL, *name = NULL, *key = NULL;
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(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) }
if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &name_len, &name) == false) }
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &name_len, &name) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
file_t *ef = find_oath_cred(name, name_len); file_t *ef = find_oath_cred(name, name_len);
if (file_has_data(ef) == false) if (file_has_data(ef) == false) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
}
if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_KEY, &key_len, &key) == false) if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_KEY, &key_len, &key) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_IMF, &chal_len, &chal) == false) if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_IMF, &chal_len,
return SW_INCORRECT_PARAMS(); &chal) == false) {
return SW_INCORRECT_PARAMS();
}
} }
res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu); res_APDU[res_APDU_size++] = TAG_RESPONSE + P2(apdu);
int ret = calculate_oath(P2(apdu), key, key_len, chal, chal_len); int ret = calculate_oath(P2(apdu), key, key_len, chal, chal_len);
if (ret != CCID_OK) if (ret != CCID_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
}
if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
uint64_t v = ((uint64_t)chal[0] << 56) | ((uint64_t)chal[1] << 48) | ((uint64_t)chal[2] << 40) | ((uint64_t)chal[3] << 32) | ((uint64_t)chal[4] << 24) | ((uint64_t)chal[5] << 16) | ((uint64_t)chal[6] << 8) | (uint64_t)chal[7]; uint64_t v =
((uint64_t) chal[0] <<
56) |
((uint64_t) chal[1] <<
48) |
((uint64_t) chal[2] <<
40) |
((uint64_t) chal[3] <<
32) |
((uint64_t) chal[4] <<
24) | ((uint64_t) chal[5] << 16) | ((uint64_t) chal[6] << 8) | (uint64_t) chal[7];
size_t ef_size = file_get_size(ef); size_t ef_size = file_get_size(ef);
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_find_tag(tmp, ef_size, TAG_IMF, &chal_len, &chal); asn1_find_tag(tmp, ef_size, TAG_IMF, &chal_len, &chal);
chal[0] = v >> 56; chal[0] = v >> 56;
@@ -372,28 +427,35 @@ int cmd_calculate() {
int cmd_calculate_all() { int cmd_calculate_all() {
size_t chal_len = 0, name_len = 0, key_len = 0, prop_len = 0; size_t chal_len = 0, name_len = 0, key_len = 0, prop_len = 0;
uint8_t *chal = NULL, *name = NULL, *key = NULL, *prop = NULL; uint8_t *chal = NULL, *name = NULL, *key = NULL, *prop = NULL;
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(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) }
if (asn1_find_tag(apdu.data, apdu.nc, TAG_CHALLENGE, &chal_len, &chal) == false) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
}
for (int i = 0; i < MAX_OATH_CRED; i++) { for (int i = 0; i < MAX_OATH_CRED; i++) {
file_t *ef = search_dynamic_file(EF_OATH_CRED + i); file_t *ef = search_dynamic_file(EF_OATH_CRED + i);
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);
if (asn1_find_tag(ef_data, ef_len, TAG_NAME, &name_len, &name) == false || asn1_find_tag(ef_data, ef_len, TAG_KEY, &key_len, &key) == false) if (asn1_find_tag(ef_data, ef_len, TAG_NAME, &name_len,
&name) == false ||
asn1_find_tag(ef_data, ef_len, TAG_KEY, &key_len, &key) == false) {
continue; continue;
}
res_APDU[res_APDU_size++] = TAG_NAME; res_APDU[res_APDU_size++] = TAG_NAME;
res_APDU[res_APDU_size++] = name_len; res_APDU[res_APDU_size++] = name_len;
memcpy(res_APDU+res_APDU_size, name, name_len); res_APDU_size += name_len; memcpy(res_APDU + res_APDU_size, name, name_len); res_APDU_size += name_len;
if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) { if ((key[0] & OATH_TYPE_MASK) == OATH_TYPE_HOTP) {
res_APDU[res_APDU_size++] = TAG_NO_RESPONSE; res_APDU[res_APDU_size++] = TAG_NO_RESPONSE;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = key[1]; res_APDU[res_APDU_size++] = key[1];
} }
else if (asn1_find_tag(ef_data, ef_len, TAG_PROPERTY, &prop_len, &prop) == true && (prop[0] & PROP_TOUCH)) { else if (asn1_find_tag(ef_data, ef_len, TAG_PROPERTY, &prop_len,
&prop) == true && (prop[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[1]; res_APDU[res_APDU_size++] = key[1];
@@ -436,14 +498,14 @@ static const cmd_t cmds[] = {
{ INS_CALCULATE, cmd_calculate }, { INS_CALCULATE, cmd_calculate },
{ INS_CALC_ALL, cmd_calculate_all }, { INS_CALC_ALL, cmd_calculate_all },
{ INS_SEND_REMAINING, cmd_send_remaining }, { INS_SEND_REMAINING, cmd_send_remaining },
{ 0x00, 0x0} { 0x00, 0x0 }
}; };
int oath_process_apdu() { int oath_process_apdu() {
if (CLA(apdu) != 0x00) if (CLA(apdu) != 0x00) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) }
{ for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
if (cmd->ins == INS(apdu)) { if (cmd->ins == INS(apdu)) {
int r = cmd->cmd_handler(); int r = cmd->cmd_handler();
return r; return r;

View File

@@ -23,11 +23,11 @@
#include "version.h" #include "version.h"
#include "asn1.h" #include "asn1.h"
#define FIXED_SIZE 16 #define FIXED_SIZE 16
#define KEY_SIZE 16 #define KEY_SIZE 16
#define UID_SIZE 6 #define UID_SIZE 6
#define KEY_SIZE_OATH 20 #define KEY_SIZE_OATH 20
#define ACC_CODE_SIZE 6 #define ACC_CODE_SIZE 6
#define CONFIG1_VALID 0x01 #define CONFIG1_VALID 0x01
#define CONFIG2_VALID 0x02 #define CONFIG2_VALID 0x02
@@ -36,7 +36,7 @@
#define CONFIG_LED_INV 0x10 #define CONFIG_LED_INV 0x10
#define CONFIG_STATUS_MASK 0x1f #define CONFIG_STATUS_MASK 0x1f
static uint8_t config_seq = {1}; static uint8_t config_seq = { 1 };
typedef struct otp_config { typedef struct otp_config {
uint8_t fixed_data[FIXED_SIZE]; uint8_t fixed_data[FIXED_SIZE];
@@ -63,14 +63,17 @@ const uint8_t otp_aid[] = {
}; };
app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) { app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
if (!memcmp(aid, otp_aid+1, MIN(aid_len,otp_aid[0]))) { if (!memcmp(aid, otp_aid + 1, MIN(aid_len, otp_aid[0]))) {
a->aid = otp_aid; a->aid = otp_aid;
a->process_apdu = otp_process_apdu; a->process_apdu = otp_process_apdu;
a->unload = otp_unload; 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(search_dynamic_file(EF_OTP_SLOT1)) ||
file_has_data(search_dynamic_file(EF_OTP_SLOT2))) {
config_seq = 1; config_seq = 1;
else }
else {
config_seq = 0; config_seq = 0;
}
otp_status(); otp_status();
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return a; return a;
@@ -78,7 +81,7 @@ app_t *otp_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
return NULL; return NULL;
} }
void __attribute__ ((constructor)) otp_ctor() { void __attribute__((constructor)) otp_ctor() {
register_app(otp_select); register_app(otp_select);
} }
@@ -92,7 +95,11 @@ uint16_t otp_status() {
res_APDU[res_APDU_size++] = 0; res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = config_seq; res_APDU[res_APDU_size++] = config_seq;
res_APDU[res_APDU_size++] = 0; res_APDU[res_APDU_size++] = 0;
res_APDU[res_APDU_size++] = (CONFIG2_TOUCH | CONFIG1_TOUCH) | (file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ? CONFIG1_VALID : 0x00) | (file_has_data(search_dynamic_file(EF_OTP_SLOT2)) ? CONFIG2_VALID : 0x00); res_APDU[res_APDU_size++] = (CONFIG2_TOUCH | CONFIG1_TOUCH) |
(file_has_data(search_dynamic_file(EF_OTP_SLOT1)) ? CONFIG1_VALID :
0x00) |
(file_has_data(search_dynamic_file(EF_OTP_SLOT2)) ? CONFIG2_VALID :
0x00);
return SW_OK(); return SW_OK();
} }
@@ -102,15 +109,18 @@ int cmd_otp() {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
if (p1 == 0x01 || p1 == 0x03) { // Configure slot if (p1 == 0x01 || p1 == 0x03) { // Configure slot
if (apdu.nc != otp_config_size+ACC_CODE_SIZE) if (apdu.nc != otp_config_size + ACC_CODE_SIZE) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
if (apdu.data[48] != 0 || apdu.data[49] != 0) }
if (apdu.data[48] != 0 || apdu.data[49] != 0) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
}
file_t *ef = file_new(p1 == 0x01 ? EF_OTP_SLOT1 : EF_OTP_SLOT2); file_t *ef = file_new(p1 == 0x01 ? EF_OTP_SLOT1 : EF_OTP_SLOT2);
if (file_has_data(ef)) { if (file_has_data(ef)) {
otp_config_t *otpc = (otp_config_t *)file_get_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) if (memcmp(otpc->acc_code, apdu.data + otp_config_size, ACC_CODE_SIZE) != 0) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
}
} }
for (int c = 0; c < otp_config_size; c++) { for (int c = 0; c < otp_config_size; c++) {
if (apdu.data[c] != 0) { if (apdu.data[c] != 0) {
@@ -122,13 +132,15 @@ int cmd_otp() {
} }
// Delete slot // Delete slot
delete_file(ef); delete_file(ef);
if (!file_has_data(search_dynamic_file(EF_OTP_SLOT1)) && !file_has_data(search_dynamic_file(EF_OTP_SLOT2))) if (!file_has_data(search_dynamic_file(EF_OTP_SLOT1)) &&
!file_has_data(search_dynamic_file(EF_OTP_SLOT2))) {
config_seq = 0; config_seq = 0;
}
return otp_status(); return otp_status();
} }
else if (p1 == 0x10) { else if (p1 == 0x10) {
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
pico_get_unique_board_id_string((char *)res_APDU, 4); pico_get_unique_board_id_string((char *) res_APDU, 4);
#endif #endif
res_APDU_size = 4; res_APDU_size = 4;
} }
@@ -147,14 +159,14 @@ int cmd_otp() {
static const cmd_t cmds[] = { static const cmd_t cmds[] = {
{ INS_OTP, cmd_otp }, { INS_OTP, cmd_otp },
{ 0x00, 0x0} { 0x00, 0x0 }
}; };
int otp_process_apdu() { int otp_process_apdu() {
if (CLA(apdu) != 0x00) if (CLA(apdu) != 0x00) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) }
{ for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
if (cmd->ins == INS(apdu)) { if (cmd->ins == INS(apdu)) {
int r = cmd->cmd_handler(); int r = cmd->cmd_handler();
return r; return r;

View File

@@ -24,4 +24,3 @@
#define PICO_FIDO_VERSION_MINOR (PICO_FIDO_VERSION & 0xff) #define PICO_FIDO_VERSION_MINOR (PICO_FIDO_VERSION & 0xff)
#endif #endif