static int16_t u2f_version() { const char version[] = "U2F_V2"; u2f_hid_set_len(2 + sizeof(version)-1); u2f_response_writeback(version, sizeof(version)-1); return U2F_SW_NO_ERROR; }
static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control) { uint8_t up = 1; uint32_t count; if (u2f_load_key(req->kh) != 0) { u2f_hid_set_len(2); return U2F_SW_WRONG_DATA; } else if (control == U2F_AUTHENTICATE_CHECK) { u2f_hid_set_len(2); return U2F_SW_CONDITIONS_NOT_SATISFIED; } if (u2f_get_user_feedback()) { u2f_hid_set_len(2); return U2F_SW_CONDITIONS_NOT_SATISFIED; } count = u2f_count(); u2f_sha256_start(); u2f_sha256_update(req->app,32); u2f_sha256_update(&up,1); u2f_sha256_update((uint8_t *)&count,4); u2f_sha256_update(req->chal,32); u2f_sha256_finish(); if (u2f_ecdsa_sign((uint8_t*)req, req->kh) == -1) { return U2F_SW_WRONG_DATA; } u2f_hid_set_len(7 + get_signature_length((uint8_t*)req)); u2f_response_writeback(&up,1); u2f_response_writeback((uint8_t *)&count,4); dump_signature_der((uint8_t*)req); return U2F_SW_NO_ERROR; }
static int16_t u2f_register(struct u2f_register_request * req) { uint8_t i[] = {0x0,U2F_EC_FMT_UNCOMPRESSED}; uint8_t key_handle[U2F_KEY_HANDLE_SIZE]; uint8_t pubkey[64]; const uint16_t attest_size = u2f_attestation_cert_size(); if (u2f_get_user_feedback()) { return U2F_SW_CONDITIONS_NOT_SATISFIED; } if ( u2f_new_keypair(key_handle, pubkey) == -1) { return U2F_SW_CONDITIONS_NOT_SATISFIED; } u2f_sha256_start(); u2f_sha256_update(i,1); u2f_sha256_update(req->app,32); u2f_sha256_update(req->chal,32); u2f_sha256_update(key_handle,U2F_KEY_HANDLE_SIZE); u2f_sha256_update(i+1,1); u2f_sha256_update(pubkey,64); u2f_sha256_finish(); if (u2f_ecdsa_sign((uint8_t*)req, U2F_ATTESTATION_HANDLE) == -1) { return U2F_SW_WRONG_DATA; } u2f_hid_set_len(69 + get_signature_length((uint8_t*)req) + U2F_KEY_HANDLE_SIZE + u2f_attestation_cert_size()); i[0] = 0x5; u2f_response_writeback(i,2); u2f_response_writeback(pubkey,64); i[0] = U2F_KEY_HANDLE_SIZE; u2f_response_writeback(i,1); u2f_response_writeback(key_handle,U2F_KEY_HANDLE_SIZE); u2f_response_writeback_progmem(u2f_get_attestation_cert(),u2f_attestation_cert_size()); dump_signature_der((uint8_t*)req); return U2F_SW_NO_ERROR; }
static void hid_u2f_parse(struct u2f_hid_msg* req) { uint16_t len = 0; uint8_t secs; struct u2f_hid_init_response * init_res = appdata.tmp; switch(hid_layer.current_cmd) { case U2FHID_INIT: if (U2FHID_LEN(req) != 8) { stamp_error(hid_layer.current_cid, ERR_INVALID_LEN); goto fail; } u2f_hid_set_len(17); if (hid_layer.current_cid == 0) { u2f_prints("out of cid's\r\n"); set_app_error(ERROR_OUT_OF_CIDS); goto fail; } init_res->cid = get_new_cid(); init_res->version_id = 1; init_res->version_major = 1; init_res->version_minor = 0; init_res->version_build = 0; init_res->cflags = 0; // write back the same data nonce u2f_hid_writeback(req->pkt.init.payload, 8); u2f_hid_writeback((uint8_t *)init_res, 9); u2f_hid_flush(); hid_layer.current_cid = init_res->cid; break; case U2FHID_MSG: if (U2FHID_LEN(req) < 4) { stamp_error(hid_layer.current_cid, ERR_INVALID_LEN); u2f_prints("invalid len msg\r\n"); goto fail; } // buffer 2 payloads (120 bytes) to get full U2F message // assuming key handle is < 45 bytes // 7 bytes for apdu header // 7 + 66 bytes + key handle for authenticate message // 7 + 64 for register message if (hid_layer.bytes_buffered == 0) { start_buffering(req); if (hid_layer.bytes_buffered >= U2FHID_LEN(req)) { u2f_request((struct u2f_request_apdu *)hid_layer.buffer); } } else { buffer_request(req); if (hid_layer.bytes_buffered >= hid_layer.req_len) { u2f_request((struct u2f_request_apdu *)hid_layer.buffer); } } break; case U2FHID_PING: //u2f_prints("U2F PING\r\n"); if (!u2f_hid_busy()) { u2f_hid_set_len(U2FHID_LEN(req)); u2f_hid_writeback(req->pkt.init.payload, MIN(hid_layer.res_len, U2FHID_INIT_PAYLOAD_SIZE)); } else { u2f_hid_writeback(req->pkt.cont.payload, MIN(hid_layer.res_len - hid_layer.bytes_written, U2FHID_CONT_PAYLOAD_SIZE)); } if (hid_layer.res_len == hid_layer.bytes_written) u2f_hid_flush(); break; case U2FHID_WINK: if (U2FHID_LEN(req) != 0) { // this one is safe stamp_error(hid_layer.current_cid, ERR_INVALID_LEN); } u2f_hid_set_len(0); u2f_hid_writeback(NULL, 0); u2f_hid_flush(); app_wink(U2F_COLOR_WINK); break; case U2FHID_LOCK: secs = req->pkt.init.payload[0]; if (secs > 10) { stamp_error(hid_layer.current_cid, ERR_INVALID_PAR); } else { _hid_lock_cid = hid_layer.current_cid; _hid_lockt = get_ms() + 1000 * secs; u2f_hid_set_len(0); u2f_hid_writeback(NULL, 0); u2f_hid_flush(); } break; default: set_app_error(ERROR_HID_INVALID_CMD); stamp_error(hid_layer.current_cid, ERR_INVALID_CMD); } return; fail: u2f_prints("U2F HID FAIL\r\n"); return; }
// return 0 if finished // return 1 if expecting more cont packets static uint8_t hid_u2f_parse(struct u2f_hid_msg* req) { uint16_t len = 0; uint8_t secs; struct u2f_hid_init_response * init_res = appdata.tmp; switch(hid_layer.current_cmd) { case U2FHID_INIT: if (U2FHID_LEN(req) != 8) { stamp_error(hid_layer.current_cid, ERR_INVALID_LEN); goto fail; } u2f_hid_set_len(17); if (hid_layer.current_cid == U2FHID_BROADCAST) { if (hid_layer.current_cid == 0) { set_app_error(ERROR_OUT_OF_CIDS); goto fail; } init_res->cid = get_new_cid(); } else { init_res->cid = hid_layer.current_cid; } init_res->version_id = 2; init_res->version_major = 2; init_res->version_minor = 0; init_res->version_build = 0; #ifdef U2F_SUPPORT_WINK && CAPABILITY_LOCK init_res->cflags = CAPABILITY_WINK | CAPABILITY_LOCK; #elif U2F_SUPPORT_WINK init_res->cflags = CAPABILITY_WINK; #elif CAPABILITY_LOCK init_res->cflags = CAPABILITY_LOCK; #else init_res->cflags = 0; #endif // write back the same data nonce u2f_hid_writeback(req->pkt.init.payload, 8); u2f_hid_writeback((uint8_t *)init_res, 9); u2f_hid_flush(); hid_layer.current_cid = init_res->cid; break; case U2FHID_MSG: if (U2FHID_LEN(req) < 4) { stamp_error(hid_layer.current_cid, ERR_INVALID_LEN); goto fail; } // buffer 2 payloads (120 bytes) to get full U2F message // assuming key handle is < 45 bytes // 7 bytes for apdu header // 7 + 66 bytes + key handle for authenticate message // 7 + 64 for register message if (hid_layer.bytes_buffered == 0) { start_buffering(req); if (hid_layer.bytes_buffered >= U2FHID_LEN(req)) { u2f_request((struct u2f_request_apdu *)hid_layer.buffer); } } else { buffer_request(req); if (hid_layer.bytes_buffered >= hid_layer.req_len) { u2f_request((struct u2f_request_apdu *)hid_layer.buffer); } } break; case U2FHID_PING: if (hid_layer.bytes_buffered == 0) { start_buffering(req); u2f_hid_set_len(U2FHID_LEN(req)); if (hid_layer.bytes_buffered >= U2FHID_LEN(req)) { u2f_hid_writeback(hid_layer.buffer,hid_layer.bytes_buffered); u2f_hid_flush(); } else { return 1; } } else { if (hid_layer.bytes_buffered + U2FHID_CONT_PAYLOAD_SIZE > BUFFER_SIZE) { u2f_hid_writeback(hid_layer.buffer,hid_layer.bytes_buffered); hid_layer.bytes_buffered = 0; } buffer_request(req); if (hid_layer.bytes_buffered + hid_layer.bytes_written >= hid_layer.req_len) { u2f_hid_writeback(hid_layer.buffer,hid_layer.bytes_buffered); u2f_hid_flush(); } else { return 1; } } break; #ifdef U2F_SUPPORT_WINK case U2FHID_WINK: if (U2FHID_LEN(req) != 0) { // this one is safe stamp_error(hid_layer.current_cid, ERR_INVALID_LEN); } u2f_hid_set_len(0); u2f_hid_writeback(NULL, 0); u2f_hid_flush(); app_wink(U2F_COLOR_WINK); break; #endif #ifdef U2F_SUPPORT_HID_LOCK case U2FHID_LOCK: secs = req->pkt.init.payload[0]; if (secs > 10) { stamp_error(hid_layer.current_cid, ERR_INVALID_PAR); } else { if (secs) { _hid_lock_cid = hid_layer.current_cid; _hid_lockt = get_ms() + 1000 * secs; } else { _hid_lockt = get_ms(); _hid_lock_cid = 0; } hid_layer.current_cmd = U2FHID_LOCK; u2f_hid_set_len(0); u2f_hid_writeback(NULL, 0); u2f_hid_flush(); } break; #endif default: set_app_error(ERROR_HID_INVALID_CMD); stamp_error(hid_layer.current_cid, ERR_INVALID_CMD); u2f_printb("invalid cmd: ",1,hid_layer.current_cmd); } return u2f_hid_busy(); fail: u2f_prints("U2F HID FAIL\r\n"); return 0; }
void set_response_length(uint16_t len) { u2f_hid_set_len(len); }