diff --git a/FIDO2 Conformance Testing.json b/FIDO2 Conformance Testing.json index e63fa088..a4839395 100644 --- a/FIDO2 Conformance Testing.json +++ b/FIDO2 Conformance Testing.json @@ -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": { diff --git a/applets/ctap/ctap-internal.h b/applets/ctap/ctap-internal.h index 33432313..c7e0f25f 100644 --- a/applets/ctap/ctap-internal.h +++ b/applets/ctap/ctap-internal.h @@ -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; diff --git a/applets/ctap/ctap.c b/applets/ctap/ctap.c index 90df9627..5860800d 100644 --- a/applets/ctap/ctap.c +++ b/applets/ctap/ctap.c @@ -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}; @@ -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) { @@ -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; @@ -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); } @@ -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) { @@ -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); } @@ -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; @@ -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; @@ -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); @@ -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; @@ -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)); @@ -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); @@ -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; diff --git a/applets/ctap/secret.c b/applets/ctap/secret.c index 49fb3286..8dc13db8 100644 --- a/applets/ctap/secret.c +++ b/applets/ctap/secret.c @@ -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; +} diff --git a/applets/ctap/secret.h b/applets/ctap/secret.h index b7387f2e..56227536 100644 --- a/applets/ctap/secret.h +++ b/applets/ctap/secret.h @@ -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_ diff --git a/include/device.h b/include/device.h index ec4bd846..a36c13d1 100644 --- a/include/device.h +++ b/include/device.h @@ -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); diff --git a/interfaces/USB/class/ctaphid/ctaphid.c b/interfaces/USB/class/ctaphid/ctaphid.c index 6d20fb16..c8ce4b3e 100644 --- a/interfaces/USB/class/ctaphid/ctaphid.c +++ b/interfaces/USB/class/ctaphid/ctaphid.c @@ -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; @@ -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; @@ -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); @@ -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) { @@ -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; } diff --git a/interfaces/USB/class/kbdhid/kbdhid.c b/interfaces/USB/class/kbdhid/kbdhid.c index c71d2e9c..43391168 100644 --- a/interfaces/USB/class/kbdhid/kbdhid.c +++ b/interfaces/USB/class/kbdhid/kbdhid.c @@ -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) { diff --git a/src/device.c b/src/device.c index 30a142e2..01cdecd8 100644 --- a/src/device.c +++ b/src/device.c @@ -58,6 +58,7 @@ uint8_t wait_for_user_presence(uint8_t entry) { if (wait_status == WAIT_DEEP_TOUCHED || wait_status == WAIT_DEEP_CANCEL) break; if (wait_status == WAIT_CTAPHID) CCID_Loop(); if (CTAPHID_Loop(wait_status != WAIT_CCID) == LOOP_CANCEL) { + DBG_MSG("Cancelled by host\n"); if (wait_status != WAIT_DEEP) { stop_blinking(); wait_status = WAIT_NONE; // namely shallow @@ -72,7 +73,7 @@ uint8_t wait_for_user_presence(uint8_t entry) { wait_status = shallow; return USER_PRESENCE_TIMEOUT; } - if (now - last >= 300) { + if (now - last >= 100) { last = now; if (wait_status != WAIT_CCID) CTAPHID_SendKeepAlive(KEEPALIVE_STATUS_UPNEEDED); } @@ -89,6 +90,12 @@ uint8_t wait_for_user_presence(uint8_t entry) { return USER_PRESENCE_OK; } +int send_keepalive_during_processing(uint8_t entry) { + if (entry == WAIT_ENTRY_CTAPHID) CTAPHID_SendKeepAlive(KEEPALIVE_STATUS_PROCESSING); + DBG_MSG("KEEPALIVE\n"); + return 0; +} + __attribute__((weak)) int strong_user_presence_test(void) { for (int i = 0; i < 5; i++) { const uint8_t wait_sec = 2; diff --git a/virt-card/ifdhandler.c b/virt-card/ifdhandler.c index 16ffd50c..5de99c97 100644 --- a/virt-card/ifdhandler.c +++ b/virt-card/ifdhandler.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "ccid.h" +#include "ctaphid.h" #include "fabrication.h" #include #include @@ -14,10 +15,16 @@ const static UCHAR ATR[] = {0x3B, 0xF7, 0x11, 0x00, 0x00, 0x81, 0x31, 0xFE, 0x65 0x43, 0x61, 0x6E, 0x6F, 0x6B, 0x65, 0x79, 0x99}; static int applet_init = 0; +static uint8_t send_hid_report(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len) +{ + return 0; +} + RESPONSECODE IFDHCreateChannel ( DWORD Lun, DWORD Channel ) { printf("IFDHCreateChannel %ld %ld\n", Lun, Channel); if(!applet_init) { + CTAPHID_Init(send_hid_report); CCID_Init(); card_fabrication_procedure("/tmp/lfs-root"); applet_init = 1;