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