static u2fh_rc _u2fh_register (u2fh_devs * devs, const char *challenge, const char *origin, char **response, size_t * response_len, u2fh_cmdflags flags) { unsigned char data[V2CHALLEN + HOSIZE]; unsigned char buf[MAXDATASIZE]; char bd[2048]; size_t bdlen = sizeof (bd); size_t len; int rc = U2FH_JSON_ERROR; char chalb64[256]; size_t challen = sizeof (chalb64); int iterations = 0; rc = get_fixed_json_data (challenge, "challenge", chalb64, &challen); if (rc != U2FH_OK) { return rc; } rc = prepare_browserdata (chalb64, origin, REGISTER_TYP, bd, &bdlen); if (rc != U2FH_OK) return rc; sha256_buffer (bd, bdlen, data); prepare_origin (challenge, data + V2CHALLEN); /* FIXME: Support asynchronous usage, through a new u2fh_cmdflags flag. */ do { struct u2fdevice *dev; if (iterations++ > 15) { return U2FH_TIMEOUT_ERROR; } for (dev = devs->first; dev != NULL; dev = dev->next) { len = MAXDATASIZE; rc = send_apdu (devs, dev->id, U2F_REGISTER, data, sizeof (data), flags & U2FH_REQUEST_USER_PRESENCE ? 3 : 0, buf, &len); if (rc != U2FH_OK) { return rc; } else if (len != 2) { break; } } if (len != 2) { break; } Sleep (1000); } while ((flags & U2FH_REQUEST_USER_PRESENCE) && len == 2 && memcmp (buf, NOTSATISFIED, 2) == 0); if (len != 2) { prepare_response (buf, len - 2, bd, response, response_len); return U2FH_OK; } return U2FH_TRANSPORT_ERROR; }
/** * u2fh_authenticate: * @devs: a device handle, from u2fh_devs_init() and u2fh_devs_discover(). * @challenge: string with JSON data containing the challenge. * @origin: U2F origin URL. * @response: pointer to output string with JSON data. * @flags: set of ORed #u2fh_cmdflags values. * * Perform the U2F Authenticate operation. * * Returns: On success %U2FH_OK (integer 0) is returned, and on errors * an #u2fh_rc error code. */ u2fh_rc u2fh_authenticate (u2fh_devs * devs, const char *challenge, const char *origin, char **response, u2fh_cmdflags flags) { unsigned char data[CHALLBINLEN + HOSIZE + MAXKHLEN + 1]; unsigned char buf[MAXDATASIZE]; char bd[2048]; size_t bdlen = sizeof (bd); size_t len; int rc; char chalb64[256]; size_t challen = sizeof (chalb64); char khb64[256]; size_t kh64len = sizeof (khb64); base64_decodestate b64; size_t khlen; int skip_devices[devs->num_devices]; int skipped = 0; int iterations = 0; memset (skip_devices, 0, sizeof (skip_devices)); rc = get_fixed_json_data (challenge, "challenge", chalb64, &challen); if (rc != U2FH_OK) return rc; rc = prepare_browserdata (chalb64, origin, AUTHENTICATE_TYP, bd, &bdlen); if (rc != U2FH_OK) return rc; sha256_buffer (bd, bdlen, data); prepare_origin (challenge, data + CHALLBINLEN); /* confusion between key_handle and keyHandle */ rc = get_fixed_json_data (challenge, "keyHandle", khb64, &kh64len); if (rc != U2FH_OK) return rc; base64_init_decodestate (&b64); khlen = base64_decode_block (khb64, kh64len, data + HOSIZE + CHALLBINLEN + 1, &b64); data[HOSIZE + CHALLBINLEN] = khlen; /* FIXME: Support asynchronous usage, through a new u2fh_cmdflags flag. */ do { int i; if (iterations++ > 15) { return U2FH_TIMEOUT_ERROR; } for (i = 0; i < devs->num_devices; i++) { unsigned char tmp_buf[MAXDATASIZE]; if (skip_devices[i] != 0) { continue; } if (!devs->devs[i].is_alive) { skipped++; skip_devices[i] = 1; continue; } len = MAXDATASIZE; rc = send_apdu (devs, i, U2F_AUTHENTICATE, data, HOSIZE + CHALLBINLEN + khlen + 1, flags & U2FH_REQUEST_USER_PRESENCE ? 3 : 7, tmp_buf, &len); if (rc != U2FH_OK) { return rc; } else if (len != 2) { memcpy (buf, tmp_buf, len); break; } else if (memcmp (tmp_buf, NOTSATISFIED, 2) != 0) { skipped++; skip_devices[i] = 2; continue; } memcpy (buf, tmp_buf, len); } if (len == 2 && memcmp (buf, NOTSATISFIED, 2) == 0) { Sleep (1000); } } while ((flags & U2FH_REQUEST_USER_PRESENCE) && len == 2 && memcmp (buf, NOTSATISFIED, 2) == 0); if (len == 2 && memcmp (buf, NOTSATISFIED, 2) != 0) { return U2FH_AUTHENTICATOR_ERROR; } if (len != 2) { prepare_response (buf, len - 2, bd, challenge, response); } return U2FH_OK; }