Skip to content

Commit

Permalink
Merge pull request #60 from canokeys/feature/fido2.1
Browse files Browse the repository at this point in the history
Feature/fido2.1
  • Loading branch information
dangfan authored Oct 25, 2023
2 parents c141e58 + b6dd99c commit 8d92f58
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 22 deletions.
2 changes: 1 addition & 1 deletion FIDO2 Conformance Testing.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"matcherProtection": ["on_chip"],
"tcDisplay": [],
"attestationRootCertificates": [
"MIIDMjCCAhqgAwIBAgIUAvaAGy8lEWimeNJniABYTEpv1GowDQYJKoZIhvcNAQELBQAwMTEvMC0GA1UEAwwmQ2Fub0tleXMgRklETyBBdHRlc3RhdGlvbiBSb290IENBIE5vLjEwHhcNMjAwNzA4MTEzNzMzWhcNNDAwMTA1MTEzNzMzWjAxMS8wLQYDVQQDDCZDYW5vS2V5cyBGSURPIEF0dGVzdGF0aW9uIFJvb3QgQ0EgTm8uMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK7eBQHp4sJBXOEM9JivpoQvS/neBPCdp2h36PGDzx6wZ5AP8UZOw5a+VFeresLm00qo5qWOJ2ajFlupjmXVpfsYnao1DDbI3ZDZkbIePj0NmnTProHr4N73gBGGaErKW+IURVGsvXAZcPz/qeGclo4ZFH4th6RZT4nJzOUd5rwB5ZNnqgxmhAziyz8MUb3dmYJpB/PC+5SRaCcW7hzKoxy9Wv4SJkCrf3V7YOix9VKqut4hIHDObHgzeoUDpw1makeRDD+I0ImKCxErVydSNXhcKF+8TDAM6S+ucD2Nj/xmrSB3P59ZIBYlGlrEZG5tbXs+KWXP5GH28jDlCzqzrMMCAwEAAaNCMEAwHQYDVR0OBBYEFLH58IKZ6u2YsgCKQdfbKILv3W1AMA8GA1UdEwQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQBoIU1j9srZqey3e1i3Ntu0Sa/co4ltDhHrl2FqZNAsVSjqD6sbDFjOO2gPWh/RhkbV0KYlFPqA7MC4KwIwBekWwZ0W5ZH+a4uEGjZqGAxym4Bae+qyHrsnBmKnwhKmQTbGmCrHWxObi8dq+cImBN/LmzWk7ImriNbTf/g/DwYLA/9FxD7O90KCW7yghXOsZhka8Z6o/5dqnIagMXeSimkPzwIdB53v4AObsguiD9aV5b1P62wymEFp1wImJoJsXQxls1AhTdAG2Yez0PjeN4l5im+px6owhDA3bcGbccdwLGj+5FClWa+Bi3Ekt5Sx9DQ8V7AnzQzpizcHkDr4tpmB"
"MIIBpzCCAUygAwIBAgIUatn9Rj8uCMjLrmFfCQYY5/X9xq4wCgYIKoZIzj0EAwIw\nMTEvMC0GA1UEAwwmQ2Fub0tleXMgRklETyBBdHRlc3RhdGlvbiBSb290IENBIE5v\nLjIwHhcNMjExMjI3MTE0OTMzWhcNNDEwNjI1MTE0OTMzWjAxMS8wLQYDVQQDDCZD\nYW5vS2V5cyBGSURPIEF0dGVzdGF0aW9uIFJvb3QgQ0EgTm8uMjBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABNgW7CwchH80l4sj8luhwjbNoohB9Uqnvsh0SLor18w8\nIMy6rnzzdDP9PgSSbuUZw302mBhyYJqJY1q9Ke0niZujQjBAMB0GA1UdDgQWBBRU\nGAKiwvk2vLP5Zi6ul73RiWyr0jAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQE\nAwIBBjAKBggqhkjOPQQDAgNJADBGAiEAlRNyrmngE3A1YZuwsuwBHLXY7wZC/4CO\nJNA30mtp2+YCIQDA88Pp+Kjx3c4nrgRgSaSueC5IlvwpTSGBGwRYDSdMTA=="
],
"icon": "data:image/png;base64,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",
"authenticatorGetInfo": {
Expand Down
1 change: 0 additions & 1 deletion applets/ctap/ctap-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ typedef struct {
user_entity user;
bool deleted;
bool has_large_blob_key;
uint8_t large_blob_key[LARGE_BLOB_KEY_SIZE];
uint8_t cred_blob_len;
uint8_t cred_blob[MAX_CRED_BLOB_LENGTH];
} __packed CTAP_discoverable_credential;
Expand Down
33 changes: 29 additions & 4 deletions applets/ctap/ctap.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
} \
} while (0)

