10afa8e06SEd Maste /*
20afa8e06SEd Maste * Copyright (c) 2019 Yubico AB. All rights reserved.
30afa8e06SEd Maste * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste */
70afa8e06SEd Maste
80afa8e06SEd Maste #include <fido.h>
90afa8e06SEd Maste #include <fido/credman.h>
100afa8e06SEd Maste
110afa8e06SEd Maste #include <stdio.h>
120afa8e06SEd Maste #include <stdlib.h>
130afa8e06SEd Maste #include <string.h>
140afa8e06SEd Maste #ifdef HAVE_UNISTD_H
150afa8e06SEd Maste #include <unistd.h>
160afa8e06SEd Maste #endif
170afa8e06SEd Maste
180afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h"
190afa8e06SEd Maste #include "extern.h"
200afa8e06SEd Maste
210afa8e06SEd Maste int
credman_get_metadata(fido_dev_t * dev,const char * path)220afa8e06SEd Maste credman_get_metadata(fido_dev_t *dev, const char *path)
230afa8e06SEd Maste {
240afa8e06SEd Maste fido_credman_metadata_t *metadata = NULL;
250afa8e06SEd Maste char *pin = NULL;
260afa8e06SEd Maste int r, ok = 1;
270afa8e06SEd Maste
280afa8e06SEd Maste if ((metadata = fido_credman_metadata_new()) == NULL) {
290afa8e06SEd Maste warnx("fido_credman_metadata_new");
300afa8e06SEd Maste goto out;
310afa8e06SEd Maste }
320afa8e06SEd Maste if ((r = fido_credman_get_dev_metadata(dev, metadata,
330afa8e06SEd Maste NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) {
340afa8e06SEd Maste if ((pin = get_pin(path)) == NULL)
350afa8e06SEd Maste goto out;
360afa8e06SEd Maste r = fido_credman_get_dev_metadata(dev, metadata, pin);
370afa8e06SEd Maste freezero(pin, PINBUF_LEN);
380afa8e06SEd Maste pin = NULL;
390afa8e06SEd Maste }
400afa8e06SEd Maste if (r != FIDO_OK) {
410afa8e06SEd Maste warnx("fido_credman_get_dev_metadata: %s", fido_strerr(r));
420afa8e06SEd Maste goto out;
430afa8e06SEd Maste }
440afa8e06SEd Maste
450afa8e06SEd Maste printf("existing rk(s): %u\n",
460afa8e06SEd Maste (unsigned)fido_credman_rk_existing(metadata));
470afa8e06SEd Maste printf("remaining rk(s): %u\n",
480afa8e06SEd Maste (unsigned)fido_credman_rk_remaining(metadata));
490afa8e06SEd Maste
500afa8e06SEd Maste ok = 0;
510afa8e06SEd Maste out:
520afa8e06SEd Maste fido_credman_metadata_free(&metadata);
530afa8e06SEd Maste fido_dev_close(dev);
540afa8e06SEd Maste fido_dev_free(&dev);
550afa8e06SEd Maste
560afa8e06SEd Maste exit(ok);
570afa8e06SEd Maste }
580afa8e06SEd Maste
590afa8e06SEd Maste static int
print_rp(fido_credman_rp_t * rp,size_t idx)600afa8e06SEd Maste print_rp(fido_credman_rp_t *rp, size_t idx)
610afa8e06SEd Maste {
620afa8e06SEd Maste char *rp_id_hash = NULL;
630afa8e06SEd Maste
640afa8e06SEd Maste if (base64_encode(fido_credman_rp_id_hash_ptr(rp, idx),
650afa8e06SEd Maste fido_credman_rp_id_hash_len(rp, idx), &rp_id_hash) < 0) {
660afa8e06SEd Maste warnx("output error");
670afa8e06SEd Maste return -1;
680afa8e06SEd Maste }
690afa8e06SEd Maste printf("%02u: %s %s\n", (unsigned)idx, rp_id_hash,
700afa8e06SEd Maste fido_credman_rp_id(rp, idx));
710afa8e06SEd Maste free(rp_id_hash);
720afa8e06SEd Maste
730afa8e06SEd Maste return 0;
740afa8e06SEd Maste }
750afa8e06SEd Maste
760afa8e06SEd Maste int
credman_list_rp(const char * path)770afa8e06SEd Maste credman_list_rp(const char *path)
780afa8e06SEd Maste {
790afa8e06SEd Maste fido_credman_rp_t *rp = NULL;
800afa8e06SEd Maste fido_dev_t *dev = NULL;
810afa8e06SEd Maste char *pin = NULL;
820afa8e06SEd Maste int r, ok = 1;
830afa8e06SEd Maste
840afa8e06SEd Maste dev = open_dev(path);
850afa8e06SEd Maste if ((rp = fido_credman_rp_new()) == NULL) {
860afa8e06SEd Maste warnx("fido_credman_rp_new");
870afa8e06SEd Maste goto out;
880afa8e06SEd Maste }
890afa8e06SEd Maste if ((r = fido_credman_get_dev_rp(dev, rp, NULL)) != FIDO_OK &&
900afa8e06SEd Maste should_retry_with_pin(dev, r)) {
910afa8e06SEd Maste if ((pin = get_pin(path)) == NULL)
920afa8e06SEd Maste goto out;
930afa8e06SEd Maste r = fido_credman_get_dev_rp(dev, rp, pin);
940afa8e06SEd Maste freezero(pin, PINBUF_LEN);
950afa8e06SEd Maste pin = NULL;
960afa8e06SEd Maste }
970afa8e06SEd Maste if (r != FIDO_OK) {
980afa8e06SEd Maste warnx("fido_credman_get_dev_rp: %s", fido_strerr(r));
990afa8e06SEd Maste goto out;
1000afa8e06SEd Maste }
1010afa8e06SEd Maste for (size_t i = 0; i < fido_credman_rp_count(rp); i++)
1020afa8e06SEd Maste if (print_rp(rp, i) < 0)
1030afa8e06SEd Maste goto out;
1040afa8e06SEd Maste
1050afa8e06SEd Maste ok = 0;
1060afa8e06SEd Maste out:
1070afa8e06SEd Maste fido_credman_rp_free(&rp);
1080afa8e06SEd Maste fido_dev_close(dev);
1090afa8e06SEd Maste fido_dev_free(&dev);
1100afa8e06SEd Maste
1110afa8e06SEd Maste exit(ok);
1120afa8e06SEd Maste }
1130afa8e06SEd Maste
1140afa8e06SEd Maste static int
print_rk(const fido_credman_rk_t * rk,size_t idx)1150afa8e06SEd Maste print_rk(const fido_credman_rk_t *rk, size_t idx)
1160afa8e06SEd Maste {
1170afa8e06SEd Maste const fido_cred_t *cred;
1180afa8e06SEd Maste char *id = NULL;
1190afa8e06SEd Maste char *user_id = NULL;
1200afa8e06SEd Maste const char *type;
1210afa8e06SEd Maste const char *prot;
1220afa8e06SEd Maste
1230afa8e06SEd Maste if ((cred = fido_credman_rk(rk, idx)) == NULL) {
1240afa8e06SEd Maste warnx("fido_credman_rk");
1250afa8e06SEd Maste return -1;
1260afa8e06SEd Maste }
1270afa8e06SEd Maste if (base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred),
1280afa8e06SEd Maste &id) < 0 || base64_encode(fido_cred_user_id_ptr(cred),
1290afa8e06SEd Maste fido_cred_user_id_len(cred), &user_id) < 0) {
1300afa8e06SEd Maste warnx("output error");
1310afa8e06SEd Maste return -1;
1320afa8e06SEd Maste }
1330afa8e06SEd Maste
1340afa8e06SEd Maste type = cose_string(fido_cred_type(cred));
1350afa8e06SEd Maste prot = prot_string(fido_cred_prot(cred));
1360afa8e06SEd Maste
1370afa8e06SEd Maste printf("%02u: %s %s %s %s %s\n", (unsigned)idx, id,
1380afa8e06SEd Maste fido_cred_display_name(cred), user_id, type, prot);
1390afa8e06SEd Maste
1400afa8e06SEd Maste free(user_id);
1410afa8e06SEd Maste free(id);
1420afa8e06SEd Maste
1430afa8e06SEd Maste return 0;
1440afa8e06SEd Maste }
1450afa8e06SEd Maste
1460afa8e06SEd Maste int
credman_list_rk(const char * path,const char * rp_id)1470afa8e06SEd Maste credman_list_rk(const char *path, const char *rp_id)
1480afa8e06SEd Maste {
1490afa8e06SEd Maste fido_dev_t *dev = NULL;
1500afa8e06SEd Maste fido_credman_rk_t *rk = NULL;
1510afa8e06SEd Maste char *pin = NULL;
1520afa8e06SEd Maste int r, ok = 1;
1530afa8e06SEd Maste
1540afa8e06SEd Maste dev = open_dev(path);
1550afa8e06SEd Maste if ((rk = fido_credman_rk_new()) == NULL) {
1560afa8e06SEd Maste warnx("fido_credman_rk_new");
1570afa8e06SEd Maste goto out;
1580afa8e06SEd Maste }
1590afa8e06SEd Maste if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, NULL)) != FIDO_OK &&
1600afa8e06SEd Maste should_retry_with_pin(dev, r)) {
1610afa8e06SEd Maste if ((pin = get_pin(path)) == NULL)
1620afa8e06SEd Maste goto out;
1630afa8e06SEd Maste r = fido_credman_get_dev_rk(dev, rp_id, rk, pin);
1640afa8e06SEd Maste freezero(pin, PINBUF_LEN);
1650afa8e06SEd Maste pin = NULL;
1660afa8e06SEd Maste }
1670afa8e06SEd Maste if (r != FIDO_OK) {
1680afa8e06SEd Maste warnx("fido_credman_get_dev_rk: %s", fido_strerr(r));
1690afa8e06SEd Maste goto out;
1700afa8e06SEd Maste }
1710afa8e06SEd Maste for (size_t i = 0; i < fido_credman_rk_count(rk); i++)
1720afa8e06SEd Maste if (print_rk(rk, i) < 0)
1730afa8e06SEd Maste goto out;
1740afa8e06SEd Maste
1750afa8e06SEd Maste ok = 0;
1760afa8e06SEd Maste out:
1770afa8e06SEd Maste fido_credman_rk_free(&rk);
1780afa8e06SEd Maste fido_dev_close(dev);
1790afa8e06SEd Maste fido_dev_free(&dev);
1800afa8e06SEd Maste
1810afa8e06SEd Maste exit(ok);
1820afa8e06SEd Maste }
1830afa8e06SEd Maste
1840afa8e06SEd Maste int
credman_print_rk(fido_dev_t * dev,const char * path,const char * rp_id,const char * cred_id)1850afa8e06SEd Maste credman_print_rk(fido_dev_t *dev, const char *path, const char *rp_id,
1860afa8e06SEd Maste const char *cred_id)
1870afa8e06SEd Maste {
1880afa8e06SEd Maste fido_credman_rk_t *rk = NULL;
1890afa8e06SEd Maste const fido_cred_t *cred = NULL;
1900afa8e06SEd Maste char *pin = NULL;
1910afa8e06SEd Maste void *cred_id_ptr = NULL;
1920afa8e06SEd Maste size_t cred_id_len = 0;
1930afa8e06SEd Maste int r, ok = 1;
1940afa8e06SEd Maste
1950afa8e06SEd Maste if ((rk = fido_credman_rk_new()) == NULL) {
1960afa8e06SEd Maste warnx("fido_credman_rk_new");
1970afa8e06SEd Maste goto out;
1980afa8e06SEd Maste }
1990afa8e06SEd Maste if (base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) {
2000afa8e06SEd Maste warnx("base64_decode");
2010afa8e06SEd Maste goto out;
2020afa8e06SEd Maste }
2030afa8e06SEd Maste if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, NULL)) != FIDO_OK &&
2040afa8e06SEd Maste should_retry_with_pin(dev, r)) {
2050afa8e06SEd Maste if ((pin = get_pin(path)) == NULL)
2060afa8e06SEd Maste goto out;
2070afa8e06SEd Maste r = fido_credman_get_dev_rk(dev, rp_id, rk, pin);
2080afa8e06SEd Maste freezero(pin, PINBUF_LEN);
2090afa8e06SEd Maste pin = NULL;
2100afa8e06SEd Maste }
2110afa8e06SEd Maste if (r != FIDO_OK) {
2120afa8e06SEd Maste warnx("fido_credman_get_dev_rk: %s", fido_strerr(r));
2130afa8e06SEd Maste goto out;
2140afa8e06SEd Maste }
2150afa8e06SEd Maste
2160afa8e06SEd Maste for (size_t i = 0; i < fido_credman_rk_count(rk); i++) {
2170afa8e06SEd Maste if ((cred = fido_credman_rk(rk, i)) == NULL ||
2180afa8e06SEd Maste fido_cred_id_ptr(cred) == NULL) {
2190afa8e06SEd Maste warnx("output error");
2200afa8e06SEd Maste goto out;
2210afa8e06SEd Maste }
2220afa8e06SEd Maste if (cred_id_len != fido_cred_id_len(cred) ||
2230afa8e06SEd Maste memcmp(cred_id_ptr, fido_cred_id_ptr(cred), cred_id_len))
2240afa8e06SEd Maste continue;
2250afa8e06SEd Maste print_cred(stdout, fido_cred_type(cred), cred);
2260afa8e06SEd Maste ok = 0;
2270afa8e06SEd Maste goto out;
2280afa8e06SEd Maste }
2290afa8e06SEd Maste
2300afa8e06SEd Maste warnx("credential not found");
2310afa8e06SEd Maste out:
2320afa8e06SEd Maste free(cred_id_ptr);
2330afa8e06SEd Maste fido_credman_rk_free(&rk);
2340afa8e06SEd Maste fido_dev_close(dev);
2350afa8e06SEd Maste fido_dev_free(&dev);
2360afa8e06SEd Maste
2370afa8e06SEd Maste exit(ok);
2380afa8e06SEd Maste }
2390afa8e06SEd Maste
2400afa8e06SEd Maste int
credman_delete_rk(const char * path,const char * id)2410afa8e06SEd Maste credman_delete_rk(const char *path, const char *id)
2420afa8e06SEd Maste {
2430afa8e06SEd Maste fido_dev_t *dev = NULL;
2440afa8e06SEd Maste char *pin = NULL;
2450afa8e06SEd Maste void *id_ptr = NULL;
2460afa8e06SEd Maste size_t id_len = 0;
2470afa8e06SEd Maste int r, ok = 1;
2480afa8e06SEd Maste
2490afa8e06SEd Maste dev = open_dev(path);
2500afa8e06SEd Maste if (base64_decode(id, &id_ptr, &id_len) < 0) {
2510afa8e06SEd Maste warnx("base64_decode");
2520afa8e06SEd Maste goto out;
2530afa8e06SEd Maste }
2540afa8e06SEd Maste if ((r = fido_credman_del_dev_rk(dev, id_ptr, id_len,
2550afa8e06SEd Maste NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) {
2560afa8e06SEd Maste if ((pin = get_pin(path)) == NULL)
2570afa8e06SEd Maste goto out;
2580afa8e06SEd Maste r = fido_credman_del_dev_rk(dev, id_ptr, id_len, pin);
2590afa8e06SEd Maste freezero(pin, PINBUF_LEN);
2600afa8e06SEd Maste pin = NULL;
2610afa8e06SEd Maste }
2620afa8e06SEd Maste if (r != FIDO_OK) {
2630afa8e06SEd Maste warnx("fido_credman_del_dev_rk: %s", fido_strerr(r));
2640afa8e06SEd Maste goto out;
2650afa8e06SEd Maste }
2660afa8e06SEd Maste
2670afa8e06SEd Maste ok = 0;
2680afa8e06SEd Maste out:
2690afa8e06SEd Maste free(id_ptr);
2700afa8e06SEd Maste fido_dev_close(dev);
2710afa8e06SEd Maste fido_dev_free(&dev);
2720afa8e06SEd Maste
2730afa8e06SEd Maste exit(ok);
2740afa8e06SEd Maste }
2750afa8e06SEd Maste
2760afa8e06SEd Maste int
credman_update_rk(const char * path,const char * user_id,const char * cred_id,const char * name,const char * display_name)2770afa8e06SEd Maste credman_update_rk(const char *path, const char *user_id, const char *cred_id,
2780afa8e06SEd Maste const char *name, const char *display_name)
2790afa8e06SEd Maste {
2800afa8e06SEd Maste fido_dev_t *dev = NULL;
2810afa8e06SEd Maste fido_cred_t *cred = NULL;
2820afa8e06SEd Maste char *pin = NULL;
2830afa8e06SEd Maste void *user_id_ptr = NULL;
2840afa8e06SEd Maste void *cred_id_ptr = NULL;
2850afa8e06SEd Maste size_t user_id_len = 0;
2860afa8e06SEd Maste size_t cred_id_len = 0;
2870afa8e06SEd Maste int r, ok = 1;
2880afa8e06SEd Maste
2890afa8e06SEd Maste dev = open_dev(path);
2900afa8e06SEd Maste if (base64_decode(user_id, &user_id_ptr, &user_id_len) < 0 ||
2910afa8e06SEd Maste base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) {
2920afa8e06SEd Maste warnx("base64_decode");
2930afa8e06SEd Maste goto out;
2940afa8e06SEd Maste }
2950afa8e06SEd Maste if ((cred = fido_cred_new()) == NULL) {
2960afa8e06SEd Maste warnx("fido_cred_new");
2970afa8e06SEd Maste goto out;
2980afa8e06SEd Maste }
2990afa8e06SEd Maste if ((r = fido_cred_set_id(cred, cred_id_ptr, cred_id_len)) != FIDO_OK) {
3000afa8e06SEd Maste warnx("fido_cred_set_id: %s", fido_strerr(r));
3010afa8e06SEd Maste goto out;
3020afa8e06SEd Maste }
3030afa8e06SEd Maste if ((r = fido_cred_set_user(cred, user_id_ptr, user_id_len, name,
3040afa8e06SEd Maste display_name, NULL)) != FIDO_OK) {
3050afa8e06SEd Maste warnx("fido_cred_set_user: %s", fido_strerr(r));
3060afa8e06SEd Maste goto out;
3070afa8e06SEd Maste }
3080afa8e06SEd Maste if ((r = fido_credman_set_dev_rk(dev, cred, NULL)) != FIDO_OK &&
3090afa8e06SEd Maste should_retry_with_pin(dev, r)) {
3100afa8e06SEd Maste if ((pin = get_pin(path)) == NULL)
3110afa8e06SEd Maste goto out;
3120afa8e06SEd Maste r = fido_credman_set_dev_rk(dev, cred, pin);
3130afa8e06SEd Maste freezero(pin, PINBUF_LEN);
3140afa8e06SEd Maste pin = NULL;
3150afa8e06SEd Maste }
3160afa8e06SEd Maste if (r != FIDO_OK) {
3170afa8e06SEd Maste warnx("fido_credman_set_dev_rk: %s", fido_strerr(r));
3180afa8e06SEd Maste goto out;
3190afa8e06SEd Maste }
3200afa8e06SEd Maste
3210afa8e06SEd Maste ok = 0;
3220afa8e06SEd Maste out:
3230afa8e06SEd Maste free(user_id_ptr);
3240afa8e06SEd Maste free(cred_id_ptr);
3250afa8e06SEd Maste fido_dev_close(dev);
3260afa8e06SEd Maste fido_dev_free(&dev);
3270afa8e06SEd Maste fido_cred_free(&cred);
3280afa8e06SEd Maste
3290afa8e06SEd Maste exit(ok);
3300afa8e06SEd Maste }
331