xref: /freebsd/contrib/libfido2/tools/credman.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
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