xref: /netbsd-src/external/bsd/libfido2/dist/tools/credman.c (revision 2d40c4512a84c0d064ec30a492c5e2a14d230bc3)
1ba9bdd8bSchristos /*
2ba9bdd8bSchristos  * Copyright (c) 2019 Yubico AB. All rights reserved.
3ba9bdd8bSchristos  * Use of this source code is governed by a BSD-style
4ba9bdd8bSchristos  * license that can be found in the LICENSE file.
5*2d40c451Schristos  * SPDX-License-Identifier: BSD-2-Clause
6ba9bdd8bSchristos  */
7ba9bdd8bSchristos 
8ba9bdd8bSchristos #include <fido.h>
9ba9bdd8bSchristos #include <fido/credman.h>
10ba9bdd8bSchristos 
11ba9bdd8bSchristos #include <stdio.h>
12ba9bdd8bSchristos #include <stdlib.h>
13ba9bdd8bSchristos #include <string.h>
14ba9bdd8bSchristos #ifdef HAVE_UNISTD_H
15ba9bdd8bSchristos #include <unistd.h>
16ba9bdd8bSchristos #endif
17ba9bdd8bSchristos 
18ba9bdd8bSchristos #include "../openbsd-compat/openbsd-compat.h"
19ba9bdd8bSchristos #include "extern.h"
20ba9bdd8bSchristos 
21ba9bdd8bSchristos int
credman_get_metadata(fido_dev_t * dev,const char * path)22ba9bdd8bSchristos credman_get_metadata(fido_dev_t *dev, const char *path)
23ba9bdd8bSchristos {
24ba9bdd8bSchristos 	fido_credman_metadata_t *metadata = NULL;
2595dbdf32Schristos 	char *pin = NULL;
2695dbdf32Schristos 	int r, ok = 1;
27ba9bdd8bSchristos 
2895dbdf32Schristos 	if ((metadata = fido_credman_metadata_new()) == NULL) {
2995dbdf32Schristos 		warnx("fido_credman_metadata_new");
3095dbdf32Schristos 		goto out;
3195dbdf32Schristos 	}
3295dbdf32Schristos 	if ((r = fido_credman_get_dev_metadata(dev, metadata,
3395dbdf32Schristos 	    NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) {
3495dbdf32Schristos 		if ((pin = get_pin(path)) == NULL)
3595dbdf32Schristos 			goto out;
36ba9bdd8bSchristos 		r = fido_credman_get_dev_metadata(dev, metadata, pin);
3795dbdf32Schristos 		freezero(pin, PINBUF_LEN);
3895dbdf32Schristos 		pin = NULL;
3995dbdf32Schristos 	}
4095dbdf32Schristos 	if (r != FIDO_OK) {
4195dbdf32Schristos 		warnx("fido_credman_get_dev_metadata: %s", fido_strerr(r));
4295dbdf32Schristos 		goto out;
4395dbdf32Schristos 	}
44ba9bdd8bSchristos 
45ba9bdd8bSchristos 	printf("existing rk(s): %u\n",
46ba9bdd8bSchristos 	    (unsigned)fido_credman_rk_existing(metadata));
471fc1e710Schristos 	printf("remaining rk(s): %u\n",
48ba9bdd8bSchristos 	    (unsigned)fido_credman_rk_remaining(metadata));
49ba9bdd8bSchristos 
5095dbdf32Schristos 	ok = 0;
5195dbdf32Schristos out:
52ba9bdd8bSchristos 	fido_credman_metadata_free(&metadata);
53ba9bdd8bSchristos 	fido_dev_close(dev);
54ba9bdd8bSchristos 	fido_dev_free(&dev);
55ba9bdd8bSchristos 
5695dbdf32Schristos 	exit(ok);
57ba9bdd8bSchristos }
58ba9bdd8bSchristos 
5995dbdf32Schristos static int
print_rp(fido_credman_rp_t * rp,size_t idx)60ba9bdd8bSchristos print_rp(fido_credman_rp_t *rp, size_t idx)
61ba9bdd8bSchristos {
62ba9bdd8bSchristos 	char *rp_id_hash = NULL;
63ba9bdd8bSchristos 
64ba9bdd8bSchristos 	if (base64_encode(fido_credman_rp_id_hash_ptr(rp, idx),
6595dbdf32Schristos 	    fido_credman_rp_id_hash_len(rp, idx), &rp_id_hash) < 0) {
6695dbdf32Schristos 		warnx("output error");
6795dbdf32Schristos 		return -1;
6895dbdf32Schristos 	}
69ba9bdd8bSchristos 	printf("%02u: %s %s\n", (unsigned)idx, rp_id_hash,
70ba9bdd8bSchristos 	    fido_credman_rp_id(rp, idx));
71ba9bdd8bSchristos 	free(rp_id_hash);
7295dbdf32Schristos 
7395dbdf32Schristos 	return 0;
74ba9bdd8bSchristos }
75ba9bdd8bSchristos 
76ba9bdd8bSchristos int
credman_list_rp(const char * path)7795dbdf32Schristos credman_list_rp(const char *path)
78ba9bdd8bSchristos {
79ba9bdd8bSchristos 	fido_credman_rp_t *rp = NULL;
8095dbdf32Schristos 	fido_dev_t *dev = NULL;
8195dbdf32Schristos 	char *pin = NULL;
8295dbdf32Schristos 	int r, ok = 1;
83ba9bdd8bSchristos 
84ba9bdd8bSchristos 	dev = open_dev(path);
8595dbdf32Schristos 	if ((rp = fido_credman_rp_new()) == NULL) {
8695dbdf32Schristos 		warnx("fido_credman_rp_new");
8795dbdf32Schristos 		goto out;
8895dbdf32Schristos 	}
8995dbdf32Schristos 	if ((r = fido_credman_get_dev_rp(dev, rp, NULL)) != FIDO_OK &&
9095dbdf32Schristos 	    should_retry_with_pin(dev, r)) {
9195dbdf32Schristos 		if ((pin = get_pin(path)) == NULL)
9295dbdf32Schristos 			goto out;
93ba9bdd8bSchristos 		r = fido_credman_get_dev_rp(dev, rp, pin);
9495dbdf32Schristos 		freezero(pin, PINBUF_LEN);
9595dbdf32Schristos 		pin = NULL;
9695dbdf32Schristos 	}
9795dbdf32Schristos 	if (r != FIDO_OK) {
9895dbdf32Schristos 		warnx("fido_credman_get_dev_rp: %s", fido_strerr(r));
9995dbdf32Schristos 		goto out;
10095dbdf32Schristos 	}
101ba9bdd8bSchristos 	for (size_t i = 0; i < fido_credman_rp_count(rp); i++)
10295dbdf32Schristos 		if (print_rp(rp, i) < 0)
10395dbdf32Schristos 			goto out;
104ba9bdd8bSchristos 
10595dbdf32Schristos 	ok = 0;
10695dbdf32Schristos out:
107ba9bdd8bSchristos 	fido_credman_rp_free(&rp);
108ba9bdd8bSchristos 	fido_dev_close(dev);
109ba9bdd8bSchristos 	fido_dev_free(&dev);
110ba9bdd8bSchristos 
11195dbdf32Schristos 	exit(ok);
112ba9bdd8bSchristos }
113ba9bdd8bSchristos 
11495dbdf32Schristos static int
print_rk(const fido_credman_rk_t * rk,size_t idx)115ba9bdd8bSchristos print_rk(const fido_credman_rk_t *rk, size_t idx)
116ba9bdd8bSchristos {
117ba9bdd8bSchristos 	const fido_cred_t *cred;
118ba9bdd8bSchristos 	char *id = NULL;
119ba9bdd8bSchristos 	char *user_id = NULL;
120ba9bdd8bSchristos 	const char *type;
1211fc1e710Schristos 	const char *prot;
122ba9bdd8bSchristos 
12395dbdf32Schristos 	if ((cred = fido_credman_rk(rk, idx)) == NULL) {
12495dbdf32Schristos 		warnx("fido_credman_rk");
12595dbdf32Schristos 		return -1;
12695dbdf32Schristos 	}
127ba9bdd8bSchristos 	if (base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred),
128ba9bdd8bSchristos 	    &id) < 0 || base64_encode(fido_cred_user_id_ptr(cred),
12995dbdf32Schristos 	    fido_cred_user_id_len(cred), &user_id) < 0) {
13095dbdf32Schristos 		warnx("output error");
13195dbdf32Schristos 		return -1;
13295dbdf32Schristos 	}
133ba9bdd8bSchristos 
1341fc1e710Schristos 	type = cose_string(fido_cred_type(cred));
1351fc1e710Schristos 	prot = prot_string(fido_cred_prot(cred));
136ba9bdd8bSchristos 
1371fc1e710Schristos 	printf("%02u: %s %s %s %s %s\n", (unsigned)idx, id,
1381fc1e710Schristos 	    fido_cred_display_name(cred), user_id, type, prot);
139ba9bdd8bSchristos 
140ba9bdd8bSchristos 	free(user_id);
141ba9bdd8bSchristos 	free(id);
14295dbdf32Schristos 
14395dbdf32Schristos 	return 0;
144ba9bdd8bSchristos }
145ba9bdd8bSchristos 
146ba9bdd8bSchristos int
credman_list_rk(const char * path,const char * rp_id)14795dbdf32Schristos credman_list_rk(const char *path, const char *rp_id)
148ba9bdd8bSchristos {
149ba9bdd8bSchristos 	fido_dev_t *dev = NULL;
150ba9bdd8bSchristos 	fido_credman_rk_t *rk = NULL;
15195dbdf32Schristos 	char *pin = NULL;
15295dbdf32Schristos 	int r, ok = 1;
153ba9bdd8bSchristos 
154ba9bdd8bSchristos 	dev = open_dev(path);
15595dbdf32Schristos 	if ((rk = fido_credman_rk_new()) == NULL) {
15695dbdf32Schristos 		warnx("fido_credman_rk_new");
15795dbdf32Schristos 		goto out;
15895dbdf32Schristos 	}
15995dbdf32Schristos 	if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, NULL)) != FIDO_OK &&
16095dbdf32Schristos 	    should_retry_with_pin(dev, r)) {
16195dbdf32Schristos 		if ((pin = get_pin(path)) == NULL)
16295dbdf32Schristos 			goto out;
163ba9bdd8bSchristos 		r = fido_credman_get_dev_rk(dev, rp_id, rk, pin);
16495dbdf32Schristos 		freezero(pin, PINBUF_LEN);
16595dbdf32Schristos 		pin = NULL;
16695dbdf32Schristos 	}
16795dbdf32Schristos 	if (r != FIDO_OK) {
16895dbdf32Schristos 		warnx("fido_credman_get_dev_rk: %s", fido_strerr(r));
16995dbdf32Schristos 		goto out;
17095dbdf32Schristos 	}
171ba9bdd8bSchristos 	for (size_t i = 0; i < fido_credman_rk_count(rk); i++)
17295dbdf32Schristos 		if (print_rk(rk, i) < 0)
17395dbdf32Schristos 			goto out;
174ba9bdd8bSchristos 
17595dbdf32Schristos 	ok = 0;
17695dbdf32Schristos out:
177ba9bdd8bSchristos 	fido_credman_rk_free(&rk);
178ba9bdd8bSchristos 	fido_dev_close(dev);
179ba9bdd8bSchristos 	fido_dev_free(&dev);
180ba9bdd8bSchristos 
18195dbdf32Schristos 	exit(ok);
182ba9bdd8bSchristos }
183ba9bdd8bSchristos 
184ba9bdd8bSchristos int
credman_print_rk(fido_dev_t * dev,const char * path,const char * rp_id,const char * cred_id)18595dbdf32Schristos credman_print_rk(fido_dev_t *dev, const char *path, const char *rp_id,
18695dbdf32Schristos     const char *cred_id)
187ba9bdd8bSchristos {
188ba9bdd8bSchristos 	fido_credman_rk_t *rk = NULL;
18995dbdf32Schristos 	const fido_cred_t *cred = NULL;
19095dbdf32Schristos 	char *pin = NULL;
191ba9bdd8bSchristos 	void *cred_id_ptr = NULL;
192ba9bdd8bSchristos 	size_t cred_id_len = 0;
19395dbdf32Schristos 	int r, ok = 1;
194ba9bdd8bSchristos 
19595dbdf32Schristos 	if ((rk = fido_credman_rk_new()) == NULL) {
19695dbdf32Schristos 		warnx("fido_credman_rk_new");
19795dbdf32Schristos 		goto out;
19895dbdf32Schristos 	}
19995dbdf32Schristos 	if (base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) {
20095dbdf32Schristos 		warnx("base64_decode");
20195dbdf32Schristos 		goto out;
20295dbdf32Schristos 	}
20395dbdf32Schristos 	if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, NULL)) != FIDO_OK &&
20495dbdf32Schristos 	    should_retry_with_pin(dev, r)) {
20595dbdf32Schristos 		if ((pin = get_pin(path)) == NULL)
20695dbdf32Schristos 			goto out;
207ba9bdd8bSchristos 		r = fido_credman_get_dev_rk(dev, rp_id, rk, pin);
20895dbdf32Schristos 		freezero(pin, PINBUF_LEN);
20995dbdf32Schristos 		pin = NULL;
21095dbdf32Schristos 	}
21195dbdf32Schristos 	if (r != FIDO_OK) {
21295dbdf32Schristos 		warnx("fido_credman_get_dev_rk: %s", fido_strerr(r));
21395dbdf32Schristos 		goto out;
21495dbdf32Schristos 	}
215ba9bdd8bSchristos 
216ba9bdd8bSchristos 	for (size_t i = 0; i < fido_credman_rk_count(rk); i++) {
217ba9bdd8bSchristos 		if ((cred = fido_credman_rk(rk, i)) == NULL ||
21895dbdf32Schristos 		    fido_cred_id_ptr(cred) == NULL) {
21995dbdf32Schristos 			warnx("output error");
22095dbdf32Schristos 			goto out;
22195dbdf32Schristos 		}
222ba9bdd8bSchristos 		if (cred_id_len != fido_cred_id_len(cred) ||
223ba9bdd8bSchristos 		    memcmp(cred_id_ptr, fido_cred_id_ptr(cred), cred_id_len))
224ba9bdd8bSchristos 			continue;
225ba9bdd8bSchristos 		print_cred(stdout, fido_cred_type(cred), cred);
22695dbdf32Schristos 		ok = 0;
227ba9bdd8bSchristos 		goto out;
228ba9bdd8bSchristos 	}
229ba9bdd8bSchristos 
23095dbdf32Schristos 	warnx("credential not found");
231ba9bdd8bSchristos out:
232ba9bdd8bSchristos 	free(cred_id_ptr);
233ba9bdd8bSchristos 	fido_credman_rk_free(&rk);
234ba9bdd8bSchristos 	fido_dev_close(dev);
235ba9bdd8bSchristos 	fido_dev_free(&dev);
236ba9bdd8bSchristos 
23795dbdf32Schristos 	exit(ok);
238ba9bdd8bSchristos }
239ba9bdd8bSchristos 
240ba9bdd8bSchristos int
credman_delete_rk(const char * path,const char * id)24195dbdf32Schristos credman_delete_rk(const char *path, const char *id)
242ba9bdd8bSchristos {
24395dbdf32Schristos 	fido_dev_t *dev = NULL;
24495dbdf32Schristos 	char *pin = NULL;
245ba9bdd8bSchristos 	void *id_ptr = NULL;
246ba9bdd8bSchristos 	size_t id_len = 0;
24795dbdf32Schristos 	int r, ok = 1;
248ba9bdd8bSchristos 
24995dbdf32Schristos 	dev = open_dev(path);
25095dbdf32Schristos 	if (base64_decode(id, &id_ptr, &id_len) < 0) {
25195dbdf32Schristos 		warnx("base64_decode");
25295dbdf32Schristos 		goto out;
25395dbdf32Schristos 	}
25495dbdf32Schristos 	if ((r = fido_credman_del_dev_rk(dev, id_ptr, id_len,
25595dbdf32Schristos 	    NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) {
25695dbdf32Schristos 		if ((pin = get_pin(path)) == NULL)
25795dbdf32Schristos 			goto out;
258ba9bdd8bSchristos 		r = fido_credman_del_dev_rk(dev, id_ptr, id_len, pin);
25995dbdf32Schristos 		freezero(pin, PINBUF_LEN);
26095dbdf32Schristos 		pin = NULL;
26195dbdf32Schristos 	}
26295dbdf32Schristos 	if (r != FIDO_OK) {
26395dbdf32Schristos 		warnx("fido_credman_del_dev_rk: %s", fido_strerr(r));
26495dbdf32Schristos 		goto out;
26595dbdf32Schristos 	}
266ba9bdd8bSchristos 
26795dbdf32Schristos 	ok = 0;
26895dbdf32Schristos out:
269ba9bdd8bSchristos 	free(id_ptr);
270ba9bdd8bSchristos 	fido_dev_close(dev);
271ba9bdd8bSchristos 	fido_dev_free(&dev);
272ba9bdd8bSchristos 
27395dbdf32Schristos 	exit(ok);
274ba9bdd8bSchristos }
275ede6d7f8Schristos 
276ede6d7f8Schristos int
credman_update_rk(const char * path,const char * user_id,const char * cred_id,const char * name,const char * display_name)277ede6d7f8Schristos credman_update_rk(const char *path, const char *user_id, const char *cred_id,
278ede6d7f8Schristos     const char *name, const char *display_name)
279ede6d7f8Schristos {
280ede6d7f8Schristos 	fido_dev_t *dev = NULL;
281ede6d7f8Schristos 	fido_cred_t *cred = NULL;
282ede6d7f8Schristos 	char *pin = NULL;
283ede6d7f8Schristos 	void *user_id_ptr = NULL;
284ede6d7f8Schristos 	void *cred_id_ptr = NULL;
285ede6d7f8Schristos 	size_t user_id_len = 0;
286ede6d7f8Schristos 	size_t cred_id_len = 0;
287ede6d7f8Schristos 	int r, ok = 1;
288ede6d7f8Schristos 
289ede6d7f8Schristos 	dev = open_dev(path);
290ede6d7f8Schristos 	if (base64_decode(user_id, &user_id_ptr, &user_id_len) < 0 ||
291ede6d7f8Schristos 	    base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) {
292ede6d7f8Schristos 		warnx("base64_decode");
293ede6d7f8Schristos 		goto out;
294ede6d7f8Schristos 	}
295ede6d7f8Schristos 	if ((cred = fido_cred_new()) == NULL) {
296ede6d7f8Schristos 		warnx("fido_cred_new");
297ede6d7f8Schristos 		goto out;
298ede6d7f8Schristos 	}
299ede6d7f8Schristos 	if ((r = fido_cred_set_id(cred, cred_id_ptr, cred_id_len)) != FIDO_OK) {
300ede6d7f8Schristos 		warnx("fido_cred_set_id: %s",  fido_strerr(r));
301ede6d7f8Schristos 		goto out;
302ede6d7f8Schristos 	}
303ede6d7f8Schristos 	if ((r = fido_cred_set_user(cred, user_id_ptr, user_id_len, name,
304ede6d7f8Schristos 	    display_name, NULL)) != FIDO_OK) {
305ede6d7f8Schristos 		warnx("fido_cred_set_user: %s", fido_strerr(r));
306ede6d7f8Schristos 		goto out;
307ede6d7f8Schristos 	}
308ede6d7f8Schristos 	if ((r = fido_credman_set_dev_rk(dev, cred, NULL)) != FIDO_OK &&
309ede6d7f8Schristos 	    should_retry_with_pin(dev, r)) {
310ede6d7f8Schristos 		if ((pin = get_pin(path)) == NULL)
311ede6d7f8Schristos 			goto out;
312ede6d7f8Schristos 		r = fido_credman_set_dev_rk(dev, cred, pin);
313ede6d7f8Schristos 		freezero(pin, PINBUF_LEN);
314ede6d7f8Schristos 		pin = NULL;
315ede6d7f8Schristos 	}
316ede6d7f8Schristos 	if (r != FIDO_OK) {
317ede6d7f8Schristos 		warnx("fido_credman_set_dev_rk: %s", fido_strerr(r));
318ede6d7f8Schristos 		goto out;
319ede6d7f8Schristos 	}
320ede6d7f8Schristos 
321ede6d7f8Schristos 	ok = 0;
322ede6d7f8Schristos out:
323ede6d7f8Schristos 	free(user_id_ptr);
324ede6d7f8Schristos 	free(cred_id_ptr);
325ede6d7f8Schristos 	fido_dev_close(dev);
326ede6d7f8Schristos 	fido_dev_free(&dev);
327ede6d7f8Schristos 	fido_cred_free(&cred);
328ede6d7f8Schristos 
329ede6d7f8Schristos 	exit(ok);
330ede6d7f8Schristos }
331