int rlm_yubikey_ykclient_init(CONF_SECTION *conf, rlm_yubikey_t *inst) { ykclient_rc status; CONF_SECTION *servers; char prefix[100]; int count = 0; if (!inst->client_id) { ERROR("rlm_yubikey (%s): validation.client_id must be set (to a valid id) when validation is enabled", inst->name); return -1; } if (!inst->api_key || !*inst->api_key || is_zero(inst->api_key)) { ERROR("rlm_yubikey (%s): validation.api_key must be set (to a valid key) when validation is enabled", inst->name); return -1; } DEBUG("rlm_yubikey (%s): Initialising ykclient", inst->name); status = ykclient_global_init(); if (status != YKCLIENT_OK) { yk_error: ERROR("rlm_yubikey (%s): %s", ykclient_strerror(status), inst->name); return -1; } status = ykclient_init(&inst->ykc); if (status != YKCLIENT_OK) { goto yk_error; } servers = cf_section_sub_find(conf, "servers"); if (servers) { CONF_PAIR *uri, *first; /* * If there were no uris configured we just use the default * ykclient uris which point to the yubico servers. */ first = uri = cf_pair_find(servers, "uri"); if (!uri) { goto init; } while (uri) { count++; uri = cf_pair_find_next(servers, uri, "uri"); } inst->uris = talloc_zero_array(inst, char const *, count); uri = first; count = 0; while (uri) { inst->uris[count++] = cf_pair_value(uri); uri = cf_pair_find_next(servers, uri, "uri"); } if (count) { status = ykclient_set_url_templates(inst->ykc, count, inst->uris); if (status != YKCLIENT_OK) { goto yk_error; } } } init: status = ykclient_set_client_b64(inst->ykc, inst->client_id, inst->api_key); if (status != YKCLIENT_OK) { ERROR("rlm_yubikey (%s): Failed setting API credentials: %s", ykclient_strerror(status), inst->name); return -1; } snprintf(prefix, sizeof(prefix), "rlm_yubikey (%s)", inst->name); inst->pool = module_connection_pool_init(conf, inst, mod_conn_create, NULL, prefix); if (!inst->pool) { ykclient_done(&inst->ykc); return -1; } return 0; }
int main (void) { int client_id = 1851; char client_key[] = { 0xa0, 0x15, 0x5b, 0x36, 0xde, 0xc8, 0x65, 0xe8, 0x59, 0x19, 0x1f, 0x7d, 0xae, 0xfa, 0xbc, 0x77, 0xa4, 0x59, 0xd4, 0x33 }; char *client_hexkey = "a0155b36dec865e859191f7daefabc77a459d433"; char *client_b64key = "oBVbNt7IZehZGR99rvq8d6RZ1DM="; ykclient_t *ykc; int ret; curl_global_init(CURL_GLOBAL_ALL); TEST(("init self")); ret = ykclient_init (&ykc); printf ("ykclient_init (%d): %s\n", ret, ykclient_strerror (ret)); assert(ret == YKCLIENT_OK); TEST(("null client_id, expect REPLAYED_OTP")); ykclient_set_verify_signature(ykc, 0); ykclient_set_client (ykc, client_id, 0, NULL); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert(ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("client_id set(20), correct client_key, expect REPLAYED_OTP")); ykclient_set_client (ykc, client_id, 20, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("wrong client_id set(10), correct client_key, expect BAD_SIGNATURE")); ykclient_set_client (ykc, client_id, 10, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif TEST(("invalid client_id set(a), correct client_key, expect HEX_DECODE_ERROR")); ret = ykclient_set_client_hex (ykc, client_id, "a"); printf ("ykclient_set_client_hex (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_HEX_DECODE_ERROR); TEST(("invalid client_id set(xx), correct client_key, expect HEX_DECODE_ERROR")); ret = ykclient_set_client_hex (ykc, client_id, "xx"); printf ("ykclient_set_client_hex (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_HEX_DECODE_ERROR); TEST(("hex client_id set, correct client_key, expect OK")); ret = ykclient_set_client_hex (ykc, client_id, client_hexkey); printf ("ykclient_set_client_hex (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_OK); #ifndef TEST_WITHOUT_INTERNET TEST(("validation request, expect REPLAYED_OTP")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("set deadbeef client_id, expect OK")); ret = ykclient_set_client_hex (ykc, client_id, "deadbeef"); printf ("ykclient_set_client_hex (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_OK); #ifndef TEST_WITHOUT_INTERNET TEST(("validation request, expect BAD_SIGNATURE")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif TEST(("b64 set deadbeef client_id, expect OK")); ret = ykclient_set_client_b64 (ykc, client_id, "deadbeef"); printf ("ykclient_set_client_b64 (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_OK); #ifndef TEST_WITHOUT_INTERNET /* When the server dislikes our signature, it will sign the response with a NULL key, so the API call will fail with BAD_SERVER_SIGNATURE even though the server returned status=BAD_SIGNATURE. */ TEST(("validation request, expect BAD_SERVER_SIGNATURE")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SERVER_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif #ifndef TEST_WITHOUT_INTERNET /* Now, disable our checking of the servers signature to get the error the server returned (server will use 00000 as key when signing this error response). */ TEST(("validation request, expect BAD_SIGNATURE")); ykclient_set_verify_signature (ykc, 0); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif TEST(("b64 set client_b64key, expect OK")); ret = ykclient_set_client_b64 (ykc, client_id, client_b64key); printf ("ykclient_set_client_b64 (%d): %s\n", ret, ykclient_strerror (ret)); assert (ret == YKCLIENT_OK); #ifndef TEST_WITHOUT_INTERNET TEST(("validation request, expect REPLAYED_OTP")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("set WS 2.0 URL template")); /* Set one URL and run tests with that. */ ykclient_set_url_template (ykc, "http://api.yubico.com/wsapi/2.0/verify?id=%d&otp=%s"); #ifndef TEST_WITHOUT_INTERNET TEST(("validation request, expect REPLAYED_OTP")); ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("yubikey_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif ykclient_set_verify_signature(ykc, 1); TEST(("validation request with valid signature, expect REPLAYED_OTP")); // Check a genuine signature. ykclient_set_client (ykc, client_id, 20, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif TEST(("validation request with bad key, expect YKCLIENT_BAD_SERVER_SIGNATURE")); // Check a genuine signature with a truncated key. ykclient_set_client (ykc, client_id, 10, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_BAD_SERVER_SIGNATURE); #else printf ("Test SKIPPED\n"); #endif TEST(("Set and use several V2.0 URLs")); const char *templates[] = { "http://api.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", "http://api2.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", "http://api3.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", "http://api4.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", "http://api5.yubico.com/wsapi/2.0/verify?id=%d&otp=%s", }; ykclient_set_url_templates(ykc, 5, templates); ykclient_set_client (ykc, client_id, 20, client_key); #ifndef TEST_WITHOUT_INTERNET ret = ykclient_request (ykc, "dteffujehknhfjbrjnlnldnhcujvddbikngjrtgh"); printf ("ykclient_request (%d): %s\n", ret, ykclient_strerror (ret)); printf ("used url: %s\n", ykclient_get_last_url (ykc)); assert (ret == YKCLIENT_REPLAYED_OTP); #else printf ("Test SKIPPED\n"); #endif ykclient_done (&ykc); TEST(("strerror 0")); printf ("strerror(0): %s\n", ykclient_strerror (0)); ret = strcmp(ykclient_strerror (0), "Success"); assert (ret == 0); TEST(("strerror BAD_OTP")); printf ("strerror(BAD_OTP): %s\n", ykclient_strerror (YKCLIENT_BAD_OTP)); ret = strcmp(ykclient_strerror (YKCLIENT_BAD_OTP), "Yubikey OTP was bad (BAD_OTP)"); assert (ret == 0); test_v1_validation(client_id, client_b64key); test_base64(); test_hmac(); printf ("All tests passed\n"); curl_global_cleanup(); return 0; }