#define KEEPALIVE() \
do { \
if (is_nfc()) break; \
send_keepalive_during_processing(WAIT_ENTRY_CTAPHID); \
} while (0)

static const uint8_t aaguid[] = {0x24, 0x4e, 0xb2, 0x9e, 0xe0, 0x90, 0x4e, 0x49,
0x81, 0xfe, 0x1f, 0x20, 0xf8, 0xd3, 0xb8, 0xf4};

Expand Down Expand Up @@ -286,6 +292,7 @@ static uint8_t ctap_make_credential(CborEncoder *encoder, uint8_t *params, size_

ret = ctap_consistency_check();
CHECK_PARSER_RET(ret);
KEEPALIVE();

// 1. If authenticator supports clientPin features and the platform sends a zero length pin_uv_auth_param
if ((mc.parsed_params & PARAM_PIN_UV_AUTH_PARAM) && mc.pin_uv_auth_param_len == 0) {
Expand Down Expand Up @@ -584,7 +591,6 @@ static uint8_t ctap_make_credential(CborEncoder *encoder, uint8_t *params, size_
memcpy(&dc.credential_id, data_buf + 55, sizeof(dc.credential_id));
memcpy(&dc.user, &mc.user, sizeof(user_entity)); // c
dc.has_large_blob_key = mc.ext_large_blob_key;
if (dc.has_large_blob_key) random_buffer(dc.large_blob_key, LARGE_BLOB_KEY_SIZE);
dc.cred_blob_len = 0;
if (mc.ext_has_cred_blob && mc.ext_cred_blob_len <= MAX_CRED_BLOB_LENGTH) {
dc.cred_blob_len = mc.ext_cred_blob_len;
Expand Down Expand Up @@ -697,9 +703,13 @@ static uint8_t ctap_make_credential(CborEncoder *encoder, uint8_t *params, size_
CHECK_CBOR_RET(ret);

if (mc.ext_large_blob_key) {
uint8_t *large_blob_key = dc.cred_blob; // reuse buffer
static_assert(LARGE_BLOB_KEY_SIZE <= MAX_CRED_BLOB_LENGTH, "Reuse buffer");
ret = make_large_blob_key(dc.credential_id.nonce, large_blob_key);
CHECK_CBOR_RET(ret);
ret = cbor_encode_int(&map, MC_RESP_LARGE_BLOB_KEY);
CHECK_CBOR_RET(ret);
ret = cbor_encode_byte_string(&map, dc.large_blob_key, LARGE_BLOB_KEY_SIZE);
ret = cbor_encode_byte_string(&map, large_blob_key, LARGE_BLOB_KEY_SIZE);
CHECK_CBOR_RET(ret);
}

Expand Down Expand Up @@ -748,6 +758,7 @@ static uint8_t ctap_get_assertion(CborEncoder *encoder, uint8_t *params, size_t
}
ret = parse_get_assertion(&parser, &ga, params, len);
CHECK_PARSER_RET(ret);
KEEPALIVE();

// 1. If authenticator supports clientPin features and the platform sends a zero length pin_uv_auth_param
if ((ga.parsed_params & PARAM_PIN_UV_AUTH_PARAM) && ga.pin_uv_auth_param_len == 0) {
Expand Down Expand Up @@ -1149,9 +1160,13 @@ static uint8_t ctap_get_assertion(CborEncoder *encoder, uint8_t *params, size_t
}

if (dc.has_large_blob_key) {
uint8_t *large_blob_key = dc.cred_blob; // reuse buffer
static_assert(LARGE_BLOB_KEY_SIZE <= MAX_CRED_BLOB_LENGTH, "Reuse buffer");
ret = make_large_blob_key(dc.credential_id.nonce, large_blob_key);
CHECK_CBOR_RET(ret);
ret = cbor_encode_int(&map, GA_RESP_LARGE_BLOB_KEY);
CHECK_CBOR_RET(ret);
ret = cbor_encode_byte_string(&map, dc.large_blob_key, LARGE_BLOB_KEY_SIZE);
ret = cbor_encode_byte_string(&map, large_blob_key, LARGE_BLOB_KEY_SIZE);
CHECK_CBOR_RET(ret);
}

Expand Down Expand Up @@ -1634,6 +1649,7 @@ static uint8_t ctap_credential_management(CborEncoder *encoder, const uint8_t *p
if (numbers == 0) return CTAP2_ERR_NO_CREDENTIALS;
size = get_file_size(DC_META_FILE), counter = 0;
n_rp = size / (int) sizeof(CTAP_rp_meta);
KEEPALIVE();
for (int i = n_rp - 1; i >= 0; --i) {
size = read_file(DC_META_FILE, &meta, i * (int) sizeof(CTAP_rp_meta), sizeof(CTAP_rp_meta));
if (size < 0) return CTAP2_ERR_UNHANDLED_REQUEST;
Expand Down Expand Up @@ -1711,6 +1727,7 @@ static uint8_t ctap_credential_management(CborEncoder *encoder, const uint8_t *p
include_numbers = true;
size = get_file_size(DC_META_FILE);
n_rp = size / (int) sizeof(CTAP_rp_meta);
KEEPALIVE();
for (idx = 0; idx < n_rp; ++idx) {
size = read_file(DC_META_FILE, &meta, idx * (int) sizeof(CTAP_rp_meta), sizeof(CTAP_rp_meta));
if (size < 0) return CTAP2_ERR_UNHANDLED_REQUEST;
Expand Down Expand Up @@ -1800,9 +1817,13 @@ static uint8_t ctap_credential_management(CborEncoder *encoder, const uint8_t *p
ret = cbor_encode_int(&map, dc.credential_id.nonce[CREDENTIAL_NONCE_CP_POS]);
CHECK_CBOR_RET(ret);
if (dc.has_large_blob_key) {
uint8_t *large_blob_key = dc.cred_blob; // reuse buffer
static_assert(LARGE_BLOB_KEY_SIZE <= MAX_CRED_BLOB_LENGTH, "Reuse buffer");
ret = make_large_blob_key(dc.credential_id.nonce, large_blob_key);
CHECK_CBOR_RET(ret);
ret = cbor_encode_int(&map, CM_RESP_LARGE_BLOB_KEY);
CHECK_CBOR_RET(ret);
ret = cbor_encode_byte_string(&map, dc.large_blob_key, LARGE_BLOB_KEY_SIZE);
ret = cbor_encode_byte_string(&map, large_blob_key, LARGE_BLOB_KEY_SIZE);
CHECK_CBOR_RET(ret);
}
ret = cbor_encoder_close_container(encoder, &map);
Expand Down Expand Up @@ -1856,6 +1877,7 @@ static uint8_t ctap_credential_management(CborEncoder *encoder, const uint8_t *p
size = get_file_size(DC_META_FILE);
if (size < 0) return CTAP2_ERR_UNHANDLED_REQUEST;
numbers = size / sizeof(CTAP_rp_meta);
KEEPALIVE();
for (int i = 0; i < numbers; ++i) {
size = read_file(DC_META_FILE, &meta, i * (int) sizeof(CTAP_rp_meta), sizeof(CTAP_rp_meta));
if (size < 0) return CTAP2_ERR_UNHANDLED_REQUEST;
Expand All @@ -1880,6 +1902,7 @@ static uint8_t ctap_credential_management(CborEncoder *encoder, const uint8_t *p
size = get_file_size(DC_FILE);
if (size < 0) return CTAP2_ERR_UNHANDLED_REQUEST;
numbers = size / sizeof(CTAP_discoverable_credential);
KEEPALIVE();
for (idx = 0; idx < numbers; ++idx) {
size = read_file(DC_FILE, &dc, idx * (int) sizeof(CTAP_discoverable_credential),
sizeof(CTAP_discoverable_credential));
Expand Down Expand Up @@ -1962,6 +1985,7 @@ static uint8_t ctap_large_blobs(CborEncoder *encoder, const uint8_t *params, siz
// in a zero-length substring.
if (lb.offset + (int)lb.get > size) lb.get = size - lb.offset;
DBG_MSG("read %hu bytes at %hu\n", lb.get, lb.offset);
KEEPALIVE();
ret = cbor_encoder_create_map(encoder, &map, 1);
CHECK_CBOR_RET(ret);
ret = cbor_encode_int(&map, LB_RESP_CONFIG);
Expand Down Expand Up @@ -2048,6 +2072,7 @@ static uint8_t ctap_large_blobs(CborEncoder *encoder, const uint8_t *params, siz
}
// g) If the value of offset is zero, prepare a buffer to receive a new serialized large-blob array.
// h) Append the value of set to the buffer containing the pending serialized large-blob array.
KEEPALIVE();
if (write_file(LB_FILE_TMP, lb.set, lb.offset, lb.set_len, lb.offset == 0) < 0) return CTAP2_ERR_UNHANDLED_REQUEST;
// i) Update expectedNextOffset to be the new length of the pending serialized large-blob array.
expectedNextOffset += lb.set_len;
Expand Down
16 changes: 16 additions & 0 deletions applets/ctap/secret.c
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,19 @@ int make_hmac_secret_output(uint8_t *nonce, uint8_t *salt, uint8_t len, uint8_t
if (len == 64) hmac_sha256(hmac_buf, HE_KEY_SIZE, salt + 32, 32, output + 32);
return 0;
}

int make_large_blob_key(uint8_t *nonce, uint8_t *output) {
static_assert(LARGE_BLOB_KEY_SIZE == HE_KEY_SIZE, "Reuse buffer");
// use hmac-sha256(transform(HE_KEY), credential_id::nonce) as LargeBlobKey
int err = read_he_key(output);
if (err < 0) return err;

// make it different from hmac extension key
output[0] ^= output[1];
output[1] ^= output[2];
output[HE_KEY_SIZE-2] ^= output[0];
output[HE_KEY_SIZE-1] ^= output[3];

hmac_sha256(output, HE_KEY_SIZE, nonce, CREDENTIAL_NONCE_SIZE, output);
return 0;
}
1 change: 1 addition & 0 deletions applets/ctap/secret.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@ int verify_pin_hash(uint8_t *buf);
int get_pin_retries(void);
int set_pin_retries(uint8_t ctr);
int make_hmac_secret_output(uint8_t *nonce, uint8_t *salt, uint8_t len, uint8_t *output, bool uv);
int make_large_blob_key(uint8_t *nonce, uint8_t *output);

#endif // CANOKEY_CORE_FIDO2_SECRET_H_
1 change: 1 addition & 0 deletions include/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ bool testmode_err_triggered(const char* filename, bool file_wr);
// platform independent functions
uint8_t wait_for_user_presence(uint8_t entry);
int strong_user_presence_test(void);
int send_keepalive_during_processing(uint8_t entry);
void device_loop(uint8_t has_touch);
uint8_t is_nfc(void);
void set_nfc_state(uint8_t state);
Expand Down
36 changes: 22 additions & 14 deletions interfaces/USB/class/ctaphid/ctaphid.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ uint8_t CTAPHID_Init(uint8_t (*send_report)(USBD_HandleTypeDef *pdev, uint8_t *r
}

uint8_t CTAPHID_OutEvent(uint8_t *data) {
if (has_frame) {
ERR_MSG("overrun\n");
return 0;
}
memcpy(&frame, data, sizeof(frame));
has_frame = 1;
return 0;
Expand Down Expand Up @@ -60,6 +64,7 @@ static void CTAPHID_SendResponse(uint32_t cid, uint8_t cmd, uint8_t *data, uint1
}

static void CTAPHID_SendErrorResponse(uint32_t cid, uint8_t code) {
DBG_MSG("error code 0x%x\n", (int)code);
memset(&frame, 0, sizeof(frame));
frame.cid = cid;
frame.init.cmd = CTAPHID_ERROR;
Expand Down Expand Up @@ -117,39 +122,39 @@ static void CTAPHID_Execute_Cbor(void) {
}

uint8_t CTAPHID_Loop(uint8_t wait_for_user) {
uint8_t ret = LOOP_SUCCESS;
if (channel.state == CTAPHID_BUSY && device_get_tick() > channel.expire) {
DBG_MSG("CTAP Timeout");
DBG_MSG("CTAP Timeout\n");
channel.state = CTAPHID_IDLE;
CTAPHID_SendErrorResponse(channel.cid, ERR_MSG_TIMEOUT);
return LOOP_SUCCESS;
}

if (!has_frame) return LOOP_SUCCESS;
has_frame = 0;

if (frame.cid == 0 || (frame.cid == CID_BROADCAST && frame.init.cmd != CTAPHID_INIT)) {
CTAPHID_SendErrorResponse(frame.cid, ERR_INVALID_CID);
return LOOP_SUCCESS;
goto consume_frame;
}
if (channel.state == CTAPHID_BUSY && frame.cid != channel.cid) {
CTAPHID_SendErrorResponse(frame.cid, ERR_CHANNEL_BUSY);
return LOOP_SUCCESS;
goto consume_frame;
}

channel.cid = frame.cid;

if (FRAME_TYPE(frame) == TYPE_INIT) {
// DBG_MSG("CTAP init frame, cmd=0x%x\n", (int)frame.init.cmd);
if (!wait_for_user && channel.state == CTAPHID_BUSY && frame.init.cmd != CTAPHID_INIT) { // self abort is ok
DBG_MSG("wait_for_user=%d, cmd=0x%x\n", (int)wait_for_user, (int)frame.init.cmd);
channel.state = CTAPHID_IDLE;
CTAPHID_SendErrorResponse(channel.cid, ERR_INVALID_SEQ);
return LOOP_SUCCESS;
goto consume_frame;
}
channel.bcnt_total = (uint16_t)MSG_LEN(frame);
if (channel.bcnt_total > MAX_CTAP_BUFSIZE) {
DBG_MSG("bcnt_total=%hu exceeds MAX_CTAP_BUFSIZE\n", channel.bcnt_total);
CTAPHID_SendErrorResponse(frame.cid, ERR_INVALID_LEN);
return LOOP_SUCCESS;
goto consume_frame;
}
uint16_t copied;
channel.bcnt_current = copied = MIN(channel.bcnt_total, ISIZE);
Expand All @@ -158,21 +163,22 @@ uint8_t CTAPHID_Loop(uint8_t wait_for_user) {
channel.seq = 0;
memcpy(channel.data, frame.init.data, copied);
channel.expire = device_get_tick() + CTAPHID_TRANS_TIMEOUT;
} else if (FRAME_TYPE(frame) == TYPE_CONT) {
} else {
// DBG_MSG("CTAP cont frame, state=%d cmd=0x%x seq=%d\n", (int)channel.state, (int)channel.cmd, (int)FRAME_SEQ(frame));
if (channel.state == CTAPHID_IDLE) return LOOP_SUCCESS; // ignore spurious continuation packet
if (channel.state == CTAPHID_IDLE) goto consume_frame; // ignore spurious continuation packet
if (FRAME_SEQ(frame) != channel.seq++) {
DBG_MSG("seq=%d\n", (int)FRAME_SEQ(frame));
channel.state = CTAPHID_IDLE;
CTAPHID_SendErrorResponse(channel.cid, ERR_INVALID_SEQ);
return LOOP_SUCCESS;
goto consume_frame;
}
uint16_t copied;
copied = MIN(channel.bcnt_total - channel.bcnt_current, CSIZE);
memcpy(channel.data + channel.bcnt_current, frame.cont.data, copied);
channel.bcnt_current += copied;
}
has_frame = 0;

uint8_t ret = LOOP_SUCCESS;
if (channel.bcnt_current == channel.bcnt_total) {
channel.expire = UINT32_MAX;
switch (channel.cmd) {
Expand Down Expand Up @@ -214,17 +220,19 @@ uint8_t CTAPHID_Loop(uint8_t wait_for_user) {
CTAPHID_SendResponse(channel.cid, channel.cmd, channel.data, 0);
break;
case CTAPHID_CANCEL:
DBG_MSG("CANCEL\n");
DBG_MSG("CANCEL when wait_for_user=%d\n", (int)wait_for_user);
ret = LOOP_CANCEL;
break;
default:
DBG_MSG("Invalid CMD 0x%hhx\n", channel.cmd);
DBG_MSG("Invalid CMD 0x%x\n", (int)channel.cmd);
CTAPHID_SendErrorResponse(channel.cid, ERR_INVALID_CMD);
break;
}
channel.state = CTAPHID_IDLE;
}

consume_frame:
has_frame = 0;
return ret;
}

Expand Down
2 changes: 1 addition & 1 deletion interfaces/USB/class/kbdhid/kbdhid.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static uint8_t ascii2keycode(char ch) {
}

static void KBDHID_UserTouchHandle(void) {
int ret, len;
int ret, len = 0;
memset(key_sequence, 0, sizeof(key_sequence));
ret = oath_process_one_touch(key_sequence, sizeof(key_sequence));
if (ret < 0) {
Expand Down
Loading

0 comments on commit 8d92f58

Please sign in to comment.