17#include <esp_system.h>
18#include <esp_random.h>
19#include <mbedtls/ecdsa.h>
20#include <mbedtls/ecp.h>
21#include <mbedtls/ecdh.h>
22#include <mbedtls/md.h>
23#include <mbedtls/sha256.h>
24#include <mbedtls/aes.h>
26#include <freertos/FreeRTOS.h>
27#include <freertos/task.h>
34static const char*
TAG =
"CTAP2";
41#ifndef CTAP2_DEBUG_COMMANDS
42#define CTAP2_DEBUG_COMMANDS 0
47 0xCD, 0xCB, 0xAD, 0x6E,
50 0xBA, 0xD6, 0xE0, 0x01,
51 0x00, 0x00, 0x00, 0x01
57#define USER_PRESENCE_TIMEOUT_MS 30000
79#define PIN_PROTOCOL_VERSION 2
80#define PIN_TOKEN_SIZE 32
81#define PIN_RETRIES_MAX 8
82#define PIN_UV_RETRIES_MAX 3
85#define PIN_CMD_GET_RETRIES 0x01
86#define PIN_CMD_GET_KEY_AGREEMENT 0x02
87#define PIN_CMD_SET_PIN 0x03
88#define PIN_CMD_CHANGE_PIN 0x04
89#define PIN_CMD_GET_PIN_TOKEN 0x05
90#define PIN_CMD_GET_PIN_UV_TOKEN 0x09
93#define PIN_PERM_MAKE_CREDENTIAL 0x01
94#define PIN_PERM_GET_ASSERTION 0x02
95#define PIN_PERM_CRED_MGMT 0x04
96#define PIN_PERM_BIO_ENROLLMENT 0x08
97#define PIN_PERM_LARGE_BLOB_WRITE 0x10
98#define PIN_PERM_AUTHN_CONFIG 0x20
122#define CRED_MGMT_GET_CREDS_METADATA 0x01
123#define CRED_MGMT_ENUMERATE_RPS_BEGIN 0x02
124#define CRED_MGMT_ENUMERATE_RPS_GET_NEXT 0x03
125#define CRED_MGMT_ENUMERATE_CREDS_BEGIN 0x04
126#define CRED_MGMT_ENUMERATE_CREDS_GET_NEXT 0x05
127#define CRED_MGMT_DELETE_CREDENTIAL 0x06
149 if (se && se->isSessionActive() && se->getRandom(out,
static_cast<uint16_t
>(len))) {
152 esp_fill_random(out, len);
159 const uint8_t *attested_cred_data,
160 uint16_t attested_cred_len,
161 const uint8_t *ext_data,
193 uint16_t cred_id_len,
194 const uint8_t *pubkey,
199 if (!out || !out_len)
return false;
201 const size_t fixed_prefix = 16 + 2 + cred_id_len;
202 if (out_size < fixed_prefix)
return false;
206 memcpy(out + off,
AAGUID, 16);
209 out[off++] = (cred_id_len >> 8) & 0xFF;
210 out[off++] = cred_id_len & 0xFF;
212 memcpy(out + off, cred_id, cred_id_len);
215 cbor_writer_t cose_w;
236 if (level == 0 || !out || out_size < 20)
return 0;
259 const uint8_t *attested_cred,
260 uint16_t attested_len,
263 uint16_t *auth_data_len) {
265 uint8_t
flags = 0x01 | 0x40;
274 uint8_t ext_data[32];
275 uint16_t ext_len = 0;
284 attested_cred, attested_len,
285 ext_len > 0 ? ext_data : NULL, ext_len,
286 auth_data, auth_data_len) ==
CTAP2_OK;
320 uint16_t auth_data_len,
326 uint16_t *response_len) {
334 if (sig_len == 0 && (cert == NULL || cert_len == 0)) {
347 if (sig_len == 0 && (cert == NULL || cert_len == 0)) {
350 }
else if (cert && cert_len > 0) {
387 if (!key || !pubkey)
return false;
388 mbedtls_ecp_keypair_init(key);
390 int rc = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, key,
ctap2_random, NULL);
392 mbedtls_ecp_keypair_free(key);
396#if defined(MBEDTLS_PRIVATE)
397#define CTAP2_ECP_GRP(k) (k).MBEDTLS_PRIVATE(grp)
398#define CTAP2_ECP_Q(k) (k).MBEDTLS_PRIVATE(Q)
400#define CTAP2_ECP_GRP(k) (k).grp
401#define CTAP2_ECP_Q(k) (k).Q
407 MBEDTLS_ECP_PF_UNCOMPRESSED,
408 &olen, buf,
sizeof(buf));
411 if (rc != 0 || olen !=
sizeof(buf)) {
412 mbedtls_ecp_keypair_free(key);
415 memcpy(pubkey, buf + 1, 64);
431 const uint8_t *msg,
size_t msg_len,
432 uint8_t *sig,
size_t sig_size,
size_t *sig_len) {
433 if (!key || !msg || !sig || !sig_len)
return false;
435 sha256(msg, msg_len, hash);
437 mbedtls_ecdsa_context ecdsa;
438 mbedtls_ecdsa_init(&ecdsa);
439 int rc = mbedtls_ecdsa_from_keypair(&ecdsa, key);
441 mbedtls_ecdsa_free(&ecdsa);
445 rc = mbedtls_ecdsa_write_signature(&ecdsa, MBEDTLS_MD_SHA256,
447 sig, sig_size, sig_len,
449 mbedtls_ecdsa_free(&ecdsa);
471 const uint8_t *attested_cred_data,
472 uint16_t attested_cred_len,
473 const uint8_t *ext_data,
485 if (ext_data && ext_len > 0) {
488 out[offset++] =
flags;
497 if (attested_cred_data && attested_cred_len > 0) {
498 memcpy(out + offset, attested_cred_data, attested_cred_len);
499 offset += attested_cred_len;
502 if (ext_data && ext_len > 0) {
503 memcpy(out + offset, ext_data, ext_len);
519 LOG_I(
TAG,
"User presence required for %s at %s",
532 LOG_I(
TAG,
"User presence approved");
538 LOG_I(
TAG,
"User presence timeout");
541 LOG_W(
TAG,
"User presence unknown state: %d", result);
675static void dump_get_info_response(
const uint8_t *response, uint16_t len) {
676 LOG_I(
TAG,
"getInfo response len=%u", len);
677 for (uint16_t offset = 0; offset < len; offset += 16) {
679 int dump_len = ((len - offset) < 16) ? (len - offset) : 16;
680 for (
int i = 0; i < dump_len; i++) {
681 sprintf(hex + (i * 3),
"%02X ", response[offset + i]);
683 LOG_D(
TAG,
"%03u: %s", offset, hex);
723 dump_get_info_response(response, *response_len);
757 memset(
this, 0,
sizeof(*
this));
772 for (
int j = 0; j <
rp_count; j++) {
779 if (strcmp(rp_key,
"id") == 0) {
799 if (user_count < 0)
return false;
801 for (
int j = 0; j < user_count; j++) {
808 if (strcmp(user_key,
"id") == 0) {
813 }
else if (strcmp(user_key,
"name") == 0) {
831 if (params_count < 0)
return false;
833 for (
int j = 0; j < params_count; j++) {
835 int64_t param_alg = 0;
836 for (
int k = 0; k < param_count; k++) {
843 if (strcmp(param_key,
"alg") == 0) {
866 if (ext_count < 0)
return false;
868 for (
int j = 0; j < ext_count; j++) {
875 if (strcmp(ext_key,
"appidExclude") == 0) {
880 }
else if (strcmp(ext_key,
"credProtect") == 0) {
901 if (opt_count < 0)
return false;
903 for (
int j = 0; j < opt_count; j++) {
910 if (strcmp(opt_key,
"rk") == 0) {
912 }
else if (strcmp(opt_key,
"uv") == 0) {
914 }
else if (strcmp(opt_key,
"up") == 0) {
941 for (
int i = 0; i < map_count; i++) {
1009 LOG_W(
TAG,
"makeCredential: pinUvAuthParam provided but no valid pinToken");
1014 uint8_t expected_hmac[32];
1015 mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
1024 LOG_W(
TAG,
"makeCredential: pinUvAuthParam verification failed");
1028 LOG_I(
TAG,
"makeCredential: pinUvAuthParam verified - UV=1");
1043 uint8_t appid_hash[32];
1059 uint8_t *response, uint16_t *response_len) {
1060 LOG_I(
TAG,
"Browser probe request (%s) - waiting for user selection", p->
rp_id);
1070 uint8_t dummy_pubkey[64];
1072 if (
ctap2_random(NULL, dummy_cred_id,
sizeof(dummy_cred_id)) != 0) {
1078 uint8_t attested_cred[256];
1079 uint16_t attested_len = 0;
1080 uint8_t auth_data[256];
1081 uint16_t auth_data_len = 0;
1084 EXT_RAM_BSS_ATTR
static uint8_t to_sign[512];
1085 uint8_t signature[128];
1088 mbedtls_ecp_keypair ephemeral_key;
1098 mbedtls_ecp_keypair_free(&ephemeral_key);
1105 0, auth_data, &auth_data_len)) {
1106 mbedtls_ecp_keypair_free(&ephemeral_key);
1112 if (auth_data_len + 32 >
sizeof(to_sign)) {
1113 mbedtls_ecp_keypair_free(&ephemeral_key);
1119 memcpy(to_sign, auth_data, auth_data_len);
1121 uint16_t to_sign_len = auth_data_len + 32;
1124 signature,
sizeof(signature), &sig_len)) {
1125 mbedtls_ecp_keypair_free(&ephemeral_key);
1130 mbedtls_ecp_keypair_free(&ephemeral_key);
1132 LOG_I(
TAG,
"User selected this authenticator");
1134 auth_data, auth_data_len, signature, (uint8_t)sig_len,
1135 NULL, 0, response, response_len);
1136 LOG_I(
TAG,
"Probe makeCredential status=0x%02X resp_len=%u", status, *response_len);
1146 return strcmp(
rp_id,
"make.me.blink") == 0 || strcmp(
rp_id,
".dummy") == 0;
1157 uint16_t *response_len) {
1174 uint8_t *response, uint16_t *response_len) {
1183 LOG_I(
TAG,
"Calling fido2_storage_create_credential...");
1192 uint8_t attested_cred[256];
1193 uint16_t attested_len = 0;
1194 uint8_t auth_data[256];
1195 uint16_t auth_data_len = 0;
1198 attested_cred,
sizeof(attested_cred),
1206 EXT_RAM_BSS_ATTR
static uint8_t mc_to_sign[512];
1207 if (auth_data_len + 32 >
sizeof(mc_to_sign)) {
1210 memcpy(mc_to_sign, auth_data, auth_data_len);
1212 uint16_t to_sign_len = auth_data_len + 32;
1215 uint8_t signature[128];
1216 uint8_t sig_len = 0;
1217 const uint8_t *att_cert = NULL;
1218 uint16_t att_cert_len = 0;
1220 LOG_I(
TAG,
"PIN state: pinToken_valid=%d, is_pin_verified=%d",
1225 LOG_E(
TAG,
"Attestation certificate not initialized");
1233 LOG_E(
TAG,
"Attestation signing failed");
1236 LOG_I(
TAG,
"Using basic attestation (cert=%u, sig=%u)", att_cert_len, sig_len);
1239 auth_data, auth_data_len, signature, sig_len,
1240 att_cert, att_cert_len, response, response_len);
1245 LOG_I(
TAG,
"Created credential for %s (slot %d)", p->
rp_id, slot);
1248 LOG_I(
TAG,
"makeCredential status=0x%02X resp_len=%u", status, *response_len);
1249 for (uint16_t offset = 0; offset < *response_len; offset += 16) {
1251 int dump_len = ((*response_len - offset) < 16) ? (*response_len - offset) : 16;
1252 for (
int i = 0; i < dump_len; i++) {
1253 sprintf(hex + (i * 3),
"%02X ", response[offset + i]);
1255 LOG_D(
TAG,
"%03u: %s", offset, hex);
1271 uint8_t *response, uint16_t *response_len) {
1277 response[0] = status;
1282 LOG_I(
TAG,
"makeCredential rp_id=%s rk=%d uv=%d up=%d alg=%d pinProto=%d pinAuthLen=%zu",
1289 response[0] = status;
1297 response[0] = status;
1350 LOG_I(
TAG,
"User presence OK, creating credential (curve=%d)...",
curve);
1405 size_t *cred_id_len) {
1412 bool have_id =
false;
1414 for (
int k = 0; k < cred_map; k++) {
1421 if (strcmp(cred_key,
"id") == 0) {
1442 if (list_count < 0) {
1446 p->allow_list_present =
true;
1448 for (
int j = 0; j < list_count; j++) {
1450 size_t cred_id_len = 0;
1462 bool exists =
false;
1463 for (uint8_t m = 0; m < p->allow_list_count; m++) {
1464 if (p->allow_list_slots[m] == (uint8_t)slot) {
1470 p->allow_list_slots[p->allow_list_count++] = (uint8_t)slot;
1485 if (ext_count < 0) {
1489 for (
int j = 0; j < ext_count; j++) {
1496 if (strcmp(ext_key,
"appid") == 0) {
1499 p->has_appid = (len > 0);
1520 if (opt_count < 0) {
1524 for (
int j = 0; j < opt_count; j++) {
1531 if (strcmp(opt_key,
"uv") == 0) {
1533 }
else if (strcmp(opt_key,
"up") == 0) {
1551 GetAssertionParams *p) {
1552 memset(p, 0,
sizeof(*p));
1553 p->option_up =
true;
1559 if (map_count < 0) {
1563 for (
int i = 0; i < map_count; i++) {
1584 if (!
cbor_read_bytes(&r, p->client_data_hash, 32, &len) || len != 32) {
1587 p->has_client_data =
true;
1593 if (status !=
CTAP2_OK)
return status;
1598 if (status !=
CTAP2_OK)
return status;
1603 if (status !=
CTAP2_OK)
return status;
1607 cbor_read_bytes(&r, p->pin_uv_auth_param,
sizeof(p->pin_uv_auth_param),
1608 &p->pin_uv_auth_param_len);
1615 p->pin_uv_auth_protocol = (uint8_t)proto;
1636 *uv_verified =
false;
1638 if (p->pin_uv_auth_param_len == 0) {
1643 LOG_W(
TAG,
"pinUvAuthParam provided but no valid pinToken");
1648 uint8_t expected_hmac[32];
1649 mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
1651 p->client_data_hash, 32,
1655 size_t compare_len = (p->pin_uv_auth_protocol == 2) ? 32 : 16;
1656 if (p->pin_uv_auth_param_len < compare_len) {
1657 LOG_W(
TAG,
"pinUvAuthParam too short: %zu < %zu",
1658 p->pin_uv_auth_param_len, compare_len);
1663 LOG_D(
TAG,
"pinUvAuthParam received (%zu bytes):", p->pin_uv_auth_param_len);
1664 LOG_D(
TAG,
" %02X%02X%02X%02X %02X%02X%02X%02X...",
1665 p->pin_uv_auth_param[0], p->pin_uv_auth_param[1],
1666 p->pin_uv_auth_param[2], p->pin_uv_auth_param[3],
1667 p->pin_uv_auth_param[4], p->pin_uv_auth_param[5],
1668 p->pin_uv_auth_param[6], p->pin_uv_auth_param[7]);
1669 LOG_D(
TAG,
"Expected HMAC (first %zu bytes):", compare_len);
1670 LOG_D(
TAG,
" %02X%02X%02X%02X %02X%02X%02X%02X...",
1671 expected_hmac[0], expected_hmac[1], expected_hmac[2], expected_hmac[3],
1672 expected_hmac[4], expected_hmac[5], expected_hmac[6], expected_hmac[7]);
1675 if (memcmp(p->pin_uv_auth_param, expected_hmac, compare_len) != 0) {
1676 LOG_W(
TAG,
"pinUvAuthParam verification failed");
1680 LOG_I(
TAG,
"pinUvAuthParam verified - UV=1");
1681 *uv_verified =
true;
1695 creds->hash_in_use = p->rp_id_hash;
1698 uint8_t temp_count = 0;
1700 if (p->allow_list_present && p->allow_list_count > 0) {
1702 uint8_t filtered = 0;
1703 for (uint8_t i = 0; i < p->allow_list_count; i++) {
1704 fido2_credential_info_t info;
1706 memcmp(info.rp_id_hash, p->rp_id_hash, 32) == 0) {
1707 creds->slots[filtered++] = p->allow_list_slots[i];
1710 creds->count = filtered;
1711 creds->include_user =
false;
1713 LOG_I(
TAG,
"getAssertion using allowList, matches=%u",
creds->count);
1717 uint8_t filtered_appid = 0;
1718 for (uint8_t i = 0; i < p->allow_list_count; i++) {
1719 fido2_credential_info_t info;
1721 memcmp(info.rp_id_hash, p->appid_hash, 32) == 0) {
1722 temp_slots[filtered_appid++] = p->allow_list_slots[i];
1725 if (filtered_appid > 0) {
1726 memcpy(
creds->slots, temp_slots, filtered_appid);
1727 creds->count = filtered_appid;
1728 creds->appid_used =
true;
1729 creds->hash_in_use = p->appid_hash;
1736 creds->include_user =
true;
1738 LOG_I(
TAG,
"getAssertion using all RP creds, matches=%u",
creds->count);
1744 if (temp_count > 0) {
1745 memcpy(
creds->slots, temp_slots, temp_count);
1746 creds->count = temp_count;
1747 creds->appid_used =
true;
1748 creds->hash_in_use = p->appid_hash;
1765 uint16_t auth_data_len,
const uint8_t *client_data_hash,
1766 uint8_t *signature, uint8_t *sig_len) {
1768 uint8_t to_sign[96];
1769 if (auth_data_len >
sizeof(to_sign) - 32) {
1770 LOG_E(
TAG,
"auth_data too large: %u", auth_data_len);
1774 memcpy(to_sign, auth_data, auth_data_len);
1775 memcpy(to_sign + auth_data_len, client_data_hash, 32);
1776 uint16_t to_sign_len = auth_data_len + 32;
1800 uint16_t auth_data_len,
const uint8_t *signature,
1801 uint8_t sig_len,
const fido2_credential_info_t *cred,
1802 bool include_user, uint8_t total_creds,
1803 uint8_t *response, uint16_t *response_len) {
1807 int resp_fields = 3;
1808 if (include_user) resp_fields++;
1809 if (total_creds > 1) resp_fields++;
1833 int user_fields = 1;
1834 if (cred->user_name[0] !=
'\0') user_fields++;
1840 if (cred->user_name[0] !=
'\0') {
1847 if (total_creds > 1) {
1870 uint8_t *response, uint16_t *response_len) {
1872 GetAssertionParams p;
1875 response[0] = status;
1880 LOG_I(
TAG,
"getAssertion rp_id=%s allowList=%d count=%u uv=%d up=%d appid=%s",
1881 p.rp_id[0] ? p.rp_id :
"(none)", p.allow_list_present ? 1 : 0,
1882 p.allow_list_count, p.option_uv, p.option_up, p.has_appid ? p.appid :
"(none)");
1885 if (!p.has_rp || !p.has_client_data) {
1898 bool uv_verified =
false;
1901 response[0] = status;
1915 AssertionCredentials
creds;
1918 if (
creds.count == 0) {
1937 memcpy(
g_ctap2.assertion_rp_id_hash,
creds.hash_in_use, 32);
1938 memcpy(
g_ctap2.assertion_client_data_hash, p.client_data_hash, 32);
1940 g_ctap2.assertion_up_done = p.option_up;
1944 uint8_t slot =
g_ctap2.assertion_creds[0];
1945 fido2_credential_info_t cred;
1960 uint8_t
flags = p.option_up ? 0x01 : 0x00;
1965 uint8_t ext_data[32];
1966 uint16_t ext_len = 0;
1967 if (
creds.appid_used) {
1971 uint8_t auth_data[128];
1972 uint16_t auth_data_len;
1974 ext_data, ext_len, auth_data, &auth_data_len);
1977 uint8_t signature[128];
1980 signature, &sig_len);
1982 response[0] = status;
1990 LOG_E(
TAG,
"Failed to get credential ID for slot %d", slot);
1997 status =
ga_build_response(cred_id, auth_data, auth_data_len, signature, sig_len,
1998 &cred,
g_ctap2.assertion_include_user,
1999 g_ctap2.assertion_count, response, response_len);
2001 response[0] = status;
2008 LOG_I(
TAG,
"Assertion for %s (slot %d)", p.rp_id, slot);
2019 if (
g_ctap2.assertion_count == 0) {
2034 fido2_credential_info_t cred;
2048 uint8_t auth_data[128];
2049 uint16_t auth_data_len;
2050 uint8_t ext_data[32];
2051 uint16_t ext_len = 0;
2052 if (
g_ctap2.assertion_appid_used) {
2056 NULL, 0, ext_data, ext_len, auth_data, &auth_data_len);
2059 uint8_t to_sign[96];
2060 if (auth_data_len >
sizeof(to_sign) - 32) {
2061 LOG_E(
TAG,
"auth_data too large: %u", auth_data_len);
2066 memcpy(to_sign, auth_data, auth_data_len);
2067 memcpy(to_sign + auth_data_len,
g_ctap2.assertion_client_data_hash, 32);
2068 uint16_t to_sign_len = auth_data_len + 32;
2070 uint8_t signature[128];
2081 LOG_E(
TAG,
"Failed to get credential ID for slot %d", slot);
2124 int ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1,
2148 const uint8_t *platform_key_y,
2149 uint8_t pin_protocol,
2150 uint8_t *shared_secret) {
2153 mbedtls_ecp_point platform_point;
2154 mbedtls_mpi shared_x;
2156 mbedtls_ecp_point_init(&platform_point);
2157 mbedtls_mpi_init(&shared_x);
2162 ret = mbedtls_mpi_read_binary(&platform_point.MBEDTLS_PRIVATE(X), platform_key_x, 32);
2163 if (ret != 0)
goto cleanup;
2165 ret = mbedtls_mpi_read_binary(&platform_point.MBEDTLS_PRIVATE(Y), platform_key_y, 32);
2166 if (ret != 0)
goto cleanup;
2168 ret = mbedtls_mpi_lset(&platform_point.MBEDTLS_PRIVATE(Z), 1);
2169 if (ret != 0)
goto cleanup;
2172 ret = mbedtls_ecdh_compute_shared(&
g_client_pin.ecdh_key.MBEDTLS_PRIVATE(grp),
2184 ret = mbedtls_mpi_write_binary(&shared_x, ecdh_z, 32);
2185 if (ret != 0)
goto cleanup;
2189 LOG_I(
TAG_PIN,
"=== ECDH DEBUG (full 32-byte values) ===");
2191 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2192 ecdh_z[0], ecdh_z[1], ecdh_z[2], ecdh_z[3], ecdh_z[4], ecdh_z[5], ecdh_z[6], ecdh_z[7],
2193 ecdh_z[8], ecdh_z[9], ecdh_z[10], ecdh_z[11], ecdh_z[12], ecdh_z[13], ecdh_z[14], ecdh_z[15]);
2194 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2195 ecdh_z[16], ecdh_z[17], ecdh_z[18], ecdh_z[19], ecdh_z[20], ecdh_z[21], ecdh_z[22], ecdh_z[23],
2196 ecdh_z[24], ecdh_z[25], ecdh_z[26], ecdh_z[27], ecdh_z[28], ecdh_z[29], ecdh_z[30], ecdh_z[31]);
2199 if (pin_protocol == 1) {
2202 mbedtls_sha256(ecdh_z, 32, shared_secret, 0);
2207 const char *info =
"CTAP2 AES key";
2209 uint8_t zero_salt[32] = {0};
2212 mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
2213 zero_salt, 32, ecdh_z, 32, prk);
2216 uint8_t expand_input[32];
2217 size_t info_len = strlen(info);
2218 memcpy(expand_input, info, info_len);
2219 expand_input[info_len] = 0x01;
2222 LOG_I(
TAG_PIN,
"HKDF PRK (HMAC-SHA256(salt=0, IKM=Z)):");
2223 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2224 prk[0], prk[1], prk[2], prk[3], prk[4], prk[5], prk[6], prk[7],
2225 prk[8], prk[9], prk[10], prk[11], prk[12], prk[13], prk[14], prk[15]);
2226 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2227 prk[16], prk[17], prk[18], prk[19], prk[20], prk[21], prk[22], prk[23],
2228 prk[24], prk[25], prk[26], prk[27], prk[28], prk[29], prk[30], prk[31]);
2229 LOG_I(
TAG_PIN,
"HKDF info: '%s' || 0x01 (len=%zu)", info, info_len + 1);
2232 mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
2233 prk, 32, expand_input, info_len + 1, shared_secret);
2238 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2239 shared_secret[0], shared_secret[1], shared_secret[2], shared_secret[3],
2240 shared_secret[4], shared_secret[5], shared_secret[6], shared_secret[7],
2241 shared_secret[8], shared_secret[9], shared_secret[10], shared_secret[11],
2242 shared_secret[12], shared_secret[13], shared_secret[14], shared_secret[15]);
2243 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2244 shared_secret[16], shared_secret[17], shared_secret[18], shared_secret[19],
2245 shared_secret[20], shared_secret[21], shared_secret[22], shared_secret[23],
2246 shared_secret[24], shared_secret[25], shared_secret[26], shared_secret[27],
2247 shared_secret[28], shared_secret[29], shared_secret[30], shared_secret[31]);
2252 mbedtls_ecp_point_free(&platform_point);
2253 mbedtls_mpi_free(&shared_x);
2267 const uint8_t *input,
size_t len, uint8_t *output) {
2268 mbedtls_aes_context aes;
2269 mbedtls_aes_init(&aes);
2271 uint8_t iv_copy[16];
2272 memcpy(iv_copy, iv, 16);
2274 int ret = mbedtls_aes_setkey_dec(&aes, key, 256);
2276 mbedtls_aes_free(&aes);
2280 ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, iv_copy, input, output);
2281 mbedtls_aes_free(&aes);
2294 size_t len, uint8_t *output) {
2295 uint8_t iv[16] = {0};
2308 size_t len, uint8_t *output) {
2309 mbedtls_aes_context aes;
2310 mbedtls_aes_init(&aes);
2312 uint8_t iv[16] = {0};
2314 int ret = mbedtls_aes_setkey_enc(&aes, key, 256);
2316 mbedtls_aes_free(&aes);
2320 ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, iv, input, output);
2321 mbedtls_aes_free(&aes);
2334 size_t len, uint8_t *output) {
2335 mbedtls_aes_context aes;
2336 mbedtls_aes_init(&aes);
2343 memcpy(output, iv, 16);
2345 int ret = mbedtls_aes_setkey_enc(&aes, key, 256);
2347 mbedtls_aes_free(&aes);
2352 ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, iv, input, output + 16);
2353 mbedtls_aes_free(&aes);
2396 uint8_t pub_x[32], pub_y[32];
2397 mbedtls_mpi_write_binary(&
g_client_pin.ecdh_key.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), pub_x, 32);
2398 mbedtls_mpi_write_binary(&
g_client_pin.ecdh_key.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), pub_y, 32);
2402 LOG_I(
TAG_PIN,
"X: %02X%02X%02X%02X %02X%02X%02X%02X...",
2403 pub_x[0], pub_x[1], pub_x[2], pub_x[3], pub_x[4], pub_x[5], pub_x[6], pub_x[7]);
2404 LOG_I(
TAG_PIN,
"Y: %02X%02X%02X%02X %02X%02X%02X%02X...",
2405 pub_y[0], pub_y[1], pub_y[2], pub_y[3], pub_y[4], pub_y[5], pub_y[6], pub_y[7]);
2452 uint8_t *response, uint16_t *response_len) {
2462 LOG_E(
TAG_PIN,
"FIDO2 hash not available - user must reset PIN");
2472 uint8_t platform_key_x[32] = {0};
2473 uint8_t platform_key_y[32] = {0};
2474 uint8_t pin_hash_enc[64] = {0};
2475 size_t pin_hash_enc_len = 0;
2476 uint8_t pin_protocol = 2;
2477 bool has_key =
false, has_pin =
false;
2486 for (
int i = 0; i < map_size; i++) {
2496 key = (int64_t)item.value;
2498 key = -1 - (int64_t)item.value;
2511 pin_protocol = (uint8_t)proto;
2512 LOG_I(
TAG_PIN,
"Client requested protocol: %d", pin_protocol);
2519 if (cose_size < 0)
break;
2520 for (
int j = 0; j < cose_size; j++) {
2522 cbor_item_t cose_item;
2530 cose_key = (int64_t)cose_item.value;
2532 cose_key = -1 - (int64_t)cose_item.value;
2534 LOG_E(
TAG_PIN,
"Unexpected COSE key type: %d", cose_item.type);
2558 if (
cbor_read_bytes(&r, pin_hash_enc,
sizeof(pin_hash_enc), &pin_hash_enc_len)) {
2559 LOG_D(
TAG_PIN,
"pinHashEnc read OK, len=%zu", pin_hash_enc_len);
2560 if (pin_hash_enc_len == 16 || pin_hash_enc_len == 32 || pin_hash_enc_len == 64) {
2562 LOG_D(
TAG_PIN,
"Got pinHashEnc (%zu bytes)", pin_hash_enc_len);
2564 LOG_E(
TAG_PIN,
"pinHashEnc unexpected size: %zu", pin_hash_enc_len);
2577 if (!has_key || !has_pin) {
2586 LOG_I(
TAG_PIN,
"Received pinHashEnc (%zu bytes):", pin_hash_enc_len);
2587 for (
size_t i = 0; i < pin_hash_enc_len; i += 16) {
2588 size_t row_len = (pin_hash_enc_len - i < 16) ? (pin_hash_enc_len - i) : 16;
2591 for (
size_t j = 0; j < row_len; j++) {
2592 p += sprintf(p,
"%02X ", pin_hash_enc[i + j]);
2599 uint8_t shared_secret[32];
2609 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2610 platform_key_x[0], platform_key_x[1], platform_key_x[2], platform_key_x[3],
2611 platform_key_x[4], platform_key_x[5], platform_key_x[6], platform_key_x[7],
2612 platform_key_x[8], platform_key_x[9], platform_key_x[10], platform_key_x[11],
2613 platform_key_x[12], platform_key_x[13], platform_key_x[14], platform_key_x[15]);
2614 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2615 platform_key_x[16], platform_key_x[17], platform_key_x[18], platform_key_x[19],
2616 platform_key_x[20], platform_key_x[21], platform_key_x[22], platform_key_x[23],
2617 platform_key_x[24], platform_key_x[25], platform_key_x[26], platform_key_x[27],
2618 platform_key_x[28], platform_key_x[29], platform_key_x[30], platform_key_x[31]);
2620 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2621 platform_key_y[0], platform_key_y[1], platform_key_y[2], platform_key_y[3],
2622 platform_key_y[4], platform_key_y[5], platform_key_y[6], platform_key_y[7],
2623 platform_key_y[8], platform_key_y[9], platform_key_y[10], platform_key_y[11],
2624 platform_key_y[12], platform_key_y[13], platform_key_y[14], platform_key_y[15]);
2625 LOG_I(
TAG_PIN,
" %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2626 platform_key_y[16], platform_key_y[17], platform_key_y[18], platform_key_y[19],
2627 platform_key_y[20], platform_key_y[21], platform_key_y[22], platform_key_y[23],
2628 platform_key_y[24], platform_key_y[25], platform_key_y[26], platform_key_y[27],
2629 platform_key_y[28], platform_key_y[29], platform_key_y[30], platform_key_y[31]);
2635 uint8_t decrypted_pin_hash[16];
2637 if (pin_protocol == 2 && pin_hash_enc_len == 32) {
2639 const uint8_t *iv = pin_hash_enc;
2640 const uint8_t *ciphertext = pin_hash_enc + 16;
2642 LOG_D(
TAG_PIN,
"Protocol 2 IV: %02X%02X%02X%02X %02X%02X%02X%02X...",
2643 iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);
2644 LOG_D(
TAG_PIN,
"Ciphertext: %02X%02X%02X%02X %02X%02X%02X%02X...",
2645 ciphertext[0], ciphertext[1], ciphertext[2], ciphertext[3],
2646 ciphertext[4], ciphertext[5], ciphertext[6], ciphertext[7]);
2656 uint8_t decrypted[64];
2663 memcpy(decrypted_pin_hash, decrypted, 16);
2667 LOG_D(
TAG_PIN,
"Decrypted PIN hash: %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2668 decrypted_pin_hash[0], decrypted_pin_hash[1], decrypted_pin_hash[2], decrypted_pin_hash[3],
2669 decrypted_pin_hash[4], decrypted_pin_hash[5], decrypted_pin_hash[6], decrypted_pin_hash[7],
2670 decrypted_pin_hash[8], decrypted_pin_hash[9], decrypted_pin_hash[10], decrypted_pin_hash[11],
2671 decrypted_pin_hash[12], decrypted_pin_hash[13], decrypted_pin_hash[14], decrypted_pin_hash[15]);
2674 uint8_t stored_hash[16];
2676 LOG_D(
TAG_PIN,
"Stored FIDO2 hash: %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2677 stored_hash[0], stored_hash[1], stored_hash[2], stored_hash[3],
2678 stored_hash[4], stored_hash[5], stored_hash[6], stored_hash[7],
2679 stored_hash[8], stored_hash[9], stored_hash[10], stored_hash[11],
2680 stored_hash[12], stored_hash[13], stored_hash[14], stored_hash[15]);
2683 uint8_t test_full[32];
2684 sha256((
const uint8_t*)
"0000", 4, test_full);
2685 LOG_D(
TAG_PIN,
"Expected for 0000: %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
2686 test_full[0], test_full[1], test_full[2], test_full[3],
2687 test_full[4], test_full[5], test_full[6], test_full[7],
2688 test_full[8], test_full[9], test_full[10], test_full[11],
2689 test_full[12], test_full[13], test_full[14], test_full[15]);
2715 size_t encrypted_len;
2717 if (pin_protocol == 2) {
2724 LOG_D(
TAG_PIN,
"Encrypted pinToken (Protocol 2, %zu bytes with IV)", encrypted_len);
2732 LOG_D(
TAG_PIN,
"Encrypted pinToken (Protocol 1, %zu bytes)", encrypted_len);
2752 LOG_I(
TAG_PIN,
"PIN verified, token issued (legacy, all permissions)");
2765 uint8_t *response, uint16_t *response_len) {
2775 LOG_E(
TAG_PIN,
"FIDO2 hash not available - user must reset PIN");
2785 uint8_t platform_key_x[32] = {0};
2786 uint8_t platform_key_y[32] = {0};
2787 uint8_t pin_hash_enc[64] = {0};
2788 size_t pin_hash_enc_len = 0;
2789 uint8_t pin_protocol = 2;
2790 uint8_t permissions = 0;
2791 char rp_id[64] = {0};
2792 bool has_key =
false, has_pin =
false, has_permissions =
false;
2801 for (
int i = 0; i < map_size; i++) {
2807 key = (int64_t)item.value;
2809 key = -1 - (int64_t)item.value;
2819 pin_protocol = (uint8_t)proto;
2825 if (cose_size < 0)
break;
2826 for (
int j = 0; j < cose_size; j++) {
2827 cbor_item_t cose_item;
2832 cose_key = (int64_t)cose_item.value;
2834 cose_key = -1 - (int64_t)cose_item.value;
2855 if (
cbor_read_bytes(&r, pin_hash_enc,
sizeof(pin_hash_enc), &pin_hash_enc_len)) {
2856 if (pin_hash_enc_len == 16 || pin_hash_enc_len == 32 || pin_hash_enc_len == 64) {
2865 permissions = (uint8_t)perm;
2866 has_permissions =
true;
2867 LOG_I(
TAG_PIN,
"Requested permissions: 0x%02X", permissions);
2884 if (!has_key || !has_pin) {
2891 if (!has_permissions) {
2899 uint8_t shared_secret[32];
2907 uint8_t decrypted_pin_hash[16];
2908 if (pin_protocol == 2 && pin_hash_enc_len == 32) {
2909 const uint8_t *iv = pin_hash_enc;
2910 const uint8_t *ciphertext = pin_hash_enc + 16;
2918 uint8_t decrypted[64];
2925 memcpy(decrypted_pin_hash, decrypted, 16);
2953 size_t encrypted_len;
2955 if (pin_protocol == 2) {
2981 LOG_I(
TAG_PIN,
"PIN verified, token issued with permissions=0x%02X", permissions);
2994 uint8_t *response, uint16_t *response_len) {
3013 uint64_t pin_protocol = 0;
3014 uint64_t sub_command = 0;
3016 for (
int i = 0; i < map_size; i++) {
3022 }
else if (key == 0x02) {
3029 LOG_I(
TAG_PIN,
"ClientPIN: protocol=%llu, subCommand=0x%02llx", pin_protocol, sub_command);
3038 switch (sub_command) {
3059 LOG_W(
TAG_PIN,
"Unknown subCommand: 0x%02lx", sub_command);
3087 LOG_I(
TAG,
"Factory reset complete");
3100 LOG_W(
TAG,
"credMgmt: skipping slot %d (no SE key)", slot);
3118 fido2_credential_info_t info;
3124 for (uint8_t j = 0; j < count; j++) {
3125 if (memcmp(unique_hashes[j], info.rp_id_hash, 32) == 0) {
3132 memcpy(unique_hashes[count], info.rp_id_hash, 32);
3152 fido2_credential_info_t info;
3155 if (memcmp(info.rp_id_hash,
rp_id_hash, 32) != 0)
continue;
3172 fido2_credential_info_t info;
3189 if (include_total) {
3205 fido2_credential_info_t info;
3222 if (info.user_name[0]) {
3245 if (include_total) {
3266 uint8_t *response, uint16_t *response_len) {
3268 if (params_len < 1) {
3278 if (map_count < 1) {
3284 uint8_t subcommand = 0;
3286 bool has_rp_id_hash =
false;
3288 uint16_t cred_id_len = 0;
3289 bool has_cred_id =
false;
3292 for (
int i = 0; i < map_count; i++) {
3304 subcommand = (uint8_t)cmd;
3312 for (
int j = 0; j < sub_count; j++) {
3323 has_rp_id_hash =
true;
3327 for (
int k = 0; k < cred_map; k++) {
3331 if (strcmp(cred_key,
"id") == 0) {
3365 LOG_I(
TAG,
"credMgmt subCmd=0x%02X", subcommand);
3378 switch (subcommand) {
3382 uint8_t existing = 0;
3397 LOG_I(
TAG,
"credMgmt metadata: %d existing, %d remaining",
3443 if (!has_rp_id_hash) {
3510 LOG_I(
TAG,
"credMgmt deleted credential slot %d", slot);
3565 uint8_t protocol,
const uint8_t *param,
3566 size_t param_len, uint8_t required_perm) {
3571 if (required_perm &&
g_client_pin.token_permissions != 0 &&
3575 uint8_t expected[32];
3576 mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
3578 msg, msg_len, expected);
3579 size_t compare_len = (protocol == 2) ? 32 : 16;
3580 if (param_len < compare_len || memcmp(param, expected, compare_len) != 0) {
3607 uint8_t *response, uint16_t *response_len) {
3615 bool has_get =
false, has_set =
false, has_offset =
false, has_length =
false;
3616 uint64_t get_len = 0, total_len = 0, offset = 0, pin_proto = 0;
3618 uint8_t pin_auth[64];
3619 size_t pin_auth_len = 0;
3621 for (
int i = 0; i < n; i++) {
3632 set_len = l; has_set =
true;
break;
3641 pin_auth_len = l;
break;
3651 if (has_get == has_set || !has_offset) {
3656 uint16_t stored_len = 0;
3660 if (offset > stored_len) {
3663 uint16_t avail = stored_len -
static_cast<uint16_t
>(offset);
3664 uint16_t chunk = (get_len < avail) ? static_cast<uint16_t>(get_len) : avail;
3686 response[0] = st; *response_len = 1;
return st;
3689 response[0] = CTAP1_ERR_INVALID_SEQ; *response_len = 1; return CTAP1_ERR_INVALID_SEQ;
3694 uint8_t msg[32 + 1 + 1 + 4 + 32];
3695 memset(msg, 0xff, 32);
3698 msg[34] =
static_cast<uint8_t
>(offset & 0xff);
3699 msg[35] =
static_cast<uint8_t
>((offset >> 8) & 0xff);
3700 msg[36] =
static_cast<uint8_t
>((offset >> 16) & 0xff);
3701 msg[37] =
static_cast<uint8_t
>((offset >> 24) & 0xff);
3707 response[0] = st; *response_len = 1;
return st;
3713 static_cast<uint16_t
>(set_len)));
3716 response[0] = st; *response_len = 1;
return st;
3723 sha256(blob, blob_len - 16, sum);
3724 if (memcmp(sum, blob + blob_len - 16, 16) != 0) {
3747 uint8_t *response, uint16_t *response_len) {
3755 uint64_t subcmd = 0, pin_proto = 0;
3756 bool has_sub =
false;
3757 const uint8_t *sub_params =
nullptr;
3758 size_t sub_params_len = 0;
3759 uint8_t pin_auth[64];
3760 size_t pin_auth_len = 0;
3762 for (
int i = 0; i < n; i++) {
3771 size_t start = r.offset;
3773 sub_params = params + start;
3774 sub_params_len = r.offset - start;
3782 pin_auth_len = l;
break;
3802 if (sub_params_len > 256) {
3805 uint8_t msg[32 + 1 + 1 + 256];
3806 memset(msg, 0xff, 32);
3808 msg[33] =
static_cast<uint8_t
>(subcmd);
3809 if (sub_params_len) memcpy(msg + 34, sub_params, sub_params_len);
3813 response[0] = st; *response_len = 1;
return st;
3827 uint64_t new_min = 0;
3828 bool has_new_min =
false;
3829 if (sub_params && sub_params_len) {
3833 for (
int i = 0; i < sn; i++) {
3882 uint8_t *response, uint16_t *response_len) {
3883 if (!
g_ctap2.initialized || cmd_len < 1) {
3889 uint8_t command = cmd[0];
3890 const uint8_t *params = cmd + 1;
3891 uint16_t params_len = cmd_len - 1;
3894 const char *cmd_name =
"?";
3907 LOG_I(
TAG,
"CMD 0x%02X (%s) %d bytes", command, cmd_name, params_len);
3909 g_ctap2.operation_pending =
true;
3951 status =
ctap2_config(params, params_len, response, response_len);
3961 g_ctap2.operation_pending =
false;
Portable authenticatorLargeBlobs write-session accumulator and the canonical empty large-blob array c...
void cbor_encode_cose_key_p256(cbor_writer_t *w, const uint8_t *x, const uint8_t *y)
Encodes COSE P-256 public key map.
void cbor_encode_uint(cbor_writer_t *w, uint64_t value)
Encodes CBOR unsigned integer.
void cbor_encode_bool(cbor_writer_t *w, bool value)
Encodes CBOR boolean.
void cbor_encode_cose_key_ed25519(cbor_writer_t *w, const uint8_t *pubkey)
Encodes COSE Ed25519 public key map.
void cbor_writer_init(cbor_writer_t *w, uint8_t *buffer, size_t size)
CBOR writer implementation.
void cbor_encode_text(cbor_writer_t *w, const char *str)
Encodes CBOR text string.
size_t cbor_writer_length(const cbor_writer_t *w)
Returns number of bytes written by CBOR writer.
bool cbor_writer_error(const cbor_writer_t *w)
Returns whether writer encountered an error.
void cbor_encode_bytes(cbor_writer_t *w, const uint8_t *data, size_t len)
Encodes CBOR byte-string.
void cbor_encode_array(cbor_writer_t *w, size_t count)
Encodes CBOR array header.
void cbor_encode_int(cbor_writer_t *w, int64_t value)
Encodes CBOR signed integer.
void cbor_encode_map(cbor_writer_t *w, size_t count)
Encodes CBOR map header.
void cbor_reader_init(cbor_reader_t *r, const uint8_t *data, size_t size)
CBOR reader implementation.
bool cbor_read_text(cbor_reader_t *r, char *out, size_t max_len, size_t *out_len)
Reads CBOR text string into output buffer.
int cbor_read_map(cbor_reader_t *r)
Reads CBOR map header and returns pair count.
int cbor_read_array(cbor_reader_t *r)
Reads CBOR array header and returns element count.
bool cbor_skip_item(cbor_reader_t *r)
Skips one complete CBOR item including nested container content.
bool cbor_read_bool(cbor_reader_t *r, bool *value)
Reads CBOR boolean simple value.
bool cbor_read_item(cbor_reader_t *r, cbor_item_t *item)
Reads next CBOR item metadata and optional inline payload pointer.
bool cbor_read_int(cbor_reader_t *r, int64_t *value)
Reads CBOR integer (positive or negative).
bool cbor_read_uint(cbor_reader_t *r, uint64_t *value)
Reads CBOR unsigned integer.
bool cbor_read_bytes(cbor_reader_t *r, uint8_t *out, size_t max_len, size_t *out_len)
Reads CBOR byte-string into optional output buffer.
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
#define LOG_D(tag, fmt,...)
#define LOG_I(tag, fmt,...)
#define LOG_E(tag, fmt,...)
static constexpr uint8_t BADGE_PIN_MAX
static constexpr uint8_t BADGE_PIN_MIN
Accumulates an offset-chunked authenticatorLargeBlobs write into a caller-owned buffer.
#define PIN_CMD_GET_PIN_TOKEN
void sha256_str(const char *str, uint8_t out[32])
#define PIN_PERM_LARGE_BLOB_WRITE
static bool cred_mgmt_encode_rp(cbor_writer_t *w, uint8_t slot, bool include_total)
Encodes a credential-management RP response entry.
uint8_t ctap2_reset(uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorReset (0x07).
bool assertion_appid_used
static uint16_t ctap2_build_cred_protect_extension(uint8_t level, uint8_t *out, size_t out_size)
Builds CBOR payload for the credProtect extension.
static void ga_find_credentials(GetAssertionParams *p, AssertionCredentials *creds)
Finds credentials matching RP/allowList and appid extension rules.
static constexpr uint64_t CTAP2_INFO_PIN_UV_AUTH_PROTOCOL_VALUE
Reported PIN/UV auth protocol version (Protocol Two).
#define PIN_CMD_GET_PIN_UV_TOKEN
uint8_t ctap2_client_pin(const uint8_t *params, uint16_t params_len, uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorClientPIN (0x06).
static bool cred_mgmt_slot_has_key(uint8_t slot)
Credential-management helper and command implementation.
static void encode_info_transports(cbor_writer_t *w)
Encodes the supported transports list.
void ctap2_cancel(void)
Marks current CTAP2 operation as cancelled.
uint8_t ctap2_process_command(const uint8_t *cmd, uint16_t cmd_len, uint8_t *response, uint16_t *response_len)
Dispatches one CTAP2 command and writes response payload.
mbedtls_ecp_keypair ecdh_key
void ctap2_clear_cancel(void)
Clears any latched cancel flag. Called at the start of a new CTAPHID channel (INIT) so a cancel from ...
#define PIN_CMD_GET_KEY_AGREEMENT
static uint8_t ga_build_response(const uint8_t *cred_id, const uint8_t *auth_data, uint16_t auth_data_len, const uint8_t *signature, uint8_t sig_len, const fido2_credential_info_t *cred, bool include_user, uint8_t total_creds, uint8_t *response, uint16_t *response_len)
Builds CBOR response payload for getAssertion/getNextAssertion.
static const uint8_t AAGUID[16]
Authenticator Attestation GUID for this authenticator model.
static void encode_info_min_pin_length(cbor_writer_t *w)
Encodes the current minPINLength policy floor.
static bool client_pin_compute_shared_secret(const uint8_t *platform_key_x, const uint8_t *platform_key_y, uint8_t pin_protocol, uint8_t *shared_secret)
Computes ClientPIN shared secret from platform ECDH public key.
static uint8_t g_large_blob_buf[cdc::mod_fido2::kLargeBlobMaxArray]
static void encode_info_versions(cbor_writer_t *w)
Encodes the supported FIDO/U2F versions into the getInfo CBOR map.
uint8_t assertion_creds[32]
static void encode_info_options(cbor_writer_t *w)
Encodes the supported authenticator options, keys sorted by length.
static void encode_info_max_msg_size(cbor_writer_t *w)
Encodes the maxMsgSize entry into the getInfo CBOR map.
static bool wait_for_user_presence(const char *rp_id, fido2_action_t action, const char *user_name)
Requests user-presence confirmation through platform callback.
static uint8_t build_authenticator_data(const uint8_t *rp_id_hash, uint8_t flags, uint32_t sign_count, const uint8_t *attested_cred_data, uint16_t attested_cred_len, const uint8_t *ext_data, uint16_t ext_len, uint8_t *out, uint16_t *out_len)
Builds raw authenticatorData structure.
static void secure_random_fill(uint8_t *out, size_t len)
Fills a buffer with cryptographically secure random bytes.
static uint8_t ga_parse_extensions(cbor_reader_t *r, GetAssertionParams *p)
Parses getAssertion extensions (map key 0x04).
#define PIN_PERM_AUTHN_CONFIG
static uint8_t cred_mgmt_find_creds_for_rp(const uint8_t *rp_id_hash)
Collects resident credentials for the given RP ID hash.
static uint8_t client_pin_get_retries(uint8_t *response, uint16_t *response_len)
Handles ClientPIN subcommand getPINRetries (0x01).
bool ctap2_init(void)
Initializes CTAP2 runtime state.
static void encode_info_max_large_blob(cbor_writer_t *w)
Encodes the maxSerializedLargeBlobArray entry.
uint8_t token_permissions
static struct @345050366056176050043354151136135170030316236203 g_client_pin
static bool ctap2_build_auth_data_for_cred(const uint8_t *rp_id_hash, const uint8_t *attested_cred, uint16_t attested_len, uint8_t cred_protect, uint8_t *auth_data, uint16_t *auth_data_len)
Builds authenticator data for makeCredential with optional credProtect extension.
static uint8_t client_pin_get_pin_token(const uint8_t *params, uint16_t params_len, uint8_t *response, uint16_t *response_len)
Handles ClientPIN subcommand getPinToken (0x05).
static bool aes_256_cbc_encrypt(const uint8_t *key, const uint8_t *input, size_t len, uint8_t *output)
Encrypts Protocol-1 PIN payload (AES-256-CBC with zero IV).
#define CRED_MGMT_ENUMERATE_RPS_GET_NEXT
#define PIN_PROTOCOL_VERSION
ClientPIN constants and state for PIN protocol support.
static uint8_t client_pin_get_pin_uv_auth_token(const uint8_t *params, uint16_t params_len, uint8_t *response, uint16_t *response_len)
Handles ClientPIN subcommand getPinUvAuthTokenUsingPinWithPermissions (0x09).
uint8_t ctap2_selection(uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorSelection (0x0B).
bool ctap2_is_cancelled(void)
Returns true if the current CTAP2 operation has been cancelled.
static constexpr uint64_t CTAP2_INFO_MAX_CRED_LIST_COUNT_VALUE
Reported maxCredentialCountInList for authenticatorGetInfo.
uint8_t assertion_rp_id_hash[32]
static uint16_t ctap2_build_appid_extension(uint8_t *out, size_t out_size)
Builds CBOR payload for appid extension in assertions.
uint8_t ctap2_large_blobs(const uint8_t *params, uint16_t params_len, uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorLargeBlobs (0x0C).
static bool client_pin_init_ecdh(void)
ClientPIN command implementation helpers.
uint8_t ctap2_config(const uint8_t *params, uint16_t params_len, uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorConfig (0x0D).
#define CRED_MGMT_GET_CREDS_METADATA
Credential management constants and enumeration state.
uint8_t current_rp_id_hash[32]
static uint8_t lb_status(cdc::mod_fido2::LbResult r)
Maps a LargeBlobWriteSession result to a CTAP status.
static uint8_t cred_mgmt_count_unique_rps(void)
Counts unique RP IDs among resident credentials.
#define PIN_UV_RETRIES_MAX
void sha256(const uint8_t *data, size_t len, uint8_t out[32])
static struct @363146237155063244362205253337222300366302103074 g_ctap2
Global CTAP2 runtime state.
static uint8_t ga_parse_allow_list(cbor_reader_t *r, GetAssertionParams *p)
Parses getAssertion allowList (map key 0x03).
static struct @074350050112271276332254352137370356012162354162 g_cred_mgmt
#define CRED_MGMT_ENUMERATE_CREDS_BEGIN
static constexpr uint64_t CTAP2_INFO_MAX_MSG_SIZE_VALUE
Reported maximum message size for authenticatorGetInfo.
static int ctap2_random(void *ctx, unsigned char *out, size_t len)
mbedTLS RNG callback backed by secure random source.
#define CRED_MGMT_ENUMERATE_CREDS_GET_NEXT
static const char * TAG_PIN
uint8_t token_rp_id_hash[32]
static bool ctap2_build_attested_cred(const uint8_t *cred_id, uint16_t cred_id_len, const uint8_t *pubkey, uint8_t curve, uint8_t *out, size_t out_size, uint16_t *out_len)
Builds attested credential data (AAGUID, credential ID, COSE key).
static bool aes_256_cbc_encrypt_p2(const uint8_t *key, const uint8_t *input, size_t len, uint8_t *output)
Encrypts Protocol-2 PIN payload and prefixes random IV (IV || ciphertext).
static uint8_t ga_sign_assertion(uint8_t slot, const uint8_t *auth_data, uint16_t auth_data_len, const uint8_t *client_data_hash, uint8_t *signature, uint8_t *sig_len)
Signs assertion message (authData || clientDataHash) for one credential slot.
static uint8_t ga_parse_params(const uint8_t *params, uint16_t params_len, GetAssertionParams *p)
Parses complete getAssertion request map from CBOR payload.
static bool cred_mgmt_encode_credential(cbor_writer_t *w, uint8_t slot, bool include_total)
Encodes a credential-management credential response entry.
static void encode_info_pin_uv_auth_protocols(cbor_writer_t *w)
Encodes the supported pinUvAuthProtocols list.
static void encode_info_aaguid(cbor_writer_t *w)
Encodes the authenticator AAGUID into the getInfo CBOR map.
void ctap2_send_keepalive(uint8_t status)
Sends CTAPHID keepalive for currently active channel.
uint8_t ctap2_get_assertion(const uint8_t *params, uint16_t params_len, uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorGetAssertion (0x02).
#define PIN_CMD_GET_RETRIES
ClientPIN subcommand identifiers.
static bool ctap2_sign_with_keypair(mbedtls_ecp_keypair *key, const uint8_t *msg, size_t msg_len, uint8_t *sig, size_t sig_size, size_t *sig_len)
Signs message using provided keypair (ECDSA over SHA-256).
uint8_t ctap2_cred_management(const uint8_t *params, uint16_t params_len, uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorCredentialManagement (0x0A).
static void encode_info_algorithms(cbor_writer_t *w)
Encodes the supported algorithms array (PublicKeyCredentialParameters).
static bool aes_256_cbc_decrypt_iv(const uint8_t *key, const uint8_t *iv, const uint8_t *input, size_t len, uint8_t *output)
Decrypts data using AES-256-CBC with caller-provided IV.
#define CRED_MGMT_DELETE_CREDENTIAL
static bool ctap2_generate_ephemeral_keypair(mbedtls_ecp_keypair *key, uint8_t pubkey[64])
Generates ephemeral P-256 key pair and exports 64-byte X||Y public key.
#define CTAP2_DEBUG_COMMANDS
uint8_t assertion_client_data_hash[32]
static uint8_t ga_verify_pin_auth(const GetAssertionParams *p, bool *uv_verified)
Verifies getAssertion pinUvAuthParam via HMAC.
static uint8_t ctap2_build_make_credential_response_packed(const uint8_t *auth_data, uint16_t auth_data_len, const uint8_t *sig, uint8_t sig_len, const uint8_t *cert, uint16_t cert_len, uint8_t *response, uint16_t *response_len)
Builds packed-attestation makeCredential response CBOR payload.
#define PIN_CMD_CHANGE_PIN
#define CRED_MGMT_ENUMERATE_RPS_BEGIN
static void encode_info_extensions(cbor_writer_t *w)
Encodes the supported CTAP extensions, sorted for CBOR canonical form.
static uint8_t client_pin_get_key_agreement(uint8_t *response, uint16_t *response_len)
Handles ClientPIN subcommand getKeyAgreement (0x02).
static void encode_info_max_cred_id_length(cbor_writer_t *w)
Encodes the maxCredentialIdLength entry.
static bool aes_256_cbc_decrypt(const uint8_t *key, const uint8_t *input, size_t len, uint8_t *output)
Decrypts Protocol-1 PIN payload (AES-256-CBC with zero IV).
static uint8_t verify_token_over_message(const uint8_t *msg, size_t msg_len, uint8_t protocol, const uint8_t *param, size_t param_len, uint8_t required_perm)
Verifies a pinUvAuthToken HMAC over an arbitrary message.
static void encode_info_max_cred_count(cbor_writer_t *w)
Encodes the maxCredentialCountInList entry.
uint8_t ctap2_get_next_assertion(uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorGetNextAssertion (0x08).
bool assertion_include_user
static bool ga_parse_allow_list_credential(cbor_reader_t *r, uint8_t *cred_id, size_t *cred_id_len)
Parses one allowList credential descriptor and extracts credential ID.
uint8_t ctap2_get_info(uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorGetInfo (0x04).
static const char * INFO_TRANSPORTS[]
Device info strings reported by authenticatorGetInfo.
static cdc::mod_fido2::LargeBlobWriteSession g_large_blob_session
static uint8_t ga_parse_options(cbor_reader_t *r, GetAssertionParams *p)
Parses getAssertion options (map key 0x05).
static uint8_t g_large_blob_chunk[cdc::mod_fido2::kLargeBlobMaxArray]
#define CTAP2_MC_RESP_AUTH_DATA
#define CTAP1_ERR_INVALID_PARAMETER
#define CTAP2_PIN_PROTOCOL
#define CTAP2_INFO_ALGORITHMS
#define CTAP2_CMD_GET_NEXT_ASSERTION
#define CTAP2_MC_PUB_KEY_CRED_PARAMS
#define CTAP2_INFO_MAX_CRED_ID_LENGTH
#define CTAP2_GA_ALLOW_LIST
#define CTAP2_ERR_PIN_REQUIRED
#define CTAP2_GA_RESP_AUTH_DATA
#define CTAP2_CMD_GET_INFO
#define CTAP2_CM_PIN_UV_AUTH_PROTOCOL
#define CTAP2_GA_RESP_USER
#define COSE_KEY_LABEL_ALG
#define CTAP1_ERR_INVALID_LENGTH
#define CTAP2_CMD_CLIENT_PIN
#define CTAP2_MC_CLIENT_DATA_HASH
#define CTAP2_LB_RESP_CONFIG
#define CTAP2_ERR_UNSUPPORTED_OPTION
#define CTAP2_INFO_MAX_MSG_SIZE
#define CTAP2_ERR_KEY_STORE_FULL
#define CTAP2_CM_SUB_RP_ID_HASH
#define CTAP2_INFO_PIN_UV_AUTH_PROTOCOLS
#define CTAP2_CM_RESP_PUBLIC_KEY
#define CTAP2_MC_RESP_FMT
#define COSE_ALG_ECDH_ES_HKDF_256
#define COSE_KEY_LABEL_CRV
#define CTAP2_MC_EXTENSIONS
#define CTAP2_PIN_RESP_PIN_RETRIES
#define CTAP2_CONFIG_SUBCOMMAND
#define CTAP2_INFO_MIN_PIN_LENGTH
#define CTAP2_ERR_PIN_NOT_SET
#define CTAP2_GA_CLIENT_DATA_HASH
#define CTAP2_LB_PIN_UV_AUTH_PROTOCOL
#define CTAP2_CONFIG_SUB_TOGGLE_ALWAYS_UV
#define CTAP2_INFO_EXTENSIONS
#define CTAP2_CM_RESP_CREDENTIAL_ID
#define CTAP2_CM_RESP_EXISTING_CRED_COUNT
#define CTAP2_PIN_PERMISSIONS_RPID
#define CTAP2_CM_RESP_USER
#define CTAP2_PIN_RESP_UV_RETRIES
#define CTAP2_ERR_OPERATION_DENIED
#define CTAP2_CONFIG_SUB_ENABLE_EP
#define CTAP2_ERR_PIN_BLOCKED
#define CTAP2_CMD_GET_ASSERTION
#define CTAP1_ERR_INVALID_SEQ
#define CTAP2_CMD_CRED_MANAGEMENT
#define CTAP2_INFO_TRANSPORTS
#define CTAP2_CONFIG_SUB_SET_MIN_PIN_LENGTH
#define CTAP2_CM_RESP_REMAINING_CRED_COUNT
#define CTAP2_CM_RESP_TOTAL_CREDENTIALS
#define CTAP1_ERR_INVALID_COMMAND
#define COSE_KEY_TYPE_EC2
#define CTAP2_CMD_LARGE_BLOBS
#define CTAP2_ERR_PIN_AUTH_INVALID
#define CTAP2_ERR_INTEGRITY_FAILURE
#define CTAP2_INFO_MAX_CRED_COUNT_IN_LIST
#define CTAP2_INFO_AAGUID
#define CTAP2_ERR_INVALID_OPTION
#define CTAP2_CMD_MAKE_CREDENTIAL
#define CTAP2_ERR_NO_CREDENTIALS
#define CTAP2_GA_PIN_UV_AUTH_PARAM
#define CTAP2_CM_SUBCOMMAND
#define CTAP2_ERR_PIN_INVALID
#define CTAP2_PIN_HASH_ENC
#define CTAP2_CM_PIN_UV_AUTH_PARAM
#define CTAP2_ERR_CREDENTIAL_EXCLUDED
#define CTAP2_CONFIG_PARAM_NEW_MIN_PIN_LEN
#define CTAP2_LB_PIN_UV_AUTH_PARAM
#define CTAP2_CM_RESP_TOTAL_RPS
#define CTAP2_CM_SUB_CREDENTIAL_ID
void ctap2_send_keepalive(uint8_t status)
Sends CTAPHID keepalive for currently active channel.
#define CTAP2_INFO_MAX_SERIALIZED_LARGE_BLOB_ARRAY
uint8_t ctap2_make_credential(const uint8_t *params, uint16_t params_len, uint8_t *response, uint16_t *response_len)
#define CTAP2_CM_SUBCOMMAND_PARAMS
#define CTAP2_ERR_MISSING_PARAMETER
#define CTAP2_CONFIG_PIN_UV_AUTH_PROTOCOL
#define CTAP2_CM_RESP_RP_ID_HASH
#define CTAP2_PIN_PERMISSIONS
#define CTAP2_GA_PIN_UV_AUTH_PROTOCOL
#define CTAP2_CONFIG_PIN_UV_AUTH_PARAM
#define CTAP2_MC_RESP_ATT_STMT
#define CTAP2_GA_EXTENSIONS
#define CTAP2_ERR_INVALID_CBOR
#define CTAP2_CM_RESP_CRED_PROTECT
#define CTAP2_INFO_OPTIONS
#define CTAP2_CONFIG_SUB_VENDOR_PROTOTYPE
#define CTAP2_PIN_RESP_KEY_AGREEMENT
#define CTAP2_MC_PIN_UV_AUTH_PROTOCOL
#define CTAP2_PIN_RESP_PIN_TOKEN
#define CTAP2_GA_RESP_NUMBER_OF_CREDS
#define CTAP2_ERR_LARGE_BLOB_STORAGE_FULL
#define CTAP2_ERR_NOT_ALLOWED
#define CTAP2_INFO_VERSIONS
#define CTAP2_GA_RESP_CREDENTIAL
#define CTAP2_CMD_SELECTION
#define CTAP2_PIN_KEY_AGREEMENT
#define CTAP2_GA_RESP_SIGNATURE
#define CTAP2_ERR_UNSUPPORTED_ALGORITHM
#define COSE_KEY_LABEL_KTY
#define CTAP2_CONFIG_SUBCOMMAND_PARAMS
#define CTAP2_MC_PIN_UV_AUTH_PARAM
uint32_t ctaphid_get_current_cid(void)
Returns the channel identifier of the currently processed request.
#define CTAPHID_STATUS_PROCESSING
#define CTAPHID_STATUS_UPNEEDED
void ctaphid_send_keepalive(uint32_t cid, uint8_t status)
Sends a CTAPHID KEEPALIVE packet immediately over USB.
#define CDC_CURVE_ED25519
#define FIDO2_MAX_CREDENTIALS
void fido2_set_pin_verified(bool verified)
Stores whether PIN verification was completed via ClientPIN.
#define FIDO2_CRED_ID_LEN
#define FIDO2_RP_ID_MAX_LEN
#define FIDO2_USER_NAME_MAX_LEN
void fido2_increment_auth_counter(void)
Increments global authentication counter.
fido2_user_presence_result_t fido2_request_user_presence(const char *rp_id, fido2_action_t action, const char *user_name)
Requests user presence from host/application callback.
fido2_user_presence_result_t
bool fido2_factory_reset(void)
Removes all credentials and resets FIDO2 data.
bool fido2_is_pin_verified(void)
Returns current PIN-verified state.
#define FIDO2_USER_ID_MAX_LEN
@ FIDO2_ACTION_AUTHENTICATE
struct @262231322003320050276064353325174062307231151161::@131310070117174352112321004206244146355206237313 creds[FIDO2_MAX_CREDENTIALS]
char rp_id[FIDO2_RP_ID_MAX_LEN]
char user_name[FIDO2_USER_NAME_MAX_LEN]
bool fido2_storage_largeblob_get(uint8_t *out, uint16_t max_len, uint16_t *out_len)
bool fido2_storage_get_always_uv(void)
bool fido2_storage_set_always_uv(bool enabled)
bool fido2_storage_largeblob_set(const uint8_t *data, uint16_t len)
bool fido2_storage_set_min_pin_len(uint8_t min_len)
bool fido2_storage_sign_raw(uint8_t slot, const uint8_t *msg, uint16_t msg_len, uint8_t *signature, uint8_t *sig_len)
Signs message and returns raw signature (EdDSA/ECDSA).
bool fido2_storage_get_credential(uint8_t slot, fido2_credential_info_t *info)
Credential create/read/delete operations.
uint8_t fido2_storage_get_min_pin_len(void)
bool fido2_storage_delete_credential(uint8_t slot)
Deletes credential and associated slot data.
bool fido2_storage_get_cred_id(uint8_t slot, uint8_t *out_cred_id)
Builds credential-id blob for logical slot.
int8_t fido2_storage_find_slot_by_cred_id(const uint8_t *cred_id, uint16_t cred_id_len)
Resolves and verifies logical slot from credential-id blob.
bool fido2_storage_get_pubkey(uint8_t slot, uint8_t *pubkey)
Reads public key from secure-element slot.
bool fido2_storage_create_credential(const char *rp_id, const uint8_t *rp_id_hash, const uint8_t *user_id, uint8_t user_id_len, const char *user_name, bool resident_key, uint8_t cred_protect, uint8_t curve, uint8_t *out_slot, uint8_t *out_cred_id, uint8_t *out_pubkey)
Creates or replaces credential in secure-element storage.
uint8_t fido2_storage_find_by_rp(const uint8_t *rp_id_hash, uint8_t *out_slots, uint8_t max_slots)
Finds credentials matching RP hash.
uint32_t fido2_storage_increment_sign_count(uint8_t slot)
Increments per-credential sign counter and persists metadata.
bool fido2_storage_is_resident(uint8_t slot)
Returns resident-key flag for slot.
int8_t fido2_storage_find_by_rp_user(const uint8_t *rp_id_hash, const uint8_t *user_id, uint8_t user_id_len)
Finds credential by RP hash and user handle for replacement logic.
ISecureElement * getSecureElementInstance()
Returns singleton secure-element stub instance.
void sha256_str(const char *str, uint8_t out[32])
static uint8_t parse_make_credential_params(const uint8_t *data, uint16_t data_len, MakeCredentialParams *p)
Parses complete makeCredential request map from CBOR payload.
static bool parse_options_map(cbor_reader_t *r, MakeCredentialParams *p)
Parses makeCredential options map from CBOR.
static uint8_t mc_rollback_credential(uint8_t slot, uint8_t *response, uint16_t *response_len)
Deletes a just-created credential and reports CTAP2_ERR_OTHER.
LbResult
Outcome of a write-session step, mapped to a CTAP status by the caller.
@ StorageFull
declared total length exceeds the buffer / kLargeBlobMaxArray
@ BadSeq
fragment offset out of order, or no active session
@ BadLength
declared total too small, or a fragment overruns the total
uint8_t ctap2_make_credential(const uint8_t *params, uint16_t params_len, uint8_t *response, uint16_t *response_len)
Handles CTAP2 authenticatorMakeCredential (0x01).
static bool is_browser_probe(const char *rp_id)
Detects known browser probe RP IDs.
static uint8_t create_credential_and_respond(const MakeCredentialParams *p, uint8_t curve, uint8_t *response, uint16_t *response_len)
Creates credential, signs attestation statement, and builds response.
static bool parse_rp_map(cbor_reader_t *r, MakeCredentialParams *p)
Parses the RP map from a makeCredential CBOR request.
static bool parse_user_map(cbor_reader_t *r, MakeCredentialParams *p)
Parses the user map from a makeCredential CBOR request.
void sha256(const uint8_t *data, size_t len, uint8_t out[32])
static bool parse_extensions_map(cbor_reader_t *r, MakeCredentialParams *p)
Parses makeCredential extensions map from CBOR.
constexpr uint16_t kLargeBlobMaxArray
Largest serialized large-blob array, advertised as maxSerializedLargeBlobArray.
static bool parse_pubkey_cred_params(cbor_reader_t *r, MakeCredentialParams *p)
Parses pubKeyCredParams and selects a supported algorithm.
static uint8_t verify_pin_uv_auth(const MakeCredentialParams *p)
Verifies pinUvAuthParam for makeCredential.
static uint8_t check_appid_exclude(const MakeCredentialParams *p)
Validates the appidExclude extension against existing credentials.
static uint8_t handle_browser_probe(const MakeCredentialParams *p, uint8_t *response, uint16_t *response_len)
Handles browser probe RP IDs by returning a synthetic attested response.
bool pin_storage_verify_fido2_hash(const uint8_t *hash_in)
bool pin_storage_fido2_available(void)
void pin_storage_set_min_pin_floor(uint8_t min_len)
bool pin_storage_get_fido2_hash(uint8_t *hash_out)
Credential-selection result used to build assertion responses.
Parsed parameters for authenticatorGetAssertion.
uint8_t client_data_hash[32]
size_t pin_uv_auth_param_len
uint8_t allow_list_slots[32]
uint8_t pin_uv_auth_protocol
uint8_t pin_uv_auth_param[32]
Parsed parameters for authenticatorMakeCredential.
uint8_t client_data_hash[32]
uint8_t pin_uv_auth_protocol
size_t pin_uv_auth_param_len
uint8_t pin_uv_auth_param[64]
bool u2f_get_attestation_cert(const uint8_t **cert, uint16_t *cert_len)
Returns attestation certificate pointer and length, initializing attestation on demand if the boot-ti...
bool u2f_attestation_sign(const uint8_t *data, size_t data_len, uint8_t *signature, uint8_t *sig_len)
Signs payload using the attestation key, initializing attestation on demand if the boot-time init did...