mirror of
https://github.com/token2/fido2-manage.git
synced 2026-04-09 18:55:38 +00:00
Add files via upload
This commit is contained in:
55
tools/CMakeLists.txt
Normal file
55
tools/CMakeLists.txt
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Copyright (c) 2018-2022 Yubico AB. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
list(APPEND COMPAT_SOURCES
|
||||||
|
../openbsd-compat/bsd-getpagesize.c
|
||||||
|
../openbsd-compat/explicit_bzero.c
|
||||||
|
../openbsd-compat/freezero.c
|
||||||
|
../openbsd-compat/recallocarray.c
|
||||||
|
../openbsd-compat/strlcat.c
|
||||||
|
../openbsd-compat/strlcpy.c
|
||||||
|
../openbsd-compat/strsep.c
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32 AND NOT CYGWIN AND NOT MSYS)
|
||||||
|
list(APPEND COMPAT_SOURCES
|
||||||
|
../openbsd-compat/bsd-getline.c
|
||||||
|
../openbsd-compat/endian_win32.c
|
||||||
|
../openbsd-compat/explicit_bzero_win32.c
|
||||||
|
../openbsd-compat/getopt_long.c
|
||||||
|
../openbsd-compat/readpassphrase_win32.c
|
||||||
|
)
|
||||||
|
if (BUILD_SHARED_LIBS)
|
||||||
|
list(APPEND COMPAT_SOURCES ../openbsd-compat/posix_win.c)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
list(APPEND COMPAT_SOURCES ../openbsd-compat/readpassphrase.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_source_files_properties(assert_get.c assert_verify.c base64.c bio.c
|
||||||
|
config.c cred_make.c cred_verify.c credman.c
|
||||||
|
fido2-token.c pin.c token.c util.c
|
||||||
|
PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
add_executable(fido2-token
|
||||||
|
fido2-token.c
|
||||||
|
base64.c
|
||||||
|
bio.c
|
||||||
|
config.c
|
||||||
|
credman.c
|
||||||
|
largeblob.c
|
||||||
|
pin.c
|
||||||
|
token.c
|
||||||
|
util.c
|
||||||
|
${COMPAT_SOURCES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(fido2-token ${CRYPTO_LIBRARIES} ${_FIDO2_LIBRARY})
|
||||||
|
|
||||||
|
install(TARGETS fido2-token
|
||||||
|
DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
328
tools/assert_get.c
Normal file
328
tools/assert_get.c
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2023 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
struct toggle {
|
||||||
|
fido_opt_t up;
|
||||||
|
fido_opt_t uv;
|
||||||
|
fido_opt_t pin;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
opt2str(fido_opt_t v)
|
||||||
|
{
|
||||||
|
switch (v) {
|
||||||
|
case FIDO_OPT_OMIT:
|
||||||
|
return "omit";
|
||||||
|
case FIDO_OPT_TRUE:
|
||||||
|
return "true";
|
||||||
|
case FIDO_OPT_FALSE:
|
||||||
|
return "false";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_toggle(const char *str, struct toggle *opt)
|
||||||
|
{
|
||||||
|
fido_opt_t *k;
|
||||||
|
fido_opt_t v;
|
||||||
|
char *assignment;
|
||||||
|
char *key;
|
||||||
|
char *val;
|
||||||
|
|
||||||
|
if ((assignment = strdup(str)) == NULL)
|
||||||
|
err(1, "strdup");
|
||||||
|
if ((val = strchr(assignment, '=')) == NULL)
|
||||||
|
errx(1, "invalid assignment '%s'", assignment);
|
||||||
|
|
||||||
|
key = assignment;
|
||||||
|
*val++ = '\0';
|
||||||
|
|
||||||
|
if (!strcmp(val, "true"))
|
||||||
|
v = FIDO_OPT_TRUE;
|
||||||
|
else if (!strcmp(val, "false"))
|
||||||
|
v = FIDO_OPT_FALSE;
|
||||||
|
else
|
||||||
|
errx(1, "unknown value '%s'", val);
|
||||||
|
|
||||||
|
if (!strcmp(key, "up"))
|
||||||
|
k = &opt->up;
|
||||||
|
else if (!strcmp(key, "uv"))
|
||||||
|
k = &opt->uv;
|
||||||
|
else if (!strcmp(key, "pin"))
|
||||||
|
k = &opt->pin;
|
||||||
|
else
|
||||||
|
errx(1, "unknown key '%s'", key);
|
||||||
|
|
||||||
|
free(assignment);
|
||||||
|
|
||||||
|
*k = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fido_assert_t *
|
||||||
|
prepare_assert(FILE *in_f, int flags, const struct toggle *opt)
|
||||||
|
{
|
||||||
|
fido_assert_t *assert = NULL;
|
||||||
|
struct blob cdh;
|
||||||
|
struct blob id;
|
||||||
|
struct blob hmac_salt;
|
||||||
|
char *rpid = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
memset(&cdh, 0, sizeof(cdh));
|
||||||
|
memset(&id, 0, sizeof(id));
|
||||||
|
memset(&hmac_salt, 0, sizeof(hmac_salt));
|
||||||
|
|
||||||
|
r = base64_read(in_f, &cdh);
|
||||||
|
r |= string_read(in_f, &rpid);
|
||||||
|
if ((flags & FLAG_RK) == 0)
|
||||||
|
r |= base64_read(in_f, &id);
|
||||||
|
if (flags & FLAG_HMAC)
|
||||||
|
r |= base64_read(in_f, &hmac_salt);
|
||||||
|
if (r < 0)
|
||||||
|
errx(1, "input error");
|
||||||
|
|
||||||
|
if (flags & FLAG_DEBUG) {
|
||||||
|
fprintf(stderr, "client data%s:\n",
|
||||||
|
flags & FLAG_CD ? "" : " hash");
|
||||||
|
xxd(cdh.ptr, cdh.len);
|
||||||
|
fprintf(stderr, "relying party id: %s\n", rpid);
|
||||||
|
if ((flags & FLAG_RK) == 0) {
|
||||||
|
fprintf(stderr, "credential id:\n");
|
||||||
|
xxd(id.ptr, id.len);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "up=%s\n", opt2str(opt->up));
|
||||||
|
fprintf(stderr, "uv=%s\n", opt2str(opt->uv));
|
||||||
|
fprintf(stderr, "pin=%s\n", opt2str(opt->pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((assert = fido_assert_new()) == NULL)
|
||||||
|
errx(1, "fido_assert_new");
|
||||||
|
|
||||||
|
if (flags & FLAG_CD)
|
||||||
|
r = fido_assert_set_clientdata(assert, cdh.ptr, cdh.len);
|
||||||
|
else
|
||||||
|
r = fido_assert_set_clientdata_hash(assert, cdh.ptr, cdh.len);
|
||||||
|
|
||||||
|
if (r != FIDO_OK || (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set: %s", fido_strerr(r));
|
||||||
|
if ((r = fido_assert_set_up(assert, opt->up)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set_up: %s", fido_strerr(r));
|
||||||
|
if ((r = fido_assert_set_uv(assert, opt->uv)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set_uv: %s", fido_strerr(r));
|
||||||
|
|
||||||
|
if (flags & FLAG_HMAC) {
|
||||||
|
if ((r = fido_assert_set_extensions(assert,
|
||||||
|
FIDO_EXT_HMAC_SECRET)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set_extensions: %s",
|
||||||
|
fido_strerr(r));
|
||||||
|
if ((r = fido_assert_set_hmac_salt(assert, hmac_salt.ptr,
|
||||||
|
hmac_salt.len)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set_hmac_salt: %s",
|
||||||
|
fido_strerr(r));
|
||||||
|
}
|
||||||
|
if (flags & FLAG_LARGEBLOB) {
|
||||||
|
if ((r = fido_assert_set_extensions(assert,
|
||||||
|
FIDO_EXT_LARGEBLOB_KEY)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set_extensions: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
if ((flags & FLAG_RK) == 0) {
|
||||||
|
if ((r = fido_assert_allow_cred(assert, id.ptr,
|
||||||
|
id.len)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_allow_cred: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(hmac_salt.ptr);
|
||||||
|
free(cdh.ptr);
|
||||||
|
free(id.ptr);
|
||||||
|
free(rpid);
|
||||||
|
|
||||||
|
return (assert);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_assert(FILE *out_f, const fido_assert_t *assert, size_t idx, int flags)
|
||||||
|
{
|
||||||
|
char *cdh = NULL;
|
||||||
|
char *authdata = NULL;
|
||||||
|
char *sig = NULL;
|
||||||
|
char *user_id = NULL;
|
||||||
|
char *hmac_secret = NULL;
|
||||||
|
char *key = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = base64_encode(fido_assert_clientdata_hash_ptr(assert),
|
||||||
|
fido_assert_clientdata_hash_len(assert), &cdh);
|
||||||
|
r |= base64_encode(fido_assert_authdata_ptr(assert, idx),
|
||||||
|
fido_assert_authdata_len(assert, 0), &authdata);
|
||||||
|
r |= base64_encode(fido_assert_sig_ptr(assert, idx),
|
||||||
|
fido_assert_sig_len(assert, idx), &sig);
|
||||||
|
if (flags & FLAG_RK)
|
||||||
|
r |= base64_encode(fido_assert_user_id_ptr(assert, idx),
|
||||||
|
fido_assert_user_id_len(assert, idx), &user_id);
|
||||||
|
if (flags & FLAG_HMAC)
|
||||||
|
r |= base64_encode(fido_assert_hmac_secret_ptr(assert, idx),
|
||||||
|
fido_assert_hmac_secret_len(assert, idx), &hmac_secret);
|
||||||
|
if (flags & FLAG_LARGEBLOB)
|
||||||
|
r |= base64_encode(fido_assert_largeblob_key_ptr(assert, idx),
|
||||||
|
fido_assert_largeblob_key_len(assert, idx), &key);
|
||||||
|
if (r < 0)
|
||||||
|
errx(1, "output error");
|
||||||
|
|
||||||
|
fprintf(out_f, "%s\n", cdh);
|
||||||
|
fprintf(out_f, "%s\n", fido_assert_rp_id(assert));
|
||||||
|
fprintf(out_f, "%s\n", authdata);
|
||||||
|
fprintf(out_f, "%s\n", sig);
|
||||||
|
if (flags & FLAG_RK)
|
||||||
|
fprintf(out_f, "%s\n", user_id);
|
||||||
|
if (hmac_secret) {
|
||||||
|
fprintf(out_f, "%s\n", hmac_secret);
|
||||||
|
explicit_bzero(hmac_secret, strlen(hmac_secret));
|
||||||
|
}
|
||||||
|
if (key) {
|
||||||
|
fprintf(out_f, "%s\n", key);
|
||||||
|
explicit_bzero(key, strlen(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(key);
|
||||||
|
free(hmac_secret);
|
||||||
|
free(cdh);
|
||||||
|
free(authdata);
|
||||||
|
free(sig);
|
||||||
|
free(user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
assert_get(int argc, char **argv)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
fido_assert_t *assert = NULL;
|
||||||
|
struct toggle opt;
|
||||||
|
char prompt[1024];
|
||||||
|
char pin[128];
|
||||||
|
char *in_path = NULL;
|
||||||
|
char *out_path = NULL;
|
||||||
|
FILE *in_f = NULL;
|
||||||
|
FILE *out_f = NULL;
|
||||||
|
int flags = 0;
|
||||||
|
int ch;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
opt.up = opt.uv = opt.pin = FIDO_OPT_OMIT;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "bdhi:o:prt:uvw")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'b':
|
||||||
|
flags |= FLAG_LARGEBLOB;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
flags |= FLAG_DEBUG;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
flags |= FLAG_HMAC;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
in_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
out_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
opt.up = FIDO_OPT_TRUE;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
flags |= FLAG_RK;
|
||||||
|
break;
|
||||||
|
case 't' :
|
||||||
|
parse_toggle(optarg, &opt);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
flags |= FLAG_U2F;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
/* -v implies both pin and uv for historical reasons */
|
||||||
|
opt.pin = FIDO_OPT_TRUE;
|
||||||
|
opt.uv = FIDO_OPT_TRUE;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
flags |= FLAG_CD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
in_f = open_read(in_path);
|
||||||
|
out_f = open_write(out_path);
|
||||||
|
|
||||||
|
fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0);
|
||||||
|
|
||||||
|
assert = prepare_assert(in_f, flags, &opt);
|
||||||
|
|
||||||
|
dev = open_dev(argv[0]);
|
||||||
|
if (flags & FLAG_U2F)
|
||||||
|
fido_dev_force_u2f(dev);
|
||||||
|
|
||||||
|
if (opt.pin == FIDO_OPT_TRUE) {
|
||||||
|
r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ",
|
||||||
|
argv[0]);
|
||||||
|
if (r < 0 || (size_t)r >= sizeof(prompt))
|
||||||
|
errx(1, "snprintf");
|
||||||
|
if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF))
|
||||||
|
errx(1, "readpassphrase");
|
||||||
|
if (strlen(pin) < 4 || strlen(pin) > 63) {
|
||||||
|
explicit_bzero(pin, sizeof(pin));
|
||||||
|
errx(1, "invalid PIN length");
|
||||||
|
}
|
||||||
|
r = fido_dev_get_assert(dev, assert, pin);
|
||||||
|
} else
|
||||||
|
r = fido_dev_get_assert(dev, assert, NULL);
|
||||||
|
|
||||||
|
explicit_bzero(pin, sizeof(pin));
|
||||||
|
|
||||||
|
if (r != FIDO_OK)
|
||||||
|
errx(1, "fido_dev_get_assert: %s", fido_strerr(r));
|
||||||
|
|
||||||
|
if (flags & FLAG_RK) {
|
||||||
|
for (size_t idx = 0; idx < fido_assert_count(assert); idx++)
|
||||||
|
print_assert(out_f, assert, idx, flags);
|
||||||
|
} else {
|
||||||
|
if (fido_assert_count(assert) != 1)
|
||||||
|
errx(1, "fido_assert_count: %zu",
|
||||||
|
fido_assert_count(assert));
|
||||||
|
print_assert(out_f, assert, 0, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
fido_assert_free(&assert);
|
||||||
|
|
||||||
|
fclose(in_f);
|
||||||
|
fclose(out_f);
|
||||||
|
in_f = NULL;
|
||||||
|
out_f = NULL;
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
208
tools/assert_verify.c
Normal file
208
tools/assert_verify.c
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2022 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <fido/es256.h>
|
||||||
|
#include <fido/es384.h>
|
||||||
|
#include <fido/rs256.h>
|
||||||
|
#include <fido/eddsa.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
static fido_assert_t *
|
||||||
|
prepare_assert(FILE *in_f, int flags)
|
||||||
|
{
|
||||||
|
fido_assert_t *assert = NULL;
|
||||||
|
struct blob cdh;
|
||||||
|
struct blob authdata;
|
||||||
|
struct blob sig;
|
||||||
|
char *rpid = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
memset(&cdh, 0, sizeof(cdh));
|
||||||
|
memset(&authdata, 0, sizeof(authdata));
|
||||||
|
memset(&sig, 0, sizeof(sig));
|
||||||
|
|
||||||
|
r = base64_read(in_f, &cdh);
|
||||||
|
r |= string_read(in_f, &rpid);
|
||||||
|
r |= base64_read(in_f, &authdata);
|
||||||
|
r |= base64_read(in_f, &sig);
|
||||||
|
if (r < 0)
|
||||||
|
errx(1, "input error");
|
||||||
|
|
||||||
|
if (flags & FLAG_DEBUG) {
|
||||||
|
fprintf(stderr, "client data hash:\n");
|
||||||
|
xxd(cdh.ptr, cdh.len);
|
||||||
|
fprintf(stderr, "relying party id: %s\n", rpid);
|
||||||
|
fprintf(stderr, "authenticator data:\n");
|
||||||
|
xxd(authdata.ptr, authdata.len);
|
||||||
|
fprintf(stderr, "signature:\n");
|
||||||
|
xxd(sig.ptr, sig.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((assert = fido_assert_new()) == NULL)
|
||||||
|
errx(1, "fido_assert_new");
|
||||||
|
if ((r = fido_assert_set_count(assert, 1)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_count: %s", fido_strerr(r));
|
||||||
|
|
||||||
|
if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr,
|
||||||
|
cdh.len)) != FIDO_OK ||
|
||||||
|
(r = fido_assert_set_rp(assert, rpid)) != FIDO_OK ||
|
||||||
|
(r = fido_assert_set_authdata(assert, 0, authdata.ptr,
|
||||||
|
authdata.len)) != FIDO_OK ||
|
||||||
|
(r = fido_assert_set_sig(assert, 0, sig.ptr, sig.len)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set: %s", fido_strerr(r));
|
||||||
|
|
||||||
|
if (flags & FLAG_UP) {
|
||||||
|
if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set_up: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
if (flags & FLAG_UV) {
|
||||||
|
if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set_uv: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
if (flags & FLAG_HMAC) {
|
||||||
|
if ((r = fido_assert_set_extensions(assert,
|
||||||
|
FIDO_EXT_HMAC_SECRET)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_set_extensions: %s",
|
||||||
|
fido_strerr(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cdh.ptr);
|
||||||
|
free(authdata.ptr);
|
||||||
|
free(sig.ptr);
|
||||||
|
free(rpid);
|
||||||
|
|
||||||
|
return (assert);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
load_pubkey(int type, const char *file)
|
||||||
|
{
|
||||||
|
EC_KEY *ec = NULL;
|
||||||
|
RSA *rsa = NULL;
|
||||||
|
EVP_PKEY *eddsa = NULL;
|
||||||
|
es256_pk_t *es256_pk = NULL;
|
||||||
|
es384_pk_t *es384_pk = NULL;
|
||||||
|
rs256_pk_t *rs256_pk = NULL;
|
||||||
|
eddsa_pk_t *eddsa_pk = NULL;
|
||||||
|
void *pk = NULL;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case COSE_ES256:
|
||||||
|
if ((ec = read_ec_pubkey(file)) == NULL)
|
||||||
|
errx(1, "read_ec_pubkey");
|
||||||
|
if ((es256_pk = es256_pk_new()) == NULL)
|
||||||
|
errx(1, "es256_pk_new");
|
||||||
|
if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK)
|
||||||
|
errx(1, "es256_pk_from_EC_KEY");
|
||||||
|
pk = es256_pk;
|
||||||
|
EC_KEY_free(ec);
|
||||||
|
break;
|
||||||
|
case COSE_ES384:
|
||||||
|
if ((ec = read_ec_pubkey(file)) == NULL)
|
||||||
|
errx(1, "read_ec_pubkey");
|
||||||
|
if ((es384_pk = es384_pk_new()) == NULL)
|
||||||
|
errx(1, "es384_pk_new");
|
||||||
|
if (es384_pk_from_EC_KEY(es384_pk, ec) != FIDO_OK)
|
||||||
|
errx(1, "es384_pk_from_EC_KEY");
|
||||||
|
pk = es384_pk;
|
||||||
|
EC_KEY_free(ec);
|
||||||
|
break;
|
||||||
|
case COSE_RS256:
|
||||||
|
if ((rsa = read_rsa_pubkey(file)) == NULL)
|
||||||
|
errx(1, "read_rsa_pubkey");
|
||||||
|
if ((rs256_pk = rs256_pk_new()) == NULL)
|
||||||
|
errx(1, "rs256_pk_new");
|
||||||
|
if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK)
|
||||||
|
errx(1, "rs256_pk_from_RSA");
|
||||||
|
pk = rs256_pk;
|
||||||
|
RSA_free(rsa);
|
||||||
|
break;
|
||||||
|
case COSE_EDDSA:
|
||||||
|
if ((eddsa = read_eddsa_pubkey(file)) == NULL)
|
||||||
|
errx(1, "read_eddsa_pubkey");
|
||||||
|
if ((eddsa_pk = eddsa_pk_new()) == NULL)
|
||||||
|
errx(1, "eddsa_pk_new");
|
||||||
|
if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK)
|
||||||
|
errx(1, "eddsa_pk_from_EVP_PKEY");
|
||||||
|
pk = eddsa_pk;
|
||||||
|
EVP_PKEY_free(eddsa);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errx(1, "invalid type %d", type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
assert_verify(int argc, char **argv)
|
||||||
|
{
|
||||||
|
fido_assert_t *assert = NULL;
|
||||||
|
void *pk = NULL;
|
||||||
|
char *in_path = NULL;
|
||||||
|
FILE *in_f = NULL;
|
||||||
|
int type = COSE_ES256;
|
||||||
|
int flags = 0;
|
||||||
|
int ch;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "dhi:pv")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'd':
|
||||||
|
flags |= FLAG_DEBUG;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
flags |= FLAG_HMAC;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
in_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
flags |= FLAG_UP;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
flags |= FLAG_UV;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc < 1 || argc > 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
in_f = open_read(in_path);
|
||||||
|
|
||||||
|
if (argc > 1 && cose_type(argv[1], &type) < 0)
|
||||||
|
errx(1, "unknown type %s", argv[1]);
|
||||||
|
|
||||||
|
fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0);
|
||||||
|
|
||||||
|
pk = load_pubkey(type, argv[0]);
|
||||||
|
assert = prepare_assert(in_f, flags);
|
||||||
|
if ((r = fido_assert_verify(assert, 0, type, pk)) != FIDO_OK)
|
||||||
|
errx(1, "fido_assert_verify: %s", fido_strerr(r));
|
||||||
|
fido_assert_free(&assert);
|
||||||
|
|
||||||
|
fclose(in_f);
|
||||||
|
in_f = NULL;
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
135
tools/base64.c
Normal file
135
tools/base64.c
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
base64_encode(const void *ptr, size_t len, char **out)
|
||||||
|
{
|
||||||
|
BIO *bio_b64 = NULL;
|
||||||
|
BIO *bio_mem = NULL;
|
||||||
|
char *b64_ptr = NULL;
|
||||||
|
long b64_len;
|
||||||
|
int n;
|
||||||
|
int ok = -1;
|
||||||
|
|
||||||
|
if (ptr == NULL || out == NULL || len > INT_MAX)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
*out = NULL;
|
||||||
|
|
||||||
|
if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL)
|
||||||
|
goto fail;
|
||||||
|
if ((bio_mem = BIO_new(BIO_s_mem())) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
BIO_push(bio_b64, bio_mem);
|
||||||
|
|
||||||
|
n = BIO_write(bio_b64, ptr, (int)len);
|
||||||
|
if (n < 0 || (size_t)n != len)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (BIO_flush(bio_b64) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
b64_len = BIO_get_mem_data(bio_b64, &b64_ptr);
|
||||||
|
if (b64_len < 0 || (size_t)b64_len == SIZE_MAX || b64_ptr == NULL)
|
||||||
|
goto fail;
|
||||||
|
if ((*out = calloc(1, (size_t)b64_len + 1)) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
memcpy(*out, b64_ptr, (size_t)b64_len);
|
||||||
|
ok = 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
BIO_free(bio_b64);
|
||||||
|
BIO_free(bio_mem);
|
||||||
|
|
||||||
|
return (ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
base64_decode(const char *in, void **ptr, size_t *len)
|
||||||
|
{
|
||||||
|
BIO *bio_mem = NULL;
|
||||||
|
BIO *bio_b64 = NULL;
|
||||||
|
size_t alloc_len;
|
||||||
|
int n;
|
||||||
|
int ok = -1;
|
||||||
|
|
||||||
|
if (in == NULL || ptr == NULL || len == NULL || strlen(in) > INT_MAX)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
*ptr = NULL;
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL)
|
||||||
|
goto fail;
|
||||||
|
if ((bio_mem = BIO_new_mem_buf((const void *)in, -1)) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
BIO_push(bio_b64, bio_mem);
|
||||||
|
|
||||||
|
alloc_len = strlen(in);
|
||||||
|
if ((*ptr = calloc(1, alloc_len)) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
n = BIO_read(bio_b64, *ptr, (int)alloc_len);
|
||||||
|
if (n <= 0 || BIO_eof(bio_b64) == 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
*len = (size_t)n;
|
||||||
|
ok = 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
BIO_free(bio_b64);
|
||||||
|
BIO_free(bio_mem);
|
||||||
|
|
||||||
|
if (ok < 0) {
|
||||||
|
free(*ptr);
|
||||||
|
*ptr = NULL;
|
||||||
|
*len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
base64_read(FILE *f, struct blob *out)
|
||||||
|
{
|
||||||
|
char *line = NULL;
|
||||||
|
size_t linesize = 0;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
out->ptr = NULL;
|
||||||
|
out->len = 0;
|
||||||
|
|
||||||
|
if ((n = getline(&line, &linesize, f)) <= 0 ||
|
||||||
|
(size_t)n != strlen(line)) {
|
||||||
|
free(line); /* XXX should be free'd _even_ if getline() fails */
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base64_decode(line, (void **)&out->ptr, &out->len) < 0) {
|
||||||
|
free(line);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
278
tools/bio.c
Normal file
278
tools/bio.c
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <fido/bio.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
print_template(const fido_bio_template_array_t *ta, size_t idx)
|
||||||
|
{
|
||||||
|
const fido_bio_template_t *t = NULL;
|
||||||
|
char *id = NULL;
|
||||||
|
|
||||||
|
if ((t = fido_bio_template(ta, idx)) == NULL) {
|
||||||
|
warnx("fido_bio_template");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (base64_encode(fido_bio_template_id_ptr(t),
|
||||||
|
fido_bio_template_id_len(t), &id) < 0) {
|
||||||
|
warnx("output error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t));
|
||||||
|
free(id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bio_list(const char *path)
|
||||||
|
{
|
||||||
|
fido_bio_template_array_t *ta = NULL;
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
if ((ta = fido_bio_template_array_new()) == NULL)
|
||||||
|
errx(1, "fido_bio_template_array_new");
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_bio_dev_get_template_array(dev, ta, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_bio_dev_get_template_array: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < fido_bio_template_array_count(ta); i++)
|
||||||
|
if (print_template(ta, i) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_bio_template_array_free(&ta);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bio_set_name(const char *path, const char *id, const char *name)
|
||||||
|
{
|
||||||
|
fido_bio_template_t *t = NULL;
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
void *id_blob_ptr = NULL;
|
||||||
|
size_t id_blob_len = 0;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
if ((t = fido_bio_template_new()) == NULL)
|
||||||
|
errx(1, "fido_bio_template_new");
|
||||||
|
if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0)
|
||||||
|
errx(1, "base64_decode");
|
||||||
|
if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK)
|
||||||
|
errx(1, "fido_bio_template_set_name: %s", fido_strerr(r));
|
||||||
|
if ((r = fido_bio_template_set_id(t, id_blob_ptr,
|
||||||
|
id_blob_len)) != FIDO_OK)
|
||||||
|
errx(1, "fido_bio_template_set_id: %s", fido_strerr(r));
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_bio_dev_set_template_name(dev, t, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_bio_dev_set_template_name: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
free(id_blob_ptr);
|
||||||
|
fido_bio_template_free(&t);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
enroll_strerr(uint8_t n)
|
||||||
|
{
|
||||||
|
switch (n) {
|
||||||
|
case FIDO_BIO_ENROLL_FP_GOOD:
|
||||||
|
return "Sample ok";
|
||||||
|
case FIDO_BIO_ENROLL_FP_TOO_HIGH:
|
||||||
|
return "Sample too high";
|
||||||
|
case FIDO_BIO_ENROLL_FP_TOO_LOW:
|
||||||
|
return "Sample too low";
|
||||||
|
case FIDO_BIO_ENROLL_FP_TOO_LEFT:
|
||||||
|
return "Sample too left";
|
||||||
|
case FIDO_BIO_ENROLL_FP_TOO_RIGHT:
|
||||||
|
return "Sample too right";
|
||||||
|
case FIDO_BIO_ENROLL_FP_TOO_FAST:
|
||||||
|
return "Sample too fast";
|
||||||
|
case FIDO_BIO_ENROLL_FP_TOO_SLOW:
|
||||||
|
return "Sample too slow";
|
||||||
|
case FIDO_BIO_ENROLL_FP_POOR_QUALITY:
|
||||||
|
return "Poor quality sample";
|
||||||
|
case FIDO_BIO_ENROLL_FP_TOO_SKEWED:
|
||||||
|
return "Sample too skewed";
|
||||||
|
case FIDO_BIO_ENROLL_FP_TOO_SHORT:
|
||||||
|
return "Sample too short";
|
||||||
|
case FIDO_BIO_ENROLL_FP_MERGE_FAILURE:
|
||||||
|
return "Sample merge failure";
|
||||||
|
case FIDO_BIO_ENROLL_FP_EXISTS:
|
||||||
|
return "Sample exists";
|
||||||
|
case FIDO_BIO_ENROLL_FP_DATABASE_FULL:
|
||||||
|
return "Fingerprint database full";
|
||||||
|
case FIDO_BIO_ENROLL_NO_USER_ACTIVITY:
|
||||||
|
return "No user activity";
|
||||||
|
case FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION:
|
||||||
|
return "No user presence transition";
|
||||||
|
default:
|
||||||
|
return "Unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bio_enroll(const char *path)
|
||||||
|
{
|
||||||
|
fido_bio_template_t *t = NULL;
|
||||||
|
fido_bio_enroll_t *e = NULL;
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
if ((t = fido_bio_template_new()) == NULL)
|
||||||
|
errx(1, "fido_bio_template_new");
|
||||||
|
if ((e = fido_bio_enroll_new()) == NULL)
|
||||||
|
errx(1, "fido_bio_enroll_new");
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
printf("Touch your security key.\n");
|
||||||
|
r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_bio_dev_enroll_begin: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
|
||||||
|
|
||||||
|
while (fido_bio_enroll_remaining_samples(e) > 0) {
|
||||||
|
printf("Touch your security key (%u sample%s left).\n",
|
||||||
|
(unsigned)fido_bio_enroll_remaining_samples(e),
|
||||||
|
plural(fido_bio_enroll_remaining_samples(e)));
|
||||||
|
if ((r = fido_bio_dev_enroll_continue(dev, t, e,
|
||||||
|
10000)) != FIDO_OK) {
|
||||||
|
fido_dev_cancel(dev);
|
||||||
|
warnx("fido_bio_dev_enroll_continue: %s",
|
||||||
|
fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_bio_template_free(&t);
|
||||||
|
fido_bio_enroll_free(&e);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bio_delete(const char *path, const char *id)
|
||||||
|
{
|
||||||
|
fido_bio_template_t *t = NULL;
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
void *id_blob_ptr = NULL;
|
||||||
|
size_t id_blob_len = 0;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
if ((t = fido_bio_template_new()) == NULL)
|
||||||
|
errx(1, "fido_bio_template_new");
|
||||||
|
if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0)
|
||||||
|
errx(1, "base64_decode");
|
||||||
|
if ((r = fido_bio_template_set_id(t, id_blob_ptr,
|
||||||
|
id_blob_len)) != FIDO_OK)
|
||||||
|
errx(1, "fido_bio_template_set_id: %s", fido_strerr(r));
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_bio_dev_enroll_remove(dev, t, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_bio_dev_enroll_remove: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
free(id_blob_ptr);
|
||||||
|
fido_bio_template_free(&t);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
type_str(uint8_t t)
|
||||||
|
{
|
||||||
|
switch (t) {
|
||||||
|
case 1:
|
||||||
|
return "touch";
|
||||||
|
case 2:
|
||||||
|
return "swipe";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bio_info(fido_dev_t *dev)
|
||||||
|
{
|
||||||
|
fido_bio_info_t *i = NULL;
|
||||||
|
|
||||||
|
if ((i = fido_bio_info_new()) == NULL) {
|
||||||
|
warnx("fido_bio_info_new");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fido_bio_dev_get_info(dev, i) != FIDO_OK) {
|
||||||
|
fido_bio_info_free(&i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i),
|
||||||
|
type_str(fido_bio_info_type(i)));
|
||||||
|
printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i));
|
||||||
|
|
||||||
|
fido_bio_info_free(&i);
|
||||||
|
}
|
||||||
198
tools/config.c
Normal file
198
tools/config.c
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <fido/config.h>
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
config_entattest(char *path)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((r = fido_dev_enable_entattest(dev, NULL)) != FIDO_OK &&
|
||||||
|
should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_dev_enable_entattest(dev, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_dev_enable_entattest: %s (0x%x)",
|
||||||
|
fido_strerr(r), r);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
config_always_uv(char *path, int toggle)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev;
|
||||||
|
char *pin = NULL;
|
||||||
|
int v, r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if (get_devopt(dev, "alwaysUv", &v) < 0) {
|
||||||
|
warnx("%s: getdevopt", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (v == -1) {
|
||||||
|
warnx("%s: option not found", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (v == toggle) {
|
||||||
|
ok = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_dev_toggle_always_uv(dev, NULL)) != FIDO_OK &&
|
||||||
|
should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_dev_toggle_always_uv(dev, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_dev_toggle_always_uv: %s (0x%x)",
|
||||||
|
fido_strerr(r), r);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
config_pin_minlen(char *path, const char *pinlen)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev;
|
||||||
|
char *pin = NULL;
|
||||||
|
int len, r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((len = base10(pinlen)) < 0 || len > 63) {
|
||||||
|
warnx("%s: len > 63", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_dev_set_pin_minlen(dev, (size_t)len, NULL)) != FIDO_OK &&
|
||||||
|
should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_dev_set_pin_minlen(dev, (size_t)len, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_dev_set_pin_minlen: %s (0x%x)", fido_strerr(r), r);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
config_force_pin_change(char *path)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((r = fido_dev_force_pin_change(dev, NULL)) != FIDO_OK &&
|
||||||
|
should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_dev_force_pin_change(dev, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_dev_force_pin_change: %s (0x%x)", fido_strerr(r), r);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
config_pin_minlen_rpid(char *path, const char *rpids)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev;
|
||||||
|
char *otmp, *tmp, *cp;
|
||||||
|
char *pin = NULL, **rpid = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if ((tmp = strdup(rpids)) == NULL)
|
||||||
|
err(1, "strdup");
|
||||||
|
otmp = tmp;
|
||||||
|
for (n = 0; (cp = strsep(&tmp, ",")) != NULL; n++) {
|
||||||
|
if (n == SIZE_MAX || (rpid = recallocarray(rpid, n, n + 1,
|
||||||
|
sizeof(*rpid))) == NULL)
|
||||||
|
err(1, "recallocarray");
|
||||||
|
if ((rpid[n] = strdup(cp)) == NULL)
|
||||||
|
err(1, "strdup");
|
||||||
|
if (*rpid[n] == '\0')
|
||||||
|
errx(1, "empty rpid");
|
||||||
|
}
|
||||||
|
free(otmp);
|
||||||
|
if (rpid == NULL || n == 0)
|
||||||
|
errx(1, "could not parse rp_id");
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((r = fido_dev_set_pin_minlen_rpid(dev, (const char * const *)rpid,
|
||||||
|
n, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_dev_set_pin_minlen_rpid(dev, (const char * const *)rpid,
|
||||||
|
n, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_dev_set_pin_minlen_rpid: %s (0x%x)",
|
||||||
|
fido_strerr(r), r);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
255
tools/cred_make.c
Normal file
255
tools/cred_make.c
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2023 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
static fido_cred_t *
|
||||||
|
prepare_cred(FILE *in_f, int type, int flags)
|
||||||
|
{
|
||||||
|
fido_cred_t *cred = NULL;
|
||||||
|
struct blob cdh;
|
||||||
|
struct blob uid;
|
||||||
|
char *rpid = NULL;
|
||||||
|
char *uname = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
memset(&cdh, 0, sizeof(cdh));
|
||||||
|
memset(&uid, 0, sizeof(uid));
|
||||||
|
|
||||||
|
r = base64_read(in_f, &cdh);
|
||||||
|
r |= string_read(in_f, &rpid);
|
||||||
|
r |= string_read(in_f, &uname);
|
||||||
|
r |= base64_read(in_f, &uid);
|
||||||
|
if (r < 0)
|
||||||
|
errx(1, "input error");
|
||||||
|
|
||||||
|
if (flags & FLAG_DEBUG) {
|
||||||
|
fprintf(stderr, "client data%s:\n",
|
||||||
|
flags & FLAG_CD ? "" : " hash");
|
||||||
|
xxd(cdh.ptr, cdh.len);
|
||||||
|
fprintf(stderr, "relying party id: %s\n", rpid);
|
||||||
|
fprintf(stderr, "user name: %s\n", uname);
|
||||||
|
fprintf(stderr, "user id:\n");
|
||||||
|
xxd(uid.ptr, uid.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cred = fido_cred_new()) == NULL)
|
||||||
|
errx(1, "fido_cred_new");
|
||||||
|
|
||||||
|
|
||||||
|
if (flags & FLAG_CD)
|
||||||
|
r = fido_cred_set_clientdata(cred, cdh.ptr, cdh.len);
|
||||||
|
else
|
||||||
|
r = fido_cred_set_clientdata_hash(cred, cdh.ptr, cdh.len);
|
||||||
|
|
||||||
|
if (r != FIDO_OK || (r = fido_cred_set_type(cred, type)) != FIDO_OK ||
|
||||||
|
(r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK ||
|
||||||
|
(r = fido_cred_set_user(cred, uid.ptr, uid.len, uname, NULL,
|
||||||
|
NULL)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_set: %s", fido_strerr(r));
|
||||||
|
|
||||||
|
if (flags & FLAG_RK) {
|
||||||
|
if ((r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_set_rk: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
if (flags & FLAG_UV) {
|
||||||
|
if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_set_uv: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
if (flags & FLAG_HMAC) {
|
||||||
|
if ((r = fido_cred_set_extensions(cred,
|
||||||
|
FIDO_EXT_HMAC_SECRET)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_set_extensions: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
if (flags & FLAG_LARGEBLOB) {
|
||||||
|
if ((r = fido_cred_set_extensions(cred,
|
||||||
|
FIDO_EXT_LARGEBLOB_KEY)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_set_extensions: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cdh.ptr);
|
||||||
|
free(uid.ptr);
|
||||||
|
free(rpid);
|
||||||
|
free(uname);
|
||||||
|
|
||||||
|
return (cred);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_attcred(FILE *out_f, const fido_cred_t *cred)
|
||||||
|
{
|
||||||
|
char *cdh = NULL;
|
||||||
|
char *authdata = NULL;
|
||||||
|
char *id = NULL;
|
||||||
|
char *sig = NULL;
|
||||||
|
char *x5c = NULL;
|
||||||
|
char *key = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = base64_encode(fido_cred_clientdata_hash_ptr(cred),
|
||||||
|
fido_cred_clientdata_hash_len(cred), &cdh);
|
||||||
|
r |= base64_encode(fido_cred_authdata_ptr(cred),
|
||||||
|
fido_cred_authdata_len(cred), &authdata);
|
||||||
|
r |= base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred),
|
||||||
|
&id);
|
||||||
|
r |= base64_encode(fido_cred_sig_ptr(cred), fido_cred_sig_len(cred),
|
||||||
|
&sig);
|
||||||
|
if (fido_cred_x5c_ptr(cred) != NULL)
|
||||||
|
r |= base64_encode(fido_cred_x5c_ptr(cred),
|
||||||
|
fido_cred_x5c_len(cred), &x5c);
|
||||||
|
if (fido_cred_largeblob_key_ptr(cred) != NULL)
|
||||||
|
r |= base64_encode(fido_cred_largeblob_key_ptr(cred),
|
||||||
|
fido_cred_largeblob_key_len(cred), &key);
|
||||||
|
if (r < 0)
|
||||||
|
errx(1, "output error");
|
||||||
|
|
||||||
|
fprintf(out_f, "%s\n", cdh);
|
||||||
|
fprintf(out_f, "%s\n", fido_cred_rp_id(cred));
|
||||||
|
fprintf(out_f, "%s\n", fido_cred_fmt(cred));
|
||||||
|
fprintf(out_f, "%s\n", authdata);
|
||||||
|
fprintf(out_f, "%s\n", id);
|
||||||
|
fprintf(out_f, "%s\n", sig);
|
||||||
|
if (x5c != NULL)
|
||||||
|
fprintf(out_f, "%s\n", x5c);
|
||||||
|
if (key != NULL) {
|
||||||
|
fprintf(out_f, "%s\n", key);
|
||||||
|
explicit_bzero(key, strlen(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cdh);
|
||||||
|
free(authdata);
|
||||||
|
free(id);
|
||||||
|
free(sig);
|
||||||
|
free(x5c);
|
||||||
|
free(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cred_make(int argc, char **argv)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
fido_cred_t *cred = NULL;
|
||||||
|
char prompt[1024];
|
||||||
|
char pin[128];
|
||||||
|
char *in_path = NULL;
|
||||||
|
char *out_path = NULL;
|
||||||
|
FILE *in_f = NULL;
|
||||||
|
FILE *out_f = NULL;
|
||||||
|
int type = COSE_ES256;
|
||||||
|
int flags = 0;
|
||||||
|
int cred_protect = -1;
|
||||||
|
int ch;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "bc:dhi:o:qruvw")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'b':
|
||||||
|
flags |= FLAG_LARGEBLOB;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
if ((cred_protect = base10(optarg)) < 0)
|
||||||
|
errx(1, "-c: invalid argument '%s'", optarg);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
flags |= FLAG_DEBUG;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
flags |= FLAG_HMAC;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
in_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
out_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
flags |= FLAG_QUIET;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
flags |= FLAG_RK;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
flags |= FLAG_U2F;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
flags |= FLAG_UV;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
flags |= FLAG_CD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc < 1 || argc > 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
in_f = open_read(in_path);
|
||||||
|
out_f = open_write(out_path);
|
||||||
|
|
||||||
|
if (argc > 1 && cose_type(argv[1], &type) < 0)
|
||||||
|
errx(1, "unknown type %s", argv[1]);
|
||||||
|
|
||||||
|
fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0);
|
||||||
|
|
||||||
|
cred = prepare_cred(in_f, type, flags);
|
||||||
|
|
||||||
|
dev = open_dev(argv[0]);
|
||||||
|
if (flags & FLAG_U2F)
|
||||||
|
fido_dev_force_u2f(dev);
|
||||||
|
|
||||||
|
if (cred_protect > 0) {
|
||||||
|
r = fido_cred_set_prot(cred, cred_protect);
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
errx(1, "fido_cred_set_prot: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = fido_dev_make_cred(dev, cred, NULL);
|
||||||
|
if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) {
|
||||||
|
r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ",
|
||||||
|
argv[0]);
|
||||||
|
if (r < 0 || (size_t)r >= sizeof(prompt))
|
||||||
|
errx(1, "snprintf");
|
||||||
|
if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF))
|
||||||
|
errx(1, "readpassphrase");
|
||||||
|
if (strlen(pin) < 4 || strlen(pin) > 63) {
|
||||||
|
explicit_bzero(pin, sizeof(pin));
|
||||||
|
errx(1, "invalid PIN length");
|
||||||
|
}
|
||||||
|
r = fido_dev_make_cred(dev, cred, pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit_bzero(pin, sizeof(pin));
|
||||||
|
if (r != FIDO_OK)
|
||||||
|
errx(1, "fido_dev_make_cred: %s", fido_strerr(r));
|
||||||
|
print_attcred(out_f, cred);
|
||||||
|
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
fido_cred_free(&cred);
|
||||||
|
|
||||||
|
fclose(in_f);
|
||||||
|
fclose(out_f);
|
||||||
|
in_f = NULL;
|
||||||
|
out_f = NULL;
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
182
tools/cred_verify.c
Normal file
182
tools/cred_verify.c
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
static fido_cred_t *
|
||||||
|
prepare_cred(FILE *in_f, int type, int flags)
|
||||||
|
{
|
||||||
|
fido_cred_t *cred = NULL;
|
||||||
|
struct blob cdh;
|
||||||
|
struct blob authdata;
|
||||||
|
struct blob id;
|
||||||
|
struct blob sig;
|
||||||
|
struct blob x5c;
|
||||||
|
char *rpid = NULL;
|
||||||
|
char *fmt = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
memset(&cdh, 0, sizeof(cdh));
|
||||||
|
memset(&authdata, 0, sizeof(authdata));
|
||||||
|
memset(&id, 0, sizeof(id));
|
||||||
|
memset(&sig, 0, sizeof(sig));
|
||||||
|
memset(&x5c, 0, sizeof(x5c));
|
||||||
|
|
||||||
|
r = base64_read(in_f, &cdh);
|
||||||
|
r |= string_read(in_f, &rpid);
|
||||||
|
r |= string_read(in_f, &fmt);
|
||||||
|
r |= base64_read(in_f, &authdata);
|
||||||
|
r |= base64_read(in_f, &id);
|
||||||
|
r |= base64_read(in_f, &sig);
|
||||||
|
if (r < 0)
|
||||||
|
errx(1, "input error");
|
||||||
|
|
||||||
|
(void)base64_read(in_f, &x5c);
|
||||||
|
|
||||||
|
if (flags & FLAG_DEBUG) {
|
||||||
|
fprintf(stderr, "client data hash:\n");
|
||||||
|
xxd(cdh.ptr, cdh.len);
|
||||||
|
fprintf(stderr, "relying party id: %s\n", rpid);
|
||||||
|
fprintf(stderr, "format: %s\n", fmt);
|
||||||
|
fprintf(stderr, "authenticator data:\n");
|
||||||
|
xxd(authdata.ptr, authdata.len);
|
||||||
|
fprintf(stderr, "credential id:\n");
|
||||||
|
xxd(id.ptr, id.len);
|
||||||
|
fprintf(stderr, "signature:\n");
|
||||||
|
xxd(sig.ptr, sig.len);
|
||||||
|
fprintf(stderr, "x509:\n");
|
||||||
|
xxd(x5c.ptr, x5c.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cred = fido_cred_new()) == NULL)
|
||||||
|
errx(1, "fido_cred_new");
|
||||||
|
|
||||||
|
if ((r = fido_cred_set_type(cred, type)) != FIDO_OK ||
|
||||||
|
(r = fido_cred_set_clientdata_hash(cred, cdh.ptr,
|
||||||
|
cdh.len)) != FIDO_OK ||
|
||||||
|
(r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK ||
|
||||||
|
(r = fido_cred_set_authdata(cred, authdata.ptr,
|
||||||
|
authdata.len)) != FIDO_OK ||
|
||||||
|
(r = fido_cred_set_sig(cred, sig.ptr, sig.len)) != FIDO_OK ||
|
||||||
|
(r = fido_cred_set_fmt(cred, fmt)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_set: %s", fido_strerr(r));
|
||||||
|
|
||||||
|
if (x5c.ptr != NULL) {
|
||||||
|
if ((r = fido_cred_set_x509(cred, x5c.ptr, x5c.len)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_set_x509: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & FLAG_UV) {
|
||||||
|
if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_set_uv: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
if (flags & FLAG_HMAC) {
|
||||||
|
if ((r = fido_cred_set_extensions(cred,
|
||||||
|
FIDO_EXT_HMAC_SECRET)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_set_extensions: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cdh.ptr);
|
||||||
|
free(authdata.ptr);
|
||||||
|
free(id.ptr);
|
||||||
|
free(sig.ptr);
|
||||||
|
free(x5c.ptr);
|
||||||
|
free(rpid);
|
||||||
|
free(fmt);
|
||||||
|
|
||||||
|
return (cred);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cred_verify(int argc, char **argv)
|
||||||
|
{
|
||||||
|
fido_cred_t *cred = NULL;
|
||||||
|
char *in_path = NULL;
|
||||||
|
char *out_path = NULL;
|
||||||
|
FILE *in_f = NULL;
|
||||||
|
FILE *out_f = NULL;
|
||||||
|
int type = COSE_ES256;
|
||||||
|
int flags = 0;
|
||||||
|
int cred_prot = -1;
|
||||||
|
int ch;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "c:dhi:o:v")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'c':
|
||||||
|
if ((cred_prot = base10(optarg)) < 0)
|
||||||
|
errx(1, "-c: invalid argument '%s'", optarg);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
flags |= FLAG_DEBUG;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
flags |= FLAG_HMAC;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
in_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
out_path = optarg;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
flags |= FLAG_UV;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
in_f = open_read(in_path);
|
||||||
|
out_f = open_write(out_path);
|
||||||
|
|
||||||
|
if (argc > 0 && cose_type(argv[0], &type) < 0)
|
||||||
|
errx(1, "unknown type %s", argv[0]);
|
||||||
|
|
||||||
|
fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0);
|
||||||
|
cred = prepare_cred(in_f, type, flags);
|
||||||
|
|
||||||
|
if (cred_prot > 0) {
|
||||||
|
r = fido_cred_set_prot(cred, cred_prot);
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
errx(1, "fido_cred_set_prot: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fido_cred_x5c_ptr(cred) == NULL) {
|
||||||
|
if ((r = fido_cred_verify_self(cred)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_verify_self: %s", fido_strerr(r));
|
||||||
|
} else {
|
||||||
|
if ((r = fido_cred_verify(cred)) != FIDO_OK)
|
||||||
|
errx(1, "fido_cred_verify: %s", fido_strerr(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
print_cred(out_f, type, cred);
|
||||||
|
fido_cred_free(&cred);
|
||||||
|
|
||||||
|
fclose(in_f);
|
||||||
|
fclose(out_f);
|
||||||
|
in_f = NULL;
|
||||||
|
out_f = NULL;
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
330
tools/credman.c
Normal file
330
tools/credman.c
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <fido/credman.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
credman_get_metadata(fido_dev_t *dev, const char *path)
|
||||||
|
{
|
||||||
|
fido_credman_metadata_t *metadata = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
if ((metadata = fido_credman_metadata_new()) == NULL) {
|
||||||
|
warnx("fido_credman_metadata_new");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_credman_get_dev_metadata(dev, metadata,
|
||||||
|
NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_credman_get_dev_metadata(dev, metadata, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_credman_get_dev_metadata: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("existing rk(s): %u\n",
|
||||||
|
(unsigned)fido_credman_rk_existing(metadata));
|
||||||
|
printf("remaining rk(s): %u\n",
|
||||||
|
(unsigned)fido_credman_rk_remaining(metadata));
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_credman_metadata_free(&metadata);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
print_rp(fido_credman_rp_t *rp, size_t idx)
|
||||||
|
{
|
||||||
|
char *rp_id_hash = NULL;
|
||||||
|
|
||||||
|
if (base64_encode(fido_credman_rp_id_hash_ptr(rp, idx),
|
||||||
|
fido_credman_rp_id_hash_len(rp, idx), &rp_id_hash) < 0) {
|
||||||
|
warnx("output error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("%02u: %s %s\n", (unsigned)idx, rp_id_hash,
|
||||||
|
fido_credman_rp_id(rp, idx));
|
||||||
|
free(rp_id_hash);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
credman_list_rp(const char *path)
|
||||||
|
{
|
||||||
|
fido_credman_rp_t *rp = NULL;
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((rp = fido_credman_rp_new()) == NULL) {
|
||||||
|
warnx("fido_credman_rp_new");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_credman_get_dev_rp(dev, rp, NULL)) != FIDO_OK &&
|
||||||
|
should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_credman_get_dev_rp(dev, rp, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_credman_get_dev_rp: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < fido_credman_rp_count(rp); i++)
|
||||||
|
if (print_rp(rp, i) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_credman_rp_free(&rp);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
print_rk(const fido_credman_rk_t *rk, size_t idx)
|
||||||
|
{
|
||||||
|
const fido_cred_t *cred;
|
||||||
|
char *id = NULL;
|
||||||
|
char *user_id = NULL;
|
||||||
|
const char *type;
|
||||||
|
const char *prot;
|
||||||
|
|
||||||
|
if ((cred = fido_credman_rk(rk, idx)) == NULL) {
|
||||||
|
warnx("fido_credman_rk");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred),
|
||||||
|
&id) < 0 || base64_encode(fido_cred_user_id_ptr(cred),
|
||||||
|
fido_cred_user_id_len(cred), &user_id) < 0) {
|
||||||
|
warnx("output error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = cose_string(fido_cred_type(cred));
|
||||||
|
prot = prot_string(fido_cred_prot(cred));
|
||||||
|
|
||||||
|
printf("%02u: %s %s %s %s %s\n", (unsigned)idx, id,
|
||||||
|
fido_cred_display_name(cred), user_id, type, prot);
|
||||||
|
|
||||||
|
free(user_id);
|
||||||
|
free(id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
credman_list_rk(const char *path, const char *rp_id)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
fido_credman_rk_t *rk = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((rk = fido_credman_rk_new()) == NULL) {
|
||||||
|
warnx("fido_credman_rk_new");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, NULL)) != FIDO_OK &&
|
||||||
|
should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_credman_get_dev_rk(dev, rp_id, rk, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_credman_get_dev_rk: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < fido_credman_rk_count(rk); i++)
|
||||||
|
if (print_rk(rk, i) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_credman_rk_free(&rk);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
credman_print_rk(fido_dev_t *dev, const char *path, const char *rp_id,
|
||||||
|
const char *cred_id)
|
||||||
|
{
|
||||||
|
fido_credman_rk_t *rk = NULL;
|
||||||
|
const fido_cred_t *cred = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
void *cred_id_ptr = NULL;
|
||||||
|
size_t cred_id_len = 0;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
if ((rk = fido_credman_rk_new()) == NULL) {
|
||||||
|
warnx("fido_credman_rk_new");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) {
|
||||||
|
warnx("base64_decode");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, NULL)) != FIDO_OK &&
|
||||||
|
should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_credman_get_dev_rk(dev, rp_id, rk, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_credman_get_dev_rk: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fido_credman_rk_count(rk); i++) {
|
||||||
|
if ((cred = fido_credman_rk(rk, i)) == NULL ||
|
||||||
|
fido_cred_id_ptr(cred) == NULL) {
|
||||||
|
warnx("output error");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (cred_id_len != fido_cred_id_len(cred) ||
|
||||||
|
memcmp(cred_id_ptr, fido_cred_id_ptr(cred), cred_id_len))
|
||||||
|
continue;
|
||||||
|
print_cred(stdout, fido_cred_type(cred), cred);
|
||||||
|
ok = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
warnx("credential not found");
|
||||||
|
out:
|
||||||
|
free(cred_id_ptr);
|
||||||
|
fido_credman_rk_free(&rk);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
credman_delete_rk(const char *path, const char *id)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
void *id_ptr = NULL;
|
||||||
|
size_t id_len = 0;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if (base64_decode(id, &id_ptr, &id_len) < 0) {
|
||||||
|
warnx("base64_decode");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_credman_del_dev_rk(dev, id_ptr, id_len,
|
||||||
|
NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_credman_del_dev_rk(dev, id_ptr, id_len, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_credman_del_dev_rk: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
free(id_ptr);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
credman_update_rk(const char *path, const char *user_id, const char *cred_id,
|
||||||
|
const char *name, const char *display_name)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
fido_cred_t *cred = NULL;
|
||||||
|
char *pin = NULL;
|
||||||
|
void *user_id_ptr = NULL;
|
||||||
|
void *cred_id_ptr = NULL;
|
||||||
|
size_t user_id_len = 0;
|
||||||
|
size_t cred_id_len = 0;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if (base64_decode(user_id, &user_id_ptr, &user_id_len) < 0 ||
|
||||||
|
base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) {
|
||||||
|
warnx("base64_decode");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((cred = fido_cred_new()) == NULL) {
|
||||||
|
warnx("fido_cred_new");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_cred_set_id(cred, cred_id_ptr, cred_id_len)) != FIDO_OK) {
|
||||||
|
warnx("fido_cred_set_id: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_cred_set_user(cred, user_id_ptr, user_id_len, name,
|
||||||
|
display_name, NULL)) != FIDO_OK) {
|
||||||
|
warnx("fido_cred_set_user: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_credman_set_dev_rk(dev, cred, NULL)) != FIDO_OK &&
|
||||||
|
should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_credman_set_dev_rk(dev, cred, pin);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_credman_set_dev_rk: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
free(user_id_ptr);
|
||||||
|
free(cred_id_ptr);
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
fido_cred_free(&cred);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
103
tools/extern.h
Normal file
103
tools/extern.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2023 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _EXTERN_H_
|
||||||
|
#define _EXTERN_H_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <openssl/ec.h>
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
struct blob {
|
||||||
|
unsigned char *ptr;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TOKEN_OPT "CDGILPRSVabcdefi:k:l:m:n:p:w:ru"
|
||||||
|
|
||||||
|
#define FLAG_DEBUG 0x001
|
||||||
|
#define FLAG_QUIET 0x002
|
||||||
|
#define FLAG_RK 0x004
|
||||||
|
#define FLAG_UV 0x008
|
||||||
|
#define FLAG_U2F 0x010
|
||||||
|
#define FLAG_HMAC 0x020
|
||||||
|
#define FLAG_UP 0x040
|
||||||
|
#define FLAG_LARGEBLOB 0x080
|
||||||
|
#define FLAG_CD 0x100
|
||||||
|
extern char* global_pin;
|
||||||
|
#define PINBUF_LEN 256
|
||||||
|
|
||||||
|
EC_KEY *read_ec_pubkey(const char *);
|
||||||
|
fido_dev_t *open_dev(const char *);
|
||||||
|
FILE *open_read(const char *);
|
||||||
|
FILE *open_write(const char *);
|
||||||
|
char *get_pin(const char *);
|
||||||
|
const char *plural(size_t);
|
||||||
|
const char *cose_string(int);
|
||||||
|
const char *prot_string(int);
|
||||||
|
int assert_get(int, char **);
|
||||||
|
int assert_verify(int, char **);
|
||||||
|
int base64_decode(const char *, void **, size_t *);
|
||||||
|
int base64_encode(const void *, size_t, char **);
|
||||||
|
int base64_read(FILE *, struct blob *);
|
||||||
|
int bio_delete(const char *, const char *);
|
||||||
|
int bio_enroll(const char *);
|
||||||
|
void bio_info(fido_dev_t *);
|
||||||
|
int bio_list(const char *);
|
||||||
|
int bio_set_name(const char *, const char *, const char *);
|
||||||
|
int blob_clean(const char *);
|
||||||
|
int blob_list(const char *);
|
||||||
|
int blob_delete(const char *, const char *, const char *, const char *);
|
||||||
|
int blob_get(const char *, const char *, const char *, const char *,
|
||||||
|
const char *);
|
||||||
|
int blob_set(const char *, const char *, const char *, const char *,
|
||||||
|
const char *);
|
||||||
|
int config_always_uv(char *, int);
|
||||||
|
int config_entattest(char *);
|
||||||
|
int config_force_pin_change(char *);
|
||||||
|
int config_pin_minlen(char *, const char *);
|
||||||
|
int config_pin_minlen_rpid(char *, const char *);
|
||||||
|
int cose_type(const char *, int *);
|
||||||
|
int cred_make(int, char **);
|
||||||
|
int cred_verify(int, char **);
|
||||||
|
int credman_delete_rk(const char *, const char *);
|
||||||
|
int credman_update_rk(const char *, const char *, const char *, const char *,
|
||||||
|
const char *);
|
||||||
|
int credman_get_metadata(fido_dev_t *, const char *);
|
||||||
|
int credman_list_rk(const char *, const char *);
|
||||||
|
int credman_list_rp(const char *);
|
||||||
|
int credman_print_rk(fido_dev_t *, const char *, const char *, const char *);
|
||||||
|
int get_devopt(fido_dev_t *, const char *, int *);
|
||||||
|
int pin_change(char *);
|
||||||
|
int pin_set(char *);
|
||||||
|
int should_retry_with_pin(const fido_dev_t *, int);
|
||||||
|
int string_read(FILE *, char **);
|
||||||
|
int token_config(int, char **, char *);
|
||||||
|
int token_delete(int, char **, char *);
|
||||||
|
int token_get(int, char **, char *);
|
||||||
|
int token_info(int, char **, char *);
|
||||||
|
int token_list(int, char **, char *);
|
||||||
|
int token_reset(char *);
|
||||||
|
int token_set(int, char **, char *);
|
||||||
|
int write_es256_pubkey(FILE *, const void *, size_t);
|
||||||
|
int write_es384_pubkey(FILE *, const void *, size_t);
|
||||||
|
int write_rsa_pubkey(FILE *, const void *, size_t);
|
||||||
|
int read_file(const char *, u_char **, size_t *);
|
||||||
|
int write_file(const char *, const u_char *, size_t);
|
||||||
|
RSA *read_rsa_pubkey(const char *);
|
||||||
|
EVP_PKEY *read_eddsa_pubkey(const char *);
|
||||||
|
int write_eddsa_pubkey(FILE *, const void *, size_t);
|
||||||
|
void print_cred(FILE *, int, const fido_cred_t *);
|
||||||
|
void usage(void);
|
||||||
|
void xxd(const void *, size_t);
|
||||||
|
int base10(const char *);
|
||||||
|
|
||||||
|
#endif /* _EXTERN_H_ */
|
||||||
15
tools/fido2-attach.sh
Normal file
15
tools/fido2-attach.sh
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
DEV=""
|
||||||
|
|
||||||
|
while [ -z "${DEV}" ]; do
|
||||||
|
sleep .5
|
||||||
|
DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')"
|
||||||
|
done
|
||||||
|
|
||||||
|
printf '%s\n' "${DEV}"
|
||||||
13
tools/fido2-detach.sh
Normal file
13
tools/fido2-detach.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')"
|
||||||
|
|
||||||
|
while [ -n "${DEV}" ]; do
|
||||||
|
sleep .5
|
||||||
|
DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')"
|
||||||
|
done
|
||||||
124
tools/fido2-token.c
Normal file
124
tools/fido2-token.c
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
static int action;
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"usage: fido2-token -C [-d] device\n"
|
||||||
|
" fido2-token -Db [-k key_path] [-i cred_id -n rp_id] device\n"
|
||||||
|
" fido2-token -Dei template_id device\n"
|
||||||
|
" fido2-token -Du device\n"
|
||||||
|
" fido2-token -Gb [-k key_path] [-i cred_id -n rp_id] blob_path device\n"
|
||||||
|
" fido2-token -I [-cd] [-k rp_id -i cred_id] device\n"
|
||||||
|
" fido2-token -L [-bder] [-k rp_id] [device]\n"
|
||||||
|
" fido2-token -R [-d] device\n"
|
||||||
|
" fido2-token -S [-adefu] [-l pin_length] [-i template_id -n template_name] device\n"
|
||||||
|
" fido2-token -Sb [-k key_path] [-i cred_id -n rp_id] blob_path device\n"
|
||||||
|
" fido2-token -Sc -i cred_id -k user_id -n name -p display_name device\n"
|
||||||
|
" fido2-token -Sm rp_id device\n"
|
||||||
|
" fido2-token -V\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* global_pin = NULL;
|
||||||
|
|
||||||
|
static void
|
||||||
|
setaction(int ch)
|
||||||
|
{
|
||||||
|
if (action)
|
||||||
|
usage();
|
||||||
|
action = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ch;
|
||||||
|
int flags = 0;
|
||||||
|
char *device;
|
||||||
|
|
||||||
|
|
||||||
|
// Parse command line arguments
|
||||||
|
for (int i = 1; i < argc - 1; i++) {
|
||||||
|
if (strcmp(argv[i], "-w") == 0) {
|
||||||
|
// Set global_pin from command line argument
|
||||||
|
global_pin = strdup(argv[i + 1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'a':
|
||||||
|
case 'b':
|
||||||
|
case 'c':
|
||||||
|
case 'e':
|
||||||
|
case 'f':
|
||||||
|
case 'i':
|
||||||
|
case 'k':
|
||||||
|
case 'l':
|
||||||
|
case 'm':
|
||||||
|
case 'n':
|
||||||
|
case 'w':
|
||||||
|
case 'p':
|
||||||
|
case 'r':
|
||||||
|
case 'u':
|
||||||
|
break; /* ignore */
|
||||||
|
case 'd':
|
||||||
|
flags = FIDO_DEBUG;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
setaction(ch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc - optind < 1)
|
||||||
|
device = NULL;
|
||||||
|
else
|
||||||
|
device = argv[argc - 1];
|
||||||
|
|
||||||
|
fido_init(flags);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'C':
|
||||||
|
return (pin_change(device));
|
||||||
|
case 'D':
|
||||||
|
return (token_delete(argc, argv, device));
|
||||||
|
case 'G':
|
||||||
|
return (token_get(argc, argv, device));
|
||||||
|
case 'I':
|
||||||
|
return (token_info(argc, argv, device));
|
||||||
|
case 'L':
|
||||||
|
return (token_list(argc, argv, device));
|
||||||
|
case 'R':
|
||||||
|
return (token_reset(device));
|
||||||
|
case 'S':
|
||||||
|
return (token_set(argc, argv, device));
|
||||||
|
case 'V':
|
||||||
|
fprintf(stderr, "%d.%d.%d\n", _FIDO_MAJOR, _FIDO_MINOR,
|
||||||
|
_FIDO_PATCH);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
usage();
|
||||||
|
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
76
tools/fido2-unprot.sh
Normal file
76
tools/fido2-unprot.sh
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2020 Fabian Henneke.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
|
||||||
|
if [ $(uname) != "Linux" ] ; then
|
||||||
|
echo "Can only run on Linux"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TOKEN_VERSION=$(${FIDO_TOOLS_PREFIX}fido2-token -V 2>&1)
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
echo "Please install libfido2 1.5.0 or higher"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
TOKEN_VERSION_MAJOR=$(echo "$TOKEN_VERSION" | cut -d. -f1)
|
||||||
|
TOKEN_VERSION_MINOR=$(echo "$TOKEN_VERSION" | cut -d. -f2)
|
||||||
|
if [ $TOKEN_VERSION_MAJOR -eq 0 -o $TOKEN_VERSION_MAJOR -eq 1 -a $TOKEN_VERSION_MINOR -lt 5 ] ; then
|
||||||
|
echo "Please install libfido2 1.5.0 or higher (current version: $TOKEN_VERSION)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TOKEN_OUTPUT=$(${FIDO_TOOLS_PREFIX}fido2-token -L)
|
||||||
|
DEV_PATH_NAMES=$(echo "$TOKEN_OUTPUT" | sed -r 's/^(.*): .*\((.*)\)$/\1 \2/g')
|
||||||
|
DEV_COUNT=$(echo "$DEV_PATH_NAMES" | wc -l)
|
||||||
|
|
||||||
|
for i in $(seq 1 $DEV_COUNT)
|
||||||
|
do
|
||||||
|
DEV_PATH_NAME=$(echo "$DEV_PATH_NAMES" | sed "${i}q;d")
|
||||||
|
DEV_PATH=$(echo "$DEV_PATH_NAME" | cut -d' ' -f1)
|
||||||
|
DEV_NAME=$(echo "$DEV_PATH_NAME" | cut -d' ' -f1 --complement)
|
||||||
|
DEV_PRETTY=$(echo "$DEV_NAME (at '$DEV_PATH')")
|
||||||
|
if expr match "$(${FIDO_TOOLS_PREFIX}fido2-token -I $DEV_PATH)" ".* credMgmt.* clientPin.*\|.* clientPin.* credMgmt.*" > /dev/null ; then
|
||||||
|
printf "Enter PIN for $DEV_PRETTY once (ignore further prompts): "
|
||||||
|
stty -echo
|
||||||
|
read PIN
|
||||||
|
stty echo
|
||||||
|
printf "\n"
|
||||||
|
RESIDENT_RPS=$(echo "${PIN}\n" | setsid -w ${FIDO_TOOLS_PREFIX}fido2-token -L -r $DEV_PATH | cut -d' ' -f3)
|
||||||
|
printf "\n"
|
||||||
|
RESIDENT_RPS_COUNT=$(echo "$RESIDENT_RPS" | wc -l)
|
||||||
|
FOUND=0
|
||||||
|
for j in $(seq 1 $DEV_RESIDENT_RPS_COUNT)
|
||||||
|
do
|
||||||
|
RESIDENT_RP=$(echo "$RESIDENT_RPS" | sed "${j}q;d")
|
||||||
|
UNPROT_CREDS=$(echo "${PIN}\n" | setsid -w ${FIDO_TOOLS_PREFIX}fido2-token -L -k $RESIDENT_RP $DEV_PATH | grep ' uvopt$' | cut -d' ' -f2,3,4)
|
||||||
|
printf "\n"
|
||||||
|
UNPROT_CREDS_COUNT=$(echo "$UNPROT_CREDS" | wc -l)
|
||||||
|
if [ $UNPROT_CREDS_COUNT -gt 0 ] ; then
|
||||||
|
FOUND=1
|
||||||
|
echo "Unprotected credentials on $DEV_PRETTY for '$RESIDENT_RP':"
|
||||||
|
echo "$UNPROT_CREDS"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $FOUND -eq 0 ] ; then
|
||||||
|
echo "No unprotected credentials on $DEV_PRETTY"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "$DEV_PRETTY cannot enumerate credentials"
|
||||||
|
echo "Discovering unprotected SSH credentials only..."
|
||||||
|
STUB_HASH=$(echo -n "" | openssl sha256 -binary | base64)
|
||||||
|
printf "$STUB_HASH\nssh:\n" | ${FIDO_TOOLS_PREFIX}fido2-assert -G -r -t up=false $DEV_PATH 2> /dev/null || ASSERT_EXIT_CODE=$?
|
||||||
|
if [ $ASSERT_EXIT_CODE -eq 0 ] ; then
|
||||||
|
echo "Found an unprotected SSH credential on $DEV_PRETTY!"
|
||||||
|
else
|
||||||
|
echo "No unprotected SSH credentials (default settings) on $DEV_PRETTY"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
printf "\n"
|
||||||
|
done
|
||||||
22
tools/include_check.sh
Normal file
22
tools/include_check.sh
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2019 Yubico AB. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
check() {
|
||||||
|
for f in $(find $1 -maxdepth 1 -name '*.h'); do
|
||||||
|
echo "#include \"$f\"" | \
|
||||||
|
cc $CFLAGS -Isrc -xc -c - -o /dev/null 2>&1
|
||||||
|
echo "$f $CFLAGS $?"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
check examples
|
||||||
|
check fuzz
|
||||||
|
check openbsd-compat
|
||||||
|
CFLAGS="${CFLAGS} -D_FIDO_INTERNAL" check src
|
||||||
|
check src/fido.h
|
||||||
|
check src/fido
|
||||||
|
check tools
|
||||||
618
tools/largeblob.c
Normal file
618
tools/largeblob.c
Normal file
@@ -0,0 +1,618 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2022 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <fido/credman.h>
|
||||||
|
|
||||||
|
#include <cbor.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
#define BOUND (1024UL * 1024UL)
|
||||||
|
|
||||||
|
struct rkmap {
|
||||||
|
fido_credman_rp_t *rp; /* known rps */
|
||||||
|
fido_credman_rk_t **rk; /* rk per rp */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_rkmap(struct rkmap *map)
|
||||||
|
{
|
||||||
|
if (map->rp != NULL) {
|
||||||
|
for (size_t i = 0; i < fido_credman_rp_count(map->rp); i++)
|
||||||
|
fido_credman_rk_free(&map->rk[i]);
|
||||||
|
fido_credman_rp_free(&map->rp);
|
||||||
|
}
|
||||||
|
free(map->rk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
map_known_rps(fido_dev_t *dev, const char *path, struct rkmap *map)
|
||||||
|
{
|
||||||
|
const char *rp_id;
|
||||||
|
char *pin = NULL;
|
||||||
|
size_t n;
|
||||||
|
int r, ok = -1;
|
||||||
|
|
||||||
|
if ((map->rp = fido_credman_rp_new()) == NULL) {
|
||||||
|
warnx("%s: fido_credman_rp_new", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
if ((r = fido_credman_get_dev_rp(dev, map->rp, pin)) != FIDO_OK) {
|
||||||
|
warnx("fido_credman_get_dev_rp: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((n = fido_credman_rp_count(map->rp)) > UINT8_MAX) {
|
||||||
|
warnx("%s: fido_credman_rp_count > UINT8_MAX", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((map->rk = calloc(n, sizeof(*map->rk))) == NULL) {
|
||||||
|
warnx("%s: calloc", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
if ((rp_id = fido_credman_rp_id(map->rp, i)) == NULL) {
|
||||||
|
warnx("%s: fido_credman_rp_id %zu", __func__, i);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((map->rk[i] = fido_credman_rk_new()) == NULL) {
|
||||||
|
warnx("%s: fido_credman_rk_new", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_credman_get_dev_rk(dev, rp_id, map->rk[i],
|
||||||
|
pin)) != FIDO_OK) {
|
||||||
|
warnx("%s: fido_credman_get_dev_rk %s: %s", __func__,
|
||||||
|
rp_id, fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lookup_key(const char *path, fido_dev_t *dev, const char *rp_id,
|
||||||
|
const struct blob *cred_id, char **pin, struct blob *key)
|
||||||
|
{
|
||||||
|
fido_credman_rk_t *rk = NULL;
|
||||||
|
const fido_cred_t *cred = NULL;
|
||||||
|
size_t i, n;
|
||||||
|
int r, ok = -1;
|
||||||
|
|
||||||
|
if ((rk = fido_credman_rk_new()) == NULL) {
|
||||||
|
warnx("%s: fido_credman_rk_new", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, *pin)) != FIDO_OK &&
|
||||||
|
*pin == NULL && should_retry_with_pin(dev, r)) {
|
||||||
|
if ((*pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_credman_get_dev_rk(dev, rp_id, rk, *pin);
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("%s: fido_credman_get_dev_rk: %s", __func__,
|
||||||
|
fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((n = fido_credman_rk_count(rk)) == 0) {
|
||||||
|
warnx("%s: rp id not found", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (n == 1 && cred_id->len == 0) {
|
||||||
|
/* use the credential we found */
|
||||||
|
cred = fido_credman_rk(rk, 0);
|
||||||
|
} else {
|
||||||
|
if (cred_id->len == 0) {
|
||||||
|
warnx("%s: multiple credentials found", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
const fido_cred_t *x = fido_credman_rk(rk, i);
|
||||||
|
if (fido_cred_id_len(x) <= cred_id->len &&
|
||||||
|
!memcmp(fido_cred_id_ptr(x), cred_id->ptr,
|
||||||
|
fido_cred_id_len(x))) {
|
||||||
|
cred = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cred == NULL) {
|
||||||
|
warnx("%s: credential not found", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (fido_cred_largeblob_key_ptr(cred) == NULL) {
|
||||||
|
warnx("%s: no associated blob key", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
key->len = fido_cred_largeblob_key_len(cred);
|
||||||
|
if ((key->ptr = malloc(key->len)) == NULL) {
|
||||||
|
warnx("%s: malloc", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memcpy(key->ptr, fido_cred_largeblob_key_ptr(cred), key->len);
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_credman_rk_free(&rk);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
load_key(const char *keyf, const char *cred_id64, const char *rp_id,
|
||||||
|
const char *path, fido_dev_t *dev, char **pin, struct blob *key)
|
||||||
|
{
|
||||||
|
struct blob cred_id;
|
||||||
|
FILE *fp;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
memset(&cred_id, 0, sizeof(cred_id));
|
||||||
|
|
||||||
|
if (keyf != NULL) {
|
||||||
|
if (rp_id != NULL || cred_id64 != NULL)
|
||||||
|
usage();
|
||||||
|
fp = open_read(keyf);
|
||||||
|
if ((r = base64_read(fp, key)) < 0)
|
||||||
|
warnx("%s: base64_read %s", __func__, keyf);
|
||||||
|
fclose(fp);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (rp_id == NULL)
|
||||||
|
usage();
|
||||||
|
if (cred_id64 != NULL && base64_decode(cred_id64, (void *)&cred_id.ptr,
|
||||||
|
&cred_id.len) < 0) {
|
||||||
|
warnx("%s: base64_decode %s", __func__, cred_id64);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
r = lookup_key(path, dev, rp_id, &cred_id, pin, key);
|
||||||
|
free(cred_id.ptr);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
blob_set(const char *path, const char *keyf, const char *rp_id,
|
||||||
|
const char *cred_id64, const char *blobf)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev;
|
||||||
|
struct blob key, blob;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
memset(&key, 0, sizeof(key));
|
||||||
|
memset(&blob, 0, sizeof(blob));
|
||||||
|
|
||||||
|
if (read_file(blobf, &blob.ptr, &blob.len) < 0 ||
|
||||||
|
load_key(keyf, cred_id64, rp_id, path, dev, &pin, &key) < 0)
|
||||||
|
goto out;
|
||||||
|
if ((r = fido_dev_largeblob_set(dev, key.ptr, key.len, blob.ptr,
|
||||||
|
blob.len, pin)) != FIDO_OK && should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_dev_largeblob_set(dev, key.ptr, key.len, blob.ptr,
|
||||||
|
blob.len, pin);
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_dev_largeblob_set: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0; /* success */
|
||||||
|
out:
|
||||||
|
freezero(key.ptr, key.len);
|
||||||
|
freezero(blob.ptr, blob.len);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
blob_get(const char *path, const char *keyf, const char *rp_id,
|
||||||
|
const char *cred_id64, const char *blobf)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev;
|
||||||
|
struct blob key, blob;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
memset(&key, 0, sizeof(key));
|
||||||
|
memset(&blob, 0, sizeof(blob));
|
||||||
|
|
||||||
|
if (load_key(keyf, cred_id64, rp_id, path, dev, &pin, &key) < 0)
|
||||||
|
goto out;
|
||||||
|
if ((r = fido_dev_largeblob_get(dev, key.ptr, key.len, &blob.ptr,
|
||||||
|
&blob.len)) != FIDO_OK) {
|
||||||
|
warnx("fido_dev_largeblob_get: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (write_file(blobf, blob.ptr, blob.len) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ok = 0; /* success */
|
||||||
|
out:
|
||||||
|
freezero(key.ptr, key.len);
|
||||||
|
freezero(blob.ptr, blob.len);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
blob_delete(const char *path, const char *keyf, const char *rp_id,
|
||||||
|
const char *cred_id64)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev;
|
||||||
|
struct blob key;
|
||||||
|
char *pin = NULL;
|
||||||
|
int r, ok = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
memset(&key, 0, sizeof(key));
|
||||||
|
|
||||||
|
if (load_key(keyf, cred_id64, rp_id, path, dev, &pin, &key) < 0)
|
||||||
|
goto out;
|
||||||
|
if ((r = fido_dev_largeblob_remove(dev, key.ptr, key.len,
|
||||||
|
pin)) != FIDO_OK && should_retry_with_pin(dev, r)) {
|
||||||
|
if ((pin = get_pin(path)) == NULL)
|
||||||
|
goto out;
|
||||||
|
r = fido_dev_largeblob_remove(dev, key.ptr, key.len, pin);
|
||||||
|
}
|
||||||
|
if (r != FIDO_OK) {
|
||||||
|
warnx("fido_dev_largeblob_remove: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0; /* success */
|
||||||
|
out:
|
||||||
|
freezero(key.ptr, key.len);
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
try_decompress(const struct blob *in, uint64_t origsiz, int wbits)
|
||||||
|
{
|
||||||
|
struct blob out;
|
||||||
|
z_stream zs;
|
||||||
|
u_int ilen, olen;
|
||||||
|
int ok = -1;
|
||||||
|
|
||||||
|
memset(&zs, 0, sizeof(zs));
|
||||||
|
memset(&out, 0, sizeof(out));
|
||||||
|
|
||||||
|
if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND)
|
||||||
|
return -1;
|
||||||
|
if (origsiz > SIZE_MAX || origsiz > UINT_MAX ||
|
||||||
|
(olen = (u_int)origsiz) > BOUND)
|
||||||
|
return -1;
|
||||||
|
if (inflateInit2(&zs, wbits) != Z_OK)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((out.ptr = calloc(1, olen)) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
out.len = olen;
|
||||||
|
zs.next_in = in->ptr;
|
||||||
|
zs.avail_in = ilen;
|
||||||
|
zs.next_out = out.ptr;
|
||||||
|
zs.avail_out = olen;
|
||||||
|
|
||||||
|
if (inflate(&zs, Z_FINISH) != Z_STREAM_END)
|
||||||
|
goto fail;
|
||||||
|
if (zs.avail_out != 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
fail:
|
||||||
|
if (inflateEnd(&zs) != Z_OK)
|
||||||
|
ok = -1;
|
||||||
|
|
||||||
|
freezero(out.ptr, out.len);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
decompress(const struct blob *plaintext, uint64_t origsiz)
|
||||||
|
{
|
||||||
|
if (try_decompress(plaintext, origsiz, MAX_WBITS) == 0) /* rfc1950 */
|
||||||
|
return 0;
|
||||||
|
return try_decompress(plaintext, origsiz, -MAX_WBITS); /* rfc1951 */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
decode(const struct blob *ciphertext, const struct blob *nonce,
|
||||||
|
uint64_t origsiz, const fido_cred_t *cred)
|
||||||
|
{
|
||||||
|
uint8_t aad[4 + sizeof(uint64_t)];
|
||||||
|
EVP_CIPHER_CTX *ctx = NULL;
|
||||||
|
const EVP_CIPHER *cipher;
|
||||||
|
struct blob plaintext;
|
||||||
|
uint64_t tmp;
|
||||||
|
int ok = -1;
|
||||||
|
|
||||||
|
memset(&plaintext, 0, sizeof(plaintext));
|
||||||
|
|
||||||
|
if (nonce->len != 12)
|
||||||
|
return -1;
|
||||||
|
if (cred == NULL ||
|
||||||
|
fido_cred_largeblob_key_ptr(cred) == NULL ||
|
||||||
|
fido_cred_largeblob_key_len(cred) != 32)
|
||||||
|
return -1;
|
||||||
|
if (ciphertext->len > UINT_MAX ||
|
||||||
|
ciphertext->len > SIZE_MAX - 16 ||
|
||||||
|
ciphertext->len < 16)
|
||||||
|
return -1;
|
||||||
|
plaintext.len = ciphertext->len - 16;
|
||||||
|
if ((plaintext.ptr = calloc(1, plaintext.len)) == NULL)
|
||||||
|
return -1;
|
||||||
|
if ((ctx = EVP_CIPHER_CTX_new()) == NULL ||
|
||||||
|
(cipher = EVP_aes_256_gcm()) == NULL ||
|
||||||
|
EVP_CipherInit(ctx, cipher, fido_cred_largeblob_key_ptr(cred),
|
||||||
|
nonce->ptr, 0) == 0)
|
||||||
|
goto out;
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16,
|
||||||
|
ciphertext->ptr + ciphertext->len - 16) == 0)
|
||||||
|
goto out;
|
||||||
|
aad[0] = 0x62; /* b */
|
||||||
|
aad[1] = 0x6c; /* l */
|
||||||
|
aad[2] = 0x6f; /* o */
|
||||||
|
aad[3] = 0x62; /* b */
|
||||||
|
tmp = htole64(origsiz);
|
||||||
|
memcpy(&aad[4], &tmp, sizeof(uint64_t));
|
||||||
|
if (EVP_Cipher(ctx, NULL, aad, (u_int)sizeof(aad)) < 0 ||
|
||||||
|
EVP_Cipher(ctx, plaintext.ptr, ciphertext->ptr,
|
||||||
|
(u_int)plaintext.len) < 0 ||
|
||||||
|
EVP_Cipher(ctx, NULL, NULL, 0) < 0)
|
||||||
|
goto out;
|
||||||
|
if (decompress(&plaintext, origsiz) < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
freezero(plaintext.ptr, plaintext.len);
|
||||||
|
|
||||||
|
if (ctx != NULL)
|
||||||
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const fido_cred_t *
|
||||||
|
try_rp(const fido_credman_rk_t *rk, const struct blob *ciphertext,
|
||||||
|
const struct blob *nonce, uint64_t origsiz)
|
||||||
|
{
|
||||||
|
const fido_cred_t *cred;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fido_credman_rk_count(rk); i++)
|
||||||
|
if ((cred = fido_credman_rk(rk, i)) != NULL &&
|
||||||
|
decode(ciphertext, nonce, origsiz, cred) == 0)
|
||||||
|
return cred;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
decode_cbor_blob(struct blob *out, const cbor_item_t *item)
|
||||||
|
{
|
||||||
|
if (out->ptr != NULL ||
|
||||||
|
cbor_isa_bytestring(item) == false ||
|
||||||
|
cbor_bytestring_is_definite(item) == false)
|
||||||
|
return -1;
|
||||||
|
out->len = cbor_bytestring_length(item);
|
||||||
|
if ((out->ptr = malloc(out->len)) == NULL)
|
||||||
|
return -1;
|
||||||
|
memcpy(out->ptr, cbor_bytestring_handle(item), out->len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
decode_blob_entry(const cbor_item_t *item, struct blob *ciphertext,
|
||||||
|
struct blob *nonce, uint64_t *origsiz)
|
||||||
|
{
|
||||||
|
struct cbor_pair *v;
|
||||||
|
|
||||||
|
if (item == NULL)
|
||||||
|
return -1;
|
||||||
|
if (cbor_isa_map(item) == false ||
|
||||||
|
cbor_map_is_definite(item) == false ||
|
||||||
|
(v = cbor_map_handle(item)) == NULL)
|
||||||
|
return -1;
|
||||||
|
if (cbor_map_size(item) > UINT8_MAX)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < cbor_map_size(item); i++) {
|
||||||
|
if (cbor_isa_uint(v[i].key) == false ||
|
||||||
|
cbor_int_get_width(v[i].key) != CBOR_INT_8)
|
||||||
|
continue; /* ignore */
|
||||||
|
switch (cbor_get_uint8(v[i].key)) {
|
||||||
|
case 1: /* ciphertext */
|
||||||
|
if (decode_cbor_blob(ciphertext, v[i].value) < 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case 2: /* nonce */
|
||||||
|
if (decode_cbor_blob(nonce, v[i].value) < 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case 3: /* origSize */
|
||||||
|
if (*origsiz != 0 ||
|
||||||
|
cbor_isa_uint(v[i].value) == false ||
|
||||||
|
(*origsiz = cbor_get_int(v[i].value)) > SIZE_MAX)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ciphertext->ptr == NULL || nonce->ptr == NULL || *origsiz == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_blob_entry(size_t idx, const cbor_item_t *item, const struct rkmap *map)
|
||||||
|
{
|
||||||
|
struct blob ciphertext, nonce;
|
||||||
|
const fido_cred_t *cred = NULL;
|
||||||
|
const char *rp_id = NULL;
|
||||||
|
char *cred_id = NULL;
|
||||||
|
uint64_t origsiz = 0;
|
||||||
|
|
||||||
|
memset(&ciphertext, 0, sizeof(ciphertext));
|
||||||
|
memset(&nonce, 0, sizeof(nonce));
|
||||||
|
|
||||||
|
if (decode_blob_entry(item, &ciphertext, &nonce, &origsiz) < 0) {
|
||||||
|
printf("%02zu: <skipped: bad cbor>\n", idx);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < fido_credman_rp_count(map->rp); i++) {
|
||||||
|
if ((cred = try_rp(map->rk[i], &ciphertext, &nonce,
|
||||||
|
origsiz)) != NULL) {
|
||||||
|
rp_id = fido_credman_rp_id(map->rp, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cred == NULL) {
|
||||||
|
if ((cred_id = strdup("<unknown>")) == NULL) {
|
||||||
|
printf("%02zu: <skipped: strdup failed>\n", idx);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (base64_encode(fido_cred_id_ptr(cred),
|
||||||
|
fido_cred_id_len(cred), &cred_id) < 0) {
|
||||||
|
printf("%02zu: <skipped: base64_encode failed>\n", idx);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rp_id == NULL)
|
||||||
|
rp_id = "<unknown>";
|
||||||
|
|
||||||
|
printf("%02zu: %4zu %4zu %s %s\n", idx, ciphertext.len,
|
||||||
|
(size_t)origsiz, cred_id, rp_id);
|
||||||
|
out:
|
||||||
|
free(ciphertext.ptr);
|
||||||
|
free(nonce.ptr);
|
||||||
|
free(cred_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static cbor_item_t *
|
||||||
|
get_cbor_array(fido_dev_t *dev)
|
||||||
|
{
|
||||||
|
struct cbor_load_result cbor_result;
|
||||||
|
cbor_item_t *item = NULL;
|
||||||
|
u_char *cbor_ptr = NULL;
|
||||||
|
size_t cbor_len;
|
||||||
|
int r, ok = -1;
|
||||||
|
|
||||||
|
if ((r = fido_dev_largeblob_get_array(dev, &cbor_ptr,
|
||||||
|
&cbor_len)) != FIDO_OK) {
|
||||||
|
warnx("%s: fido_dev_largeblob_get_array: %s", __func__,
|
||||||
|
fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((item = cbor_load(cbor_ptr, cbor_len, &cbor_result)) == NULL) {
|
||||||
|
warnx("%s: cbor_load", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (cbor_result.read != cbor_len) {
|
||||||
|
warnx("%s: cbor_result.read (%zu) != cbor_len (%zu)", __func__,
|
||||||
|
cbor_result.read, cbor_len);
|
||||||
|
/* continue */
|
||||||
|
}
|
||||||
|
if (cbor_isa_array(item) == false ||
|
||||||
|
cbor_array_is_definite(item) == false) {
|
||||||
|
warnx("%s: cbor type", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (cbor_array_size(item) > UINT8_MAX) {
|
||||||
|
warnx("%s: cbor_array_size > UINT8_MAX", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (cbor_array_size(item) == 0) {
|
||||||
|
ok = 0; /* nothing to do */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("total map size: %zu byte%s\n", cbor_len, plural(cbor_len));
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
if (ok < 0 && item != NULL) {
|
||||||
|
cbor_decref(&item);
|
||||||
|
item = NULL;
|
||||||
|
}
|
||||||
|
free(cbor_ptr);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
blob_list(const char *path)
|
||||||
|
{
|
||||||
|
struct rkmap map;
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
cbor_item_t *item = NULL, **v;
|
||||||
|
int ok = 1;
|
||||||
|
|
||||||
|
memset(&map, 0, sizeof(map));
|
||||||
|
dev = open_dev(path);
|
||||||
|
if (map_known_rps(dev, path, &map) < 0 ||
|
||||||
|
(item = get_cbor_array(dev)) == NULL)
|
||||||
|
goto out;
|
||||||
|
if (cbor_array_size(item) == 0) {
|
||||||
|
ok = 0; /* nothing to do */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((v = cbor_array_handle(item)) == NULL) {
|
||||||
|
warnx("%s: cbor_array_handle", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < cbor_array_size(item); i++)
|
||||||
|
print_blob_entry(i, v[i], &map);
|
||||||
|
|
||||||
|
ok = 0; /* success */
|
||||||
|
out:
|
||||||
|
free_rkmap(&map);
|
||||||
|
|
||||||
|
if (item != NULL)
|
||||||
|
cbor_decref(&item);
|
||||||
|
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(ok);
|
||||||
|
}
|
||||||
159
tools/pin.c
Normal file
159
tools/pin.c
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
pin_set(char *path)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
char prompt[1024];
|
||||||
|
char pin1[128];
|
||||||
|
char pin2[128];
|
||||||
|
int r;
|
||||||
|
int status = 1;
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
|
||||||
|
r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path);
|
||||||
|
if (r < 0 || (size_t)r >= sizeof(prompt)) {
|
||||||
|
warnx("snprintf");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) {
|
||||||
|
warnx("readpassphrase");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: ");
|
||||||
|
if (r < 0 || (size_t)r >= sizeof(prompt)) {
|
||||||
|
warnx("snprintf");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) {
|
||||||
|
warnx("readpassphrase");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(pin1, pin2) != 0) {
|
||||||
|
fprintf(stderr, "PINs do not match. Try again.\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(pin1) < 4 || strlen(pin1) > 63) {
|
||||||
|
fprintf(stderr, "invalid PIN length\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r = fido_dev_set_pin(dev, pin1, NULL)) != FIDO_OK) {
|
||||||
|
warnx("fido_dev_set_pin: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
status = 0;
|
||||||
|
out:
|
||||||
|
explicit_bzero(pin1, sizeof(pin1));
|
||||||
|
explicit_bzero(pin2, sizeof(pin2));
|
||||||
|
|
||||||
|
exit(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pin_change(char *path)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
char prompt[1024];
|
||||||
|
char pin0[128];
|
||||||
|
char pin1[128];
|
||||||
|
char pin2[128];
|
||||||
|
int r;
|
||||||
|
int status = 1;
|
||||||
|
|
||||||
|
if (path == NULL)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
|
||||||
|
r = snprintf(prompt, sizeof(prompt), "Enter current PIN for %s: ", path);
|
||||||
|
if (r < 0 || (size_t)r >= sizeof(prompt)) {
|
||||||
|
warnx("snprintf");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readpassphrase(prompt, pin0, sizeof(pin0), RPP_ECHO_OFF)) {
|
||||||
|
warnx("readpassphrase");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(pin0) < 4 || strlen(pin0) > 63) {
|
||||||
|
warnx("invalid PIN length");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path);
|
||||||
|
if (r < 0 || (size_t)r >= sizeof(prompt)) {
|
||||||
|
warnx("snprintf");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) {
|
||||||
|
warnx("readpassphrase");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: ");
|
||||||
|
if (r < 0 || (size_t)r >= sizeof(prompt)) {
|
||||||
|
warnx("snprintf");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) {
|
||||||
|
warnx("readpassphrase");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(pin1, pin2) != 0) {
|
||||||
|
fprintf(stderr, "PINs do not match. Try again.\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(pin1) < 4 || strlen(pin1) > 63) {
|
||||||
|
fprintf(stderr, "invalid PIN length\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r = fido_dev_set_pin(dev, pin1, pin0)) != FIDO_OK) {
|
||||||
|
warnx("fido_dev_set_pin: %s", fido_strerr(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
status = 0;
|
||||||
|
out:
|
||||||
|
explicit_bzero(pin0, sizeof(pin0));
|
||||||
|
explicit_bzero(pin1, sizeof(pin1));
|
||||||
|
explicit_bzero(pin2, sizeof(pin2));
|
||||||
|
|
||||||
|
exit(status);
|
||||||
|
}
|
||||||
304
tools/test.sh
Normal file
304
tools/test.sh
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
#!/bin/sh -ex
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2022 Yubico AB. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
# usage: ./test.sh "$(mktemp -d fido2test-XXXXXXXX)" device
|
||||||
|
|
||||||
|
# Please note that this test script:
|
||||||
|
# - is incomplete;
|
||||||
|
# - assumes CTAP 2.1-like hmac-secret;
|
||||||
|
# - should pass as-is on a YubiKey with a PIN set;
|
||||||
|
# - may otherwise require set +e above;
|
||||||
|
# - can be executed with UV=1 to run additional UV tests;
|
||||||
|
# - was last tested on 2022-01-11 with firmware 5.4.3.
|
||||||
|
|
||||||
|
cd "$1"
|
||||||
|
DEV="$2"
|
||||||
|
TYPE="es256"
|
||||||
|
#TYPE="es384"
|
||||||
|
#TYPE="eddsa"
|
||||||
|
|
||||||
|
make_cred() {
|
||||||
|
sed /^$/d > cred_param << EOF
|
||||||
|
$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64)
|
||||||
|
$1
|
||||||
|
some user name
|
||||||
|
$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64)
|
||||||
|
EOF
|
||||||
|
fido2-cred -M $2 "${DEV}" "${TYPE}" > "$3" < cred_param
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_cred() {
|
||||||
|
fido2-cred -V $1 "${TYPE}" > cred_out < "$2"
|
||||||
|
head -1 cred_out > "$3"
|
||||||
|
tail -n +2 cred_out > "$4"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_assert() {
|
||||||
|
sed /^$/d > assert_param << EOF
|
||||||
|
$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64)
|
||||||
|
$1
|
||||||
|
$(cat $3)
|
||||||
|
$(cat $4)
|
||||||
|
EOF
|
||||||
|
fido2-assert -G $2 "${DEV}" > "$5" < assert_param
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_assert() {
|
||||||
|
fido2-assert -V $1 "$2" "${TYPE}" < "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
dd if=/dev/urandom bs=32 count=1 | base64 > hmac-salt
|
||||||
|
|
||||||
|
# u2f
|
||||||
|
if [ "x${TYPE}" = "xes256" ]; then
|
||||||
|
make_cred no.tld "-u" u2f
|
||||||
|
! make_cred no.tld "-ru" /dev/null
|
||||||
|
! make_cred no.tld "-uc1" /dev/null
|
||||||
|
! make_cred no.tld "-uc2" /dev/null
|
||||||
|
verify_cred "--" u2f u2f-cred u2f-pubkey
|
||||||
|
! verify_cred "-h" u2f /dev/null /dev/null
|
||||||
|
! verify_cred "-v" u2f /dev/null /dev/null
|
||||||
|
verify_cred "-c0" u2f /dev/null /dev/null
|
||||||
|
! verify_cred "-c1" u2f /dev/null /dev/null
|
||||||
|
! verify_cred "-c2" u2f /dev/null /dev/null
|
||||||
|
! verify_cred "-c3" u2f /dev/null /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# wrap (non-resident)
|
||||||
|
make_cred no.tld "--" wrap
|
||||||
|
verify_cred "--" wrap wrap-cred wrap-pubkey
|
||||||
|
! verify_cred "-h" wrap /dev/null /dev/null
|
||||||
|
! verify_cred "-v" wrap /dev/null /dev/null
|
||||||
|
verify_cred "-c0" wrap /dev/null /dev/null
|
||||||
|
! verify_cred "-c1" wrap /dev/null /dev/null
|
||||||
|
! verify_cred "-c2" wrap /dev/null /dev/null
|
||||||
|
! verify_cred "-c3" wrap /dev/null /dev/null
|
||||||
|
|
||||||
|
# wrap (non-resident) + hmac-secret
|
||||||
|
make_cred no.tld "-h" wrap-hs
|
||||||
|
! verify_cred "--" wrap-hs /dev/null /dev/null
|
||||||
|
verify_cred "-h" wrap-hs wrap-hs-cred wrap-hs-pubkey
|
||||||
|
! verify_cred "-v" wrap-hs /dev/null /dev/null
|
||||||
|
verify_cred "-hc0" wrap-hs /dev/null /dev/null
|
||||||
|
! verify_cred "-c0" wrap-hs /dev/null /dev/null
|
||||||
|
! verify_cred "-c1" wrap-hs /dev/null /dev/null
|
||||||
|
! verify_cred "-c2" wrap-hs /dev/null /dev/null
|
||||||
|
! verify_cred "-c3" wrap-hs /dev/null /dev/null
|
||||||
|
|
||||||
|
# resident
|
||||||
|
make_cred no.tld "-r" rk
|
||||||
|
verify_cred "--" rk rk-cred rk-pubkey
|
||||||
|
! verify_cred "-h" rk /dev/null /dev/null
|
||||||
|
! verify_cred "-v" rk /dev/null /dev/null
|
||||||
|
verify_cred "-c0" rk /dev/null /dev/null
|
||||||
|
! verify_cred "-c1" rk /dev/null /dev/null
|
||||||
|
! verify_cred "-c2" rk /dev/null /dev/null
|
||||||
|
! verify_cred "-c3" rk /dev/null /dev/null
|
||||||
|
|
||||||
|
# resident + hmac-secret
|
||||||
|
make_cred no.tld "-hr" rk-hs
|
||||||
|
! verify_cred "--" rk-hs rk-hs-cred rk-hs-pubkey
|
||||||
|
verify_cred "-h" rk-hs /dev/null /dev/null
|
||||||
|
! verify_cred "-v" rk-hs /dev/null /dev/null
|
||||||
|
verify_cred "-hc0" rk-hs /dev/null /dev/null
|
||||||
|
! verify_cred "-c0" rk-hs /dev/null /dev/null
|
||||||
|
! verify_cred "-c1" rk-hs /dev/null /dev/null
|
||||||
|
! verify_cred "-c2" rk-hs /dev/null /dev/null
|
||||||
|
! verify_cred "-c3" rk-hs /dev/null /dev/null
|
||||||
|
|
||||||
|
# u2f
|
||||||
|
if [ "x${TYPE}" = "xes256" ]; then
|
||||||
|
get_assert no.tld "-u" u2f-cred /dev/null u2f-assert
|
||||||
|
! get_assert no.tld "-u -t up=false" u2f-cred /dev/null /dev/null
|
||||||
|
verify_assert "--" u2f-pubkey u2f-assert
|
||||||
|
verify_assert "-p" u2f-pubkey u2f-assert
|
||||||
|
fi
|
||||||
|
|
||||||
|
# wrap (non-resident)
|
||||||
|
get_assert no.tld "--" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t pin=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t pin=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-p" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=true -t pin=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-p" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-pv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=true -t pin=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-p" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
! verify_assert "-p" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=false -t pin=true" wrap-cred /dev/null wrap-assert
|
||||||
|
! verify_assert "-p" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
! verify_assert "-pv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=false -t pin=false" wrap-cred /dev/null wrap-assert
|
||||||
|
! verify_assert "-p" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h" wrap-cred hmac-salt wrap-assert
|
||||||
|
! verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-h" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t pin=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
! verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-h" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-hv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t pin=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
! verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-h" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t up=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
! verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-h" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-hp" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t up=true -t pin=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
! verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-h" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-hp" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-hv" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-hpv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t up=true -t pin=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
! verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-h" wrap-pubkey wrap-assert
|
||||||
|
verify_assert "-hp" wrap-pubkey wrap-assert
|
||||||
|
! get_assert no.tld "-h -t up=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-h -t up=false -t pin=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-h -t up=false -t pin=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
|
||||||
|
if [ "x${UV}" != "x" ]; then
|
||||||
|
get_assert no.tld "-t uv=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t uv=true -t pin=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t uv=true -t pin=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t uv=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t uv=false -t pin=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t uv=false -t pin=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=true -t uv=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-pv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=true -t uv=true -t pin=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-pv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=true -t uv=true -t pin=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-pv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=true -t uv=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-p" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=true -t uv=false -t pin=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-pv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=true -t uv=false -t pin=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-p" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=false -t uv=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=false -t uv=true -t pin=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=false -t uv=true -t pin=false" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=false -t uv=false" wrap-cred /dev/null wrap-assert
|
||||||
|
! verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=false -t uv=false -t pin=true" wrap-cred /dev/null wrap-assert
|
||||||
|
verify_assert "-v" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-t up=false -t uv=false -t pin=false" wrap-cred /dev/null wrap-assert
|
||||||
|
! verify_assert "--" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t uv=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t uv=true -t pin=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t uv=true -t pin=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t uv=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-h" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t uv=false -t pin=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t uv=false -t pin=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-h" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t up=true -t uv=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hpv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t up=true -t uv=true -t pin=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hpv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t up=true -t uv=true -t pin=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hpv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t up=true -t uv=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hp" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t up=true -t uv=false -t pin=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hpv" wrap-pubkey wrap-assert
|
||||||
|
get_assert no.tld "-h -t up=true -t uv=false -t pin=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
verify_assert "-hp" wrap-pubkey wrap-assert
|
||||||
|
! get_assert no.tld "-h -t up=false -t uv=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-h -t up=false -t uv=true -t pin=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-h -t up=false -t uv=true -t pin=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-h -t up=false -t uv=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-h -t up=false -t uv=false -t pin=true" wrap-cred hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-h -t up=false -t uv=false -t pin=false" wrap-cred hmac-salt wrap-assert
|
||||||
|
fi
|
||||||
|
|
||||||
|
# resident
|
||||||
|
get_assert no.tld "-r" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t pin=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t pin=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=true -t pin=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=true -t pin=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=false -t pin=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=false -t pin=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -h" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t pin=true" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t pin=false" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t up=true" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t up=true -t pin=true" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t up=true -t pin=false" /dev/null hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-r -h -t up=false" /dev/null hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-r -h -t up=false -t pin=true" /dev/null hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-r -h -t up=false -t pin=false" /dev/null hmac-salt wrap-assert
|
||||||
|
|
||||||
|
if [ "x${UV}" != "x" ]; then
|
||||||
|
get_assert no.tld "-r -t uv=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t uv=true -t pin=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t uv=true -t pin=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t uv=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t uv=false -t pin=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t uv=false -t pin=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=true -t uv=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=true -t uv=true -t pin=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=true -t uv=true -t pin=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=true -t uv=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=true -t uv=false -t pin=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=true -t uv=false -t pin=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=false -t uv=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=false -t uv=true -t pin=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=false -t uv=true -t pin=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=false -t uv=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=false -t uv=false -t pin=true" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -t up=false -t uv=false -t pin=false" /dev/null /dev/null wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t uv=true" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t uv=true -t pin=true" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t uv=true -t pin=false" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t uv=false" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t uv=false -t pin=true" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t uv=false -t pin=false" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t up=true -t uv=true" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t up=true -t uv=true -t pin=true" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t up=true -t uv=true -t pin=false" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t up=true -t uv=false" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t up=true -t uv=false -t pin=true" /dev/null hmac-salt wrap-assert
|
||||||
|
get_assert no.tld "-r -h -t up=true -t uv=false -t pin=false" /dev/null hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-r -h -t up=false -t uv=true" /dev/null hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-r -h -t up=false -t uv=true -t pin=true" /dev/null hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-r -h -t up=false -t uv=true -t pin=false" /dev/null hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-r -h -t up=false -t uv=false" /dev/null hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-r -h -t up=false -t uv=false -t pin=true" /dev/null hmac-salt wrap-assert
|
||||||
|
! get_assert no.tld "-r -h -t up=false -t uv=false -t pin=false" /dev/null hmac-salt wrap-assert
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
738
tools/token.c
Normal file
738
tools/token.c
Normal file
@@ -0,0 +1,738 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2022 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
format_flags(char *ret, size_t retlen, uint8_t flags)
|
||||||
|
{
|
||||||
|
memset(ret, 0, retlen);
|
||||||
|
|
||||||
|
if (flags & FIDO_CAP_WINK) {
|
||||||
|
if (strlcat(ret, "wink,", retlen) >= retlen)
|
||||||
|
goto toolong;
|
||||||
|
} else {
|
||||||
|
if (strlcat(ret, "nowink,", retlen) >= retlen)
|
||||||
|
goto toolong;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & FIDO_CAP_CBOR) {
|
||||||
|
if (strlcat(ret, " cbor,", retlen) >= retlen)
|
||||||
|
goto toolong;
|
||||||
|
} else {
|
||||||
|
if (strlcat(ret, " nocbor,", retlen) >= retlen)
|
||||||
|
goto toolong;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & FIDO_CAP_NMSG) {
|
||||||
|
if (strlcat(ret, " nomsg", retlen) >= retlen)
|
||||||
|
goto toolong;
|
||||||
|
} else {
|
||||||
|
if (strlcat(ret, " msg", retlen) >= retlen)
|
||||||
|
goto toolong;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
toolong:
|
||||||
|
strlcpy(ret, "toolong", retlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_attr(const fido_dev_t *dev)
|
||||||
|
{
|
||||||
|
char flags_txt[128];
|
||||||
|
|
||||||
|
printf("proto: 0x%02x\n", fido_dev_protocol(dev));
|
||||||
|
printf("major: 0x%02x\n", fido_dev_major(dev));
|
||||||
|
printf("minor: 0x%02x\n", fido_dev_minor(dev));
|
||||||
|
printf("build: 0x%02x\n", fido_dev_build(dev));
|
||||||
|
|
||||||
|
format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev));
|
||||||
|
printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_str_array(const char *label, char * const *sa, size_t len)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("%s strings: ", label);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
printf("%s%s", i > 0 ? ", " : "", sa[i]);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_opt_array(const char *label, char * const *name, const bool *value,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("%s: ", label);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
printf("%s%s%s", i > 0 ? ", " : "",
|
||||||
|
value[i] ? "" : "no", name[i]);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_cert_array(const char *label, char * const *name, const uint64_t *value,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("%s: ", label);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
printf("%s%s %llu", i > 0 ? ", " : "", name[i],
|
||||||
|
(unsigned long long)value[i]);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_algorithms(const fido_cbor_info_t *ci)
|
||||||
|
{
|
||||||
|
const char *cose, *type;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if ((len = fido_cbor_info_algorithm_count(ci)) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("algorithms: ");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
cose = type = "unknown";
|
||||||
|
switch (fido_cbor_info_algorithm_cose(ci, i)) {
|
||||||
|
case COSE_ES256:
|
||||||
|
cose = "es256";
|
||||||
|
break;
|
||||||
|
case COSE_ES384:
|
||||||
|
cose = "es384";
|
||||||
|
break;
|
||||||
|
case COSE_RS256:
|
||||||
|
cose = "rs256";
|
||||||
|
break;
|
||||||
|
case COSE_EDDSA:
|
||||||
|
cose = "eddsa";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fido_cbor_info_algorithm_type(ci, i) != NULL)
|
||||||
|
type = fido_cbor_info_algorithm_type(ci, i);
|
||||||
|
printf("%s%s (%s)", i > 0 ? ", " : "", cose, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_aaguid(const unsigned char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
printf("aaguid: ");
|
||||||
|
|
||||||
|
while (buflen--)
|
||||||
|
printf("%02x", *buf++);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_maxmsgsiz(uint64_t maxmsgsiz)
|
||||||
|
{
|
||||||
|
printf("maxmsgsiz: %d\n", (int)maxmsgsiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_maxcredcntlst(uint64_t maxcredcntlst)
|
||||||
|
{
|
||||||
|
printf("maxcredcntlst: %d\n", (int)maxcredcntlst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_maxcredblob(uint64_t maxcredblob)
|
||||||
|
{
|
||||||
|
printf("maxcredblob: %d\n", (int)maxcredblob);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_maxcredidlen(uint64_t maxcredidlen)
|
||||||
|
{
|
||||||
|
printf("maxcredlen: %d\n", (int)maxcredidlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_maxlargeblob(uint64_t maxlargeblob)
|
||||||
|
{
|
||||||
|
printf("maxlargeblob: %d\n", (int)maxlargeblob);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_maxrpid_minpinlen(uint64_t maxrpid)
|
||||||
|
{
|
||||||
|
if (maxrpid > 0)
|
||||||
|
printf("maxrpids in minpinlen: %d\n", (int)maxrpid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_minpinlen(uint64_t minpinlen)
|
||||||
|
{
|
||||||
|
if (minpinlen > 0)
|
||||||
|
printf("minpinlen: %d\n", (int)minpinlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_uv_attempts(uint64_t uv_attempts)
|
||||||
|
{
|
||||||
|
if (uv_attempts > 0)
|
||||||
|
printf("platform uv attempt(s): %d\n", (int)uv_attempts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_uv_modality(uint64_t uv_modality)
|
||||||
|
{
|
||||||
|
uint64_t mode;
|
||||||
|
bool printed = false;
|
||||||
|
|
||||||
|
if (uv_modality == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("uv modality: 0x%x (", (int)uv_modality);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 64; i++) {
|
||||||
|
mode = 1ULL << i;
|
||||||
|
if ((uv_modality & mode) == 0)
|
||||||
|
continue;
|
||||||
|
if (printed)
|
||||||
|
printf(", ");
|
||||||
|
switch (mode) {
|
||||||
|
case FIDO_UV_MODE_TUP:
|
||||||
|
printf("test of user presence");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_FP:
|
||||||
|
printf("fingerprint check");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_PIN:
|
||||||
|
printf("pin check");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_VOICE:
|
||||||
|
printf("voice recognition");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_FACE:
|
||||||
|
printf("face recognition");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_LOCATION:
|
||||||
|
printf("location check");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_EYE:
|
||||||
|
printf("eyeprint check");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_DRAWN:
|
||||||
|
printf("drawn pattern check");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_HAND:
|
||||||
|
printf("handprint verification");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_NONE:
|
||||||
|
printf("none");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_ALL:
|
||||||
|
printf("all required");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_EXT_PIN:
|
||||||
|
printf("external pin");
|
||||||
|
break;
|
||||||
|
case FIDO_UV_MODE_EXT_DRAWN:
|
||||||
|
printf("external drawn pattern check");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unknown 0x%llx", (unsigned long long)mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(")\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_rk_remaining(int64_t rk_remaining)
|
||||||
|
{
|
||||||
|
if (rk_remaining != -1)
|
||||||
|
printf("remaining rk(s): %d\n", (int)rk_remaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_fwversion(uint64_t fwversion)
|
||||||
|
{
|
||||||
|
printf("fwversion: 0x%x\n", (int)fwversion);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_byte_array(const char *label, const uint8_t *ba, size_t len)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("%s: ", label);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
token_info(int argc, char **argv, char *path)
|
||||||
|
{
|
||||||
|
char *cred_id = NULL;
|
||||||
|
char *rp_id = NULL;
|
||||||
|
fido_cbor_info_t *ci = NULL;
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
int ch;
|
||||||
|
int credman = 0;
|
||||||
|
int r;
|
||||||
|
int retrycnt;
|
||||||
|
|
||||||
|
optind = 1;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'c':
|
||||||
|
credman = 1;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
cred_id = optarg;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
rp_id = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; /* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path == NULL || (credman && (cred_id != NULL || rp_id != NULL)))
|
||||||
|
usage();
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
|
||||||
|
if (credman)
|
||||||
|
return (credman_get_metadata(dev, path));
|
||||||
|
if (cred_id && rp_id)
|
||||||
|
return (credman_print_rk(dev, path, rp_id, cred_id));
|
||||||
|
if (cred_id || rp_id)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
print_attr(dev);
|
||||||
|
|
||||||
|
if (fido_dev_is_fido2(dev) == false)
|
||||||
|
goto end;
|
||||||
|
if ((ci = fido_cbor_info_new()) == NULL)
|
||||||
|
errx(1, "fido_cbor_info_new");
|
||||||
|
if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK)
|
||||||
|
errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
|
||||||
|
|
||||||
|
/* print supported protocol versions */
|
||||||
|
print_str_array("version", fido_cbor_info_versions_ptr(ci),
|
||||||
|
fido_cbor_info_versions_len(ci));
|
||||||
|
|
||||||
|
/* print supported extensions */
|
||||||
|
print_str_array("extension", fido_cbor_info_extensions_ptr(ci),
|
||||||
|
fido_cbor_info_extensions_len(ci));
|
||||||
|
|
||||||
|
/* print supported transports */
|
||||||
|
print_str_array("transport", fido_cbor_info_transports_ptr(ci),
|
||||||
|
fido_cbor_info_transports_len(ci));
|
||||||
|
|
||||||
|
/* print supported algorithms */
|
||||||
|
print_algorithms(ci);
|
||||||
|
|
||||||
|
/* print aaguid */
|
||||||
|
print_aaguid(fido_cbor_info_aaguid_ptr(ci),
|
||||||
|
fido_cbor_info_aaguid_len(ci));
|
||||||
|
|
||||||
|
/* print supported options */
|
||||||
|
print_opt_array("options", fido_cbor_info_options_name_ptr(ci),
|
||||||
|
fido_cbor_info_options_value_ptr(ci),
|
||||||
|
fido_cbor_info_options_len(ci));
|
||||||
|
|
||||||
|
/* print certifications */
|
||||||
|
print_cert_array("certifications", fido_cbor_info_certs_name_ptr(ci),
|
||||||
|
fido_cbor_info_certs_value_ptr(ci),
|
||||||
|
fido_cbor_info_certs_len(ci));
|
||||||
|
|
||||||
|
/* print firmware version */
|
||||||
|
print_fwversion(fido_cbor_info_fwversion(ci));
|
||||||
|
|
||||||
|
/* print maximum message size */
|
||||||
|
print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci));
|
||||||
|
|
||||||
|
/* print maximum number of credentials allowed in credential lists */
|
||||||
|
print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci));
|
||||||
|
|
||||||
|
/* print maximum length of a credential ID */
|
||||||
|
print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
|
||||||
|
|
||||||
|
/* print maximum length of credBlob */
|
||||||
|
print_maxcredblob(fido_cbor_info_maxcredbloblen(ci));
|
||||||
|
|
||||||
|
/* print maximum length of serialized largeBlob array */
|
||||||
|
print_maxlargeblob(fido_cbor_info_maxlargeblob(ci));
|
||||||
|
|
||||||
|
/* print maximum number of RP IDs in fido_dev_set_pin_minlen_rpid() */
|
||||||
|
print_maxrpid_minpinlen(fido_cbor_info_maxrpid_minpinlen(ci));
|
||||||
|
|
||||||
|
/* print estimated number of resident credentials */
|
||||||
|
print_rk_remaining(fido_cbor_info_rk_remaining(ci));
|
||||||
|
|
||||||
|
/* print minimum pin length */
|
||||||
|
print_minpinlen(fido_cbor_info_minpinlen(ci));
|
||||||
|
|
||||||
|
/* print supported pin protocols */
|
||||||
|
print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci),
|
||||||
|
fido_cbor_info_protocols_len(ci));
|
||||||
|
|
||||||
|
if (fido_dev_get_retry_count(dev, &retrycnt) != FIDO_OK)
|
||||||
|
printf("pin retries: undefined\n");
|
||||||
|
else
|
||||||
|
printf("pin retries: %d\n", retrycnt);
|
||||||
|
|
||||||
|
printf("pin change required: %s\n",
|
||||||
|
fido_cbor_info_new_pin_required(ci) ? "true" : "false");
|
||||||
|
|
||||||
|
if (fido_dev_get_uv_retry_count(dev, &retrycnt) != FIDO_OK)
|
||||||
|
printf("uv retries: undefined\n");
|
||||||
|
else
|
||||||
|
printf("uv retries: %d\n", retrycnt);
|
||||||
|
|
||||||
|
/* print platform uv attempts */
|
||||||
|
print_uv_attempts(fido_cbor_info_uv_attempts(ci));
|
||||||
|
|
||||||
|
/* print supported uv mechanisms */
|
||||||
|
print_uv_modality(fido_cbor_info_uv_modality(ci));
|
||||||
|
|
||||||
|
bio_info(dev);
|
||||||
|
|
||||||
|
fido_cbor_info_free(&ci);
|
||||||
|
end:
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
token_reset(char *path)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (path == NULL)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
dev = open_dev(path);
|
||||||
|
if ((r = fido_dev_reset(dev)) != FIDO_OK)
|
||||||
|
errx(1, "fido_dev_reset: %s", fido_strerr(r));
|
||||||
|
|
||||||
|
fido_dev_close(dev);
|
||||||
|
fido_dev_free(&dev);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
token_get(int argc, char **argv, char *path)
|
||||||
|
{
|
||||||
|
char *id = NULL;
|
||||||
|
char *key = NULL;
|
||||||
|
char *name = NULL;
|
||||||
|
int blob = 0;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
optind = 1;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'b':
|
||||||
|
blob = 1;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
id = optarg;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
key = optarg;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
name = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; /* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (blob == 0 || argc != 2)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
return blob_get(path, key, name, id, argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
token_set(int argc, char **argv, char *path)
|
||||||
|
{
|
||||||
|
char *id = NULL;
|
||||||
|
char *key = NULL;
|
||||||
|
char *len = NULL;
|
||||||
|
char *display_name = NULL;
|
||||||
|
char *name = NULL;
|
||||||
|
char *rpid = NULL;
|
||||||
|
int blob = 0;
|
||||||
|
int cred = 0;
|
||||||
|
int ch;
|
||||||
|
int enroll = 0;
|
||||||
|
int ea = 0;
|
||||||
|
int uv = 0;
|
||||||
|
bool force = false;
|
||||||
|
|
||||||
|
optind = 1;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'a':
|
||||||
|
ea = 1;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
blob = 1;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
cred = 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
enroll = 1;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
force = true;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
id = optarg;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
key = optarg;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
len = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
display_name = optarg;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
rpid = optarg;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
name = optarg;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
uv = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; /* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (path == NULL)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if (blob) {
|
||||||
|
if (argc != 2)
|
||||||
|
usage();
|
||||||
|
return (blob_set(path, key, name, id, argv[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cred) {
|
||||||
|
if (!id || !key)
|
||||||
|
usage();
|
||||||
|
if (!name && !display_name)
|
||||||
|
usage();
|
||||||
|
return (credman_update_rk(path, key, id, name, display_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enroll) {
|
||||||
|
if (ea || uv)
|
||||||
|
usage();
|
||||||
|
if (id && name)
|
||||||
|
return (bio_set_name(path, id, name));
|
||||||
|
if (!id && !name)
|
||||||
|
return (bio_enroll(path));
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ea) {
|
||||||
|
if (uv)
|
||||||
|
usage();
|
||||||
|
return (config_entattest(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
return (config_pin_minlen(path, len));
|
||||||
|
if (rpid)
|
||||||
|
return (config_pin_minlen_rpid(path, rpid));
|
||||||
|
if (force)
|
||||||
|
return (config_force_pin_change(path));
|
||||||
|
if (uv)
|
||||||
|
return (config_always_uv(path, 1));
|
||||||
|
|
||||||
|
return (pin_set(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
token_list(int argc, char **argv, char *path)
|
||||||
|
{
|
||||||
|
fido_dev_info_t *devlist;
|
||||||
|
size_t ndevs;
|
||||||
|
const char *rp_id = NULL;
|
||||||
|
int blobs = 0;
|
||||||
|
int enrolls = 0;
|
||||||
|
int keys = 0;
|
||||||
|
int rplist = 0;
|
||||||
|
int ch;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
optind = 1;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'b':
|
||||||
|
blobs = 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
enrolls = 1;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
keys = 1;
|
||||||
|
rp_id = optarg;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
rplist = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; /* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blobs || enrolls || keys || rplist) {
|
||||||
|
if (path == NULL)
|
||||||
|
usage();
|
||||||
|
if (blobs)
|
||||||
|
return (blob_list(path));
|
||||||
|
if (enrolls)
|
||||||
|
return (bio_list(path));
|
||||||
|
if (keys)
|
||||||
|
return (credman_list_rk(path, rp_id));
|
||||||
|
if (rplist)
|
||||||
|
return (credman_list_rp(path));
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((devlist = fido_dev_info_new(64)) == NULL)
|
||||||
|
errx(1, "fido_dev_info_new");
|
||||||
|
if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK)
|
||||||
|
errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ndevs; i++) {
|
||||||
|
const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
|
||||||
|
printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n",
|
||||||
|
fido_dev_info_path(di),
|
||||||
|
(uint16_t)fido_dev_info_vendor(di),
|
||||||
|
(uint16_t)fido_dev_info_product(di),
|
||||||
|
fido_dev_info_manufacturer_string(di),
|
||||||
|
fido_dev_info_product_string(di));
|
||||||
|
}
|
||||||
|
|
||||||
|
fido_dev_info_free(&devlist, ndevs);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
token_delete(int argc, char **argv, char *path)
|
||||||
|
{
|
||||||
|
char *id = NULL;
|
||||||
|
char *key = NULL;
|
||||||
|
char *name = NULL;
|
||||||
|
int blob = 0;
|
||||||
|
int ch;
|
||||||
|
int enroll = 0;
|
||||||
|
int uv = 0;
|
||||||
|
|
||||||
|
optind = 1;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'b':
|
||||||
|
blob = 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
enroll = 1;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
id = optarg;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
key = optarg;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
name = optarg;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
uv = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; /* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path == NULL)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if (blob)
|
||||||
|
return (blob_delete(path, key, name, id));
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
if (uv)
|
||||||
|
usage();
|
||||||
|
if (enroll == 0)
|
||||||
|
return (credman_delete_rk(path, id));
|
||||||
|
return (bio_delete(path, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uv == 0)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
return (config_always_uv(path, 0));
|
||||||
|
}
|
||||||
655
tools/util.c
Normal file
655
tools/util.c
Normal file
@@ -0,0 +1,655 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2022 Yubico AB. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <openssl/ec.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
|
#include <fido.h>
|
||||||
|
#include <fido/es256.h>
|
||||||
|
#include <fido/es384.h>
|
||||||
|
#include <fido/rs256.h>
|
||||||
|
#include <fido/eddsa.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../openbsd-compat/openbsd-compat.h"
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include "../openbsd-compat/posix_win.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char*
|
||||||
|
get_pin(const char* path)
|
||||||
|
{
|
||||||
|
char* pin;
|
||||||
|
char prompt[1024];
|
||||||
|
int r, ok = -1;
|
||||||
|
|
||||||
|
|
||||||
|
if ((pin = calloc(1, PINBUF_LEN)) == NULL) {
|
||||||
|
warn("%s: calloc", __func__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if global_pin is empty
|
||||||
|
if (global_pin && global_pin[0] != '\0') {
|
||||||
|
// Use global_pin
|
||||||
|
strncpy(pin, global_pin, PINBUF_LEN - 1);
|
||||||
|
ok = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", path)) < 0 || (size_t)r >= sizeof(prompt)) {
|
||||||
|
warn("%s: snprintf", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readpassphrase(prompt, pin, PINBUF_LEN, RPP_ECHO_OFF)) {
|
||||||
|
warnx("%s: readpassphrase", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
if (ok < 0) {
|
||||||
|
freezero(pin, PINBUF_LEN);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pin;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *
|
||||||
|
open_write(const char *file)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (file == NULL || strcmp(file, "-") == 0)
|
||||||
|
return (stdout);
|
||||||
|
if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0)
|
||||||
|
err(1, "open %s", file);
|
||||||
|
if ((f = fdopen(fd, "w")) == NULL)
|
||||||
|
err(1, "fdopen %s", file);
|
||||||
|
|
||||||
|
return (f);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *
|
||||||
|
open_read(const char *file)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (file == NULL || strcmp(file, "-") == 0) {
|
||||||
|
#ifdef FIDO_FUZZ
|
||||||
|
setvbuf(stdin, NULL, _IONBF, 0);
|
||||||
|
#endif
|
||||||
|
return (stdin);
|
||||||
|
}
|
||||||
|
if ((fd = open(file, O_RDONLY)) < 0)
|
||||||
|
err(1, "open %s", file);
|
||||||
|
if ((f = fdopen(fd, "r")) == NULL)
|
||||||
|
err(1, "fdopen %s", file);
|
||||||
|
|
||||||
|
return (f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
base10(const char *str)
|
||||||
|
{
|
||||||
|
char *ep;
|
||||||
|
long long ll;
|
||||||
|
|
||||||
|
ll = strtoll(str, &ep, 10);
|
||||||
|
if (str == ep || *ep != '\0')
|
||||||
|
return (-1);
|
||||||
|
else if (ll == LLONG_MIN && errno == ERANGE)
|
||||||
|
return (-1);
|
||||||
|
else if (ll == LLONG_MAX && errno == ERANGE)
|
||||||
|
return (-1);
|
||||||
|
else if (ll < 0 || ll > INT_MAX)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
return ((int)ll);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xxd(const void *buf, size_t count)
|
||||||
|
{
|
||||||
|
const uint8_t *ptr = buf;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
fprintf(stderr, " ");
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
fprintf(stderr, "%02x ", *ptr++);
|
||||||
|
if ((i + 1) % 16 == 0 && i + 1 < count)
|
||||||
|
fprintf(stderr, "\n ");
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
string_read(FILE *f, char **out)
|
||||||
|
{
|
||||||
|
char *line = NULL;
|
||||||
|
size_t linesize = 0;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
*out = NULL;
|
||||||
|
|
||||||
|
if ((n = getline(&line, &linesize, f)) <= 0 ||
|
||||||
|
(size_t)n != strlen(line)) {
|
||||||
|
free(line);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
line[n - 1] = '\0'; /* trim \n */
|
||||||
|
*out = line;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fido_dev_t *
|
||||||
|
open_dev(const char *path)
|
||||||
|
{
|
||||||
|
fido_dev_t *dev;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((dev = fido_dev_new()) == NULL)
|
||||||
|
errx(1, "fido_dev_new");
|
||||||
|
|
||||||
|
r = fido_dev_open(dev, path);
|
||||||
|
if (r != FIDO_OK)
|
||||||
|
errx(1, "fido_dev_open %s: %s", path, fido_strerr(r));
|
||||||
|
|
||||||
|
return (dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_devopt(fido_dev_t *dev, const char *name, int *val)
|
||||||
|
{
|
||||||
|
fido_cbor_info_t *cbor_info;
|
||||||
|
char * const *names;
|
||||||
|
const bool *values;
|
||||||
|
int r, ok = -1;
|
||||||
|
|
||||||
|
if ((cbor_info = fido_cbor_info_new()) == NULL) {
|
||||||
|
warnx("fido_cbor_info_new");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r = fido_dev_get_cbor_info(dev, cbor_info)) != FIDO_OK) {
|
||||||
|
warnx("fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((names = fido_cbor_info_options_name_ptr(cbor_info)) == NULL ||
|
||||||
|
(values = fido_cbor_info_options_value_ptr(cbor_info)) == NULL) {
|
||||||
|
warnx("fido_dev_get_cbor_info: NULL name/value pointer");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*val = -1;
|
||||||
|
for (size_t i = 0; i < fido_cbor_info_options_len(cbor_info); i++)
|
||||||
|
if (strcmp(names[i], name) == 0) {
|
||||||
|
*val = values[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
out:
|
||||||
|
fido_cbor_info_free(&cbor_info);
|
||||||
|
|
||||||
|
return (ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
EC_KEY *
|
||||||
|
read_ec_pubkey(const char *path)
|
||||||
|
{
|
||||||
|
FILE *fp = NULL;
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
EC_KEY *ec = NULL;
|
||||||
|
|
||||||
|
if ((fp = fopen(path, "r")) == NULL) {
|
||||||
|
warn("fopen");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
|
||||||
|
warnx("PEM_read_PUBKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
|
||||||
|
warnx("EVP_PKEY_get1_EC_KEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (fp) {
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
if (pkey) {
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
write_es256_pubkey(FILE *f, const void *ptr, size_t len)
|
||||||
|
{
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
es256_pk_t *pk = NULL;
|
||||||
|
int ok = -1;
|
||||||
|
|
||||||
|
if ((pk = es256_pk_new()) == NULL) {
|
||||||
|
warnx("es256_pk_new");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
|
||||||
|
warnx("es256_pk_from_ptr");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
|
||||||
|
warnx("es256_pk_to_EVP_PKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PEM_write_PUBKEY(f, pkey) == 0) {
|
||||||
|
warnx("PEM_write_PUBKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
fail:
|
||||||
|
es256_pk_free(&pk);
|
||||||
|
|
||||||
|
if (pkey != NULL) {
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
write_es384_pubkey(FILE *f, const void *ptr, size_t len)
|
||||||
|
{
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
es384_pk_t *pk = NULL;
|
||||||
|
int ok = -1;
|
||||||
|
|
||||||
|
if ((pk = es384_pk_new()) == NULL) {
|
||||||
|
warnx("es384_pk_new");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
|
||||||
|
warnx("es384_pk_from_ptr");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) {
|
||||||
|
warnx("es384_pk_to_EVP_PKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PEM_write_PUBKEY(f, pkey) == 0) {
|
||||||
|
warnx("PEM_write_PUBKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
fail:
|
||||||
|
es384_pk_free(&pk);
|
||||||
|
|
||||||
|
if (pkey != NULL) {
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
RSA *
|
||||||
|
read_rsa_pubkey(const char *path)
|
||||||
|
{
|
||||||
|
FILE *fp = NULL;
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
RSA *rsa = NULL;
|
||||||
|
|
||||||
|
if ((fp = fopen(path, "r")) == NULL) {
|
||||||
|
warn("fopen");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
|
||||||
|
warnx("PEM_read_PUBKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
|
||||||
|
warnx("EVP_PKEY_get1_RSA");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (fp) {
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
if (pkey) {
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rsa);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
write_rsa_pubkey(FILE *f, const void *ptr, size_t len)
|
||||||
|
{
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
rs256_pk_t *pk = NULL;
|
||||||
|
int ok = -1;
|
||||||
|
|
||||||
|
if ((pk = rs256_pk_new()) == NULL) {
|
||||||
|
warnx("rs256_pk_new");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
|
||||||
|
warnx("rs256_pk_from_ptr");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
|
||||||
|
warnx("rs256_pk_to_EVP_PKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PEM_write_PUBKEY(f, pkey) == 0) {
|
||||||
|
warnx("PEM_write_PUBKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
fail:
|
||||||
|
rs256_pk_free(&pk);
|
||||||
|
|
||||||
|
if (pkey != NULL) {
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_PKEY *
|
||||||
|
read_eddsa_pubkey(const char *path)
|
||||||
|
{
|
||||||
|
FILE *fp = NULL;
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
|
||||||
|
if ((fp = fopen(path, "r")) == NULL) {
|
||||||
|
warn("fopen");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
|
||||||
|
warnx("PEM_read_PUBKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (fp) {
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (pkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
write_eddsa_pubkey(FILE *f, const void *ptr, size_t len)
|
||||||
|
{
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
eddsa_pk_t *pk = NULL;
|
||||||
|
int ok = -1;
|
||||||
|
|
||||||
|
if ((pk = eddsa_pk_new()) == NULL) {
|
||||||
|
warnx("eddsa_pk_new");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
|
||||||
|
warnx("eddsa_pk_from_ptr");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
|
||||||
|
warnx("eddsa_pk_to_EVP_PKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PEM_write_PUBKEY(f, pkey) == 0) {
|
||||||
|
warnx("PEM_write_PUBKEY");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
fail:
|
||||||
|
eddsa_pk_free(&pk);
|
||||||
|
|
||||||
|
if (pkey != NULL) {
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_cred(FILE *out_f, int type, const fido_cred_t *cred)
|
||||||
|
{
|
||||||
|
char *id;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id);
|
||||||
|
if (r < 0)
|
||||||
|
errx(1, "output error");
|
||||||
|
|
||||||
|
fprintf(out_f, "%s\n", id);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case COSE_ES256:
|
||||||
|
write_es256_pubkey(out_f, fido_cred_pubkey_ptr(cred),
|
||||||
|
fido_cred_pubkey_len(cred));
|
||||||
|
break;
|
||||||
|
case COSE_ES384:
|
||||||
|
write_es384_pubkey(out_f, fido_cred_pubkey_ptr(cred),
|
||||||
|
fido_cred_pubkey_len(cred));
|
||||||
|
break;
|
||||||
|
case COSE_RS256:
|
||||||
|
write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
|
||||||
|
fido_cred_pubkey_len(cred));
|
||||||
|
break;
|
||||||
|
case COSE_EDDSA:
|
||||||
|
write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
|
||||||
|
fido_cred_pubkey_len(cred));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errx(1, "print_cred: unknown type");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cose_type(const char *str, int *type)
|
||||||
|
{
|
||||||
|
if (strcmp(str, "es256") == 0)
|
||||||
|
*type = COSE_ES256;
|
||||||
|
else if (strcmp(str, "es384") == 0)
|
||||||
|
*type = COSE_ES384;
|
||||||
|
else if (strcmp(str, "rs256") == 0)
|
||||||
|
*type = COSE_RS256;
|
||||||
|
else if (strcmp(str, "eddsa") == 0)
|
||||||
|
*type = COSE_EDDSA;
|
||||||
|
else {
|
||||||
|
*type = 0;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
cose_string(int type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case COSE_ES256:
|
||||||
|
return ("es256");
|
||||||
|
case COSE_ES384:
|
||||||
|
return ("es384");
|
||||||
|
case COSE_RS256:
|
||||||
|
return ("rs256");
|
||||||
|
case COSE_EDDSA:
|
||||||
|
return ("eddsa");
|
||||||
|
default:
|
||||||
|
return ("unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
prot_string(int prot)
|
||||||
|
{
|
||||||
|
switch (prot) {
|
||||||
|
case FIDO_CRED_PROT_UV_OPTIONAL:
|
||||||
|
return ("uvopt");
|
||||||
|
case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID:
|
||||||
|
return ("uvopt+id");
|
||||||
|
case FIDO_CRED_PROT_UV_REQUIRED:
|
||||||
|
return ("uvreq");
|
||||||
|
default:
|
||||||
|
return ("unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
read_file(const char *path, u_char **ptr, size_t *len)
|
||||||
|
{
|
||||||
|
int fd, ok = -1;
|
||||||
|
struct stat st;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
*ptr = NULL;
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
if ((fd = open(path, O_RDONLY)) < 0) {
|
||||||
|
warn("%s: open %s", __func__, path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (fstat(fd, &st) < 0) {
|
||||||
|
warn("%s: stat %s", __func__, path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (st.st_size < 0) {
|
||||||
|
warnx("%s: stat %s: invalid size", __func__, path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
*len = (size_t)st.st_size;
|
||||||
|
if ((*ptr = malloc(*len)) == NULL) {
|
||||||
|
warn("%s: malloc", __func__);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((n = read(fd, *ptr, *len)) < 0) {
|
||||||
|
warn("%s: read", __func__);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((size_t)n != *len) {
|
||||||
|
warnx("%s: read", __func__);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
fail:
|
||||||
|
if (fd != -1) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
if (ok < 0) {
|
||||||
|
free(*ptr);
|
||||||
|
*ptr = NULL;
|
||||||
|
*len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
write_file(const char *path, const u_char *ptr, size_t len)
|
||||||
|
{
|
||||||
|
int fd, ok = -1;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) {
|
||||||
|
warn("%s: open %s", __func__, path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((n = write(fd, ptr, len)) < 0) {
|
||||||
|
warn("%s: write", __func__);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if ((size_t)n != len) {
|
||||||
|
warnx("%s: write", __func__);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 0;
|
||||||
|
fail:
|
||||||
|
if (fd != -1) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
plural(size_t x)
|
||||||
|
{
|
||||||
|
return x == 1 ? "" : "s";
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
should_retry_with_pin(const fido_dev_t *dev, int r)
|
||||||
|
{
|
||||||
|
if (fido_dev_has_pin(dev) == false) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (r) {
|
||||||
|
case FIDO_ERR_PIN_REQUIRED:
|
||||||
|
case FIDO_ERR_UNAUTHORIZED_PERM:
|
||||||
|
case FIDO_ERR_UV_BLOCKED:
|
||||||
|
case FIDO_ERR_UV_INVALID:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
270
udev/70-u2f.rules
Normal file
270
udev/70-u2f.rules
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
# Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in
|
||||||
|
# the documentation and/or other materials provided with the
|
||||||
|
# distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
# This file is automatically generated, and should be used with udev 188
|
||||||
|
# or newer.
|
||||||
|
|
||||||
|
ACTION!="add|change", GOTO="fido_end"
|
||||||
|
|
||||||
|
# ellipticSecure MIRKey by STMicroelectronics
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ac", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by STMicroelectronics
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by STMicroelectronics
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="cdab", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Infineon FIDO by Infineon Technologies
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="058b", ATTRS{idProduct}=="022d", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Kensington VeriMark by Synaptics Inc.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="0088", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# FS ePass FIDO by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0850", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0852", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0853", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0854", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0856", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0858", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# FS MultiPass FIDO U2F by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085a", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085b", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085d", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# BioPass FIDO2 K33 by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0866", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# BioPass FIDO2 K43 by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0867", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Hypersecu HyperFIDO by Feitian Technologies Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# YubiKey NEO FIDO by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# YubiKey NEO OTP+FIDO by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0114", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# YubiKey NEO FIDO+CCID by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0115", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# YubiKey NEO OTP+FIDO+CCID by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0116", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Security Key by Yubico by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0120", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Unknown product by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0121", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Gnubby U2F by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0200", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# YubiKey 4 FIDO by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0402", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# YubiKey 4 OTP+FIDO by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0403", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# YubiKey 4 FIDO+CCID by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0406", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# YubiKey 4 OTP+FIDO+CCID by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0407", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# YubiKey Plus by Yubico AB
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0410", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# U2F Zero by Silicon Laboratories, Inc.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# SoloKeys SoloHacker by pid.codes
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5070", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# SoloKeys SoloBoot by pid.codes
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="50b0", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# SatoshiLabs TREZOR by pid.codes
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# SoloKeys v2 by pid.codes
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="beee", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Google Titan U2F by Google Inc.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# VASCO SecureClick by VASCO Data Security NV
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1a44", ATTRS{idProduct}=="00bb", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# OnlyKey (FIDO2/U2F) by OpenMoko, Inc.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fc", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Neowave Keydo AES by NEOWAVE
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1ae", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Neowave Keydo by NEOWAVE
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Thethis Key by Shenzhen Excelsecu Data Technology Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="f025", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# ExcelSecu FIDO2 Security Key by Shenzhen Excelsecu Data Technology Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="fc25", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# GoTrust Idem Key by NXP Semiconductors
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="f143", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Nitrokey FIDO U2F by Clay Logic
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Nitrokey FIDO2 by Clay Logic
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Nitrokey 3C NFC by Clay Logic
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b2", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Safetech SafeKey by Clay Logic
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b3", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# CanoKey by Clay Logic
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42d4", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# JaCarta U2F by Aladdin Software Security R.D.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0101", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# JaCarta U2F by Aladdin Software Security R.D.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0501", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Happlink Security Key by Plug‐up
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Bluink Key by Bluink Ltd
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2abe", ATTRS{idProduct}=="1002", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Blue by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0000", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano S Old firmware by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano X Old firmware by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0004", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Blue by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0011", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Blue Legacy by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0015", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano S HID+U2F by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="1005", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano S HID+WEBUSB by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="1011", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano S HID+U2F+WEBUSB by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="1015", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano X HID+U2F by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="4005", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano X HID+WEBUSB by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="4011", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano X HID+U2F+WEBUSB by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="4015", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano S+ HID+U2F by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="5005", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano S+ HID+WEBUSB by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="5011", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Nano S+ HID+U2F+WEBUSB by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="5015", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Stax HID+U2F by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="6005", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger Stax HID+WEBUSB by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="6011", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Ledger stax HID+U2F+WEBUSB by LEDGER
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="6015", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Hypersecu HyperFIDO by Hypersecu Information Systems, Inc.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2ccf", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# TrustKey Solutions FIDO2 G310 by eWBM Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a1a", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# TrustKey Solutions FIDO2 G310H/G320H by eWBM Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a2a", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# TrustKey Solutions FIDO2 G320 by eWBM Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4c2a", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# eWBM FIDO2 Goldengate G500 by eWBM Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="5c2f", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# TrustKey Solutions FIDO2 T120 by eWBM Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="a6e9", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# TrustKey Solutions FIDO2 T110 by eWBM Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="a7f9", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# eWBM FIDO2 Goldengate G450 by eWBM Co., Ltd.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="f47c", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Idem Key by GoTrustID Inc.
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="32a3", ATTRS{idProduct}=="3201", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# Longmai mFIDO by Unknown vendor
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="4c4d", ATTRS{idProduct}=="f703", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
# SatoshiLabs TREZOR by SatoshiLabs
|
||||||
|
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660"
|
||||||
|
|
||||||
|
LABEL="fido_end"
|
||||||
8
udev/CMakeLists.txt
Normal file
8
udev/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Copyright (c) 2018 Yubico AB. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
if(UDEV_RULES_DIR)
|
||||||
|
install(FILES 70-u2f.rules DESTINATION ${UDEV_RULES_DIR})
|
||||||
|
endif()
|
||||||
32
udev/check.sh
Normal file
32
udev/check.sh
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/sh -u
|
||||||
|
|
||||||
|
# Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
sort_by_id() {
|
||||||
|
awk '{ printf "%d\n", $3 }' | sort -Cnu
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! grep '^vendor' "$1" | sort_by_id; then
|
||||||
|
echo unsorted vendor section 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VENDORS=$(grep '^vendor' "$1" | awk '{ print $2 }')
|
||||||
|
PRODUCTS=$(grep '^product' "$1" | awk '{ print $2 }' | uniq)
|
||||||
|
|
||||||
|
if [ "${VENDORS}" != "${PRODUCTS}" ]; then
|
||||||
|
echo vendors: "$(echo "${VENDORS}" | tr '\n' ',')" 1>&2
|
||||||
|
echo products: "$(echo "${PRODUCTS}" | tr '\n' ',')" 1>&2
|
||||||
|
echo vendors and products in different order 1>&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
for v in ${VENDORS}; do
|
||||||
|
if ! grep "^product ${v}" "$1" | sort_by_id; then
|
||||||
|
echo "${v}": unsorted product section 1>&2
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
done
|
||||||
137
udev/fidodevs
Normal file
137
udev/fidodevs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
# After modifying this file, regenerate 70-u2f.rules:
|
||||||
|
# ./genrules.awk fidodevs > 70-u2f.rules
|
||||||
|
|
||||||
|
# List of known vendors. Sorted by vendor ID.
|
||||||
|
|
||||||
|
vendor STMICRO 0x0483 STMicroelectronics
|
||||||
|
vendor INFINEON 0x058b Infineon Technologies
|
||||||
|
vendor SYNAPTICS 0x06cb Synaptics Inc.
|
||||||
|
vendor FEITIAN 0x096e Feitian Technologies Co., Ltd.
|
||||||
|
vendor YUBICO 0x1050 Yubico AB
|
||||||
|
vendor SILICON 0x10c4 Silicon Laboratories, Inc.
|
||||||
|
vendor PIDCODES 0x1209 pid.codes
|
||||||
|
vendor GOOGLE 0x18d1 Google Inc.
|
||||||
|
vendor VASCO 0x1a44 VASCO Data Security NV
|
||||||
|
vendor OPENMOKO 0x1d50 OpenMoko, Inc.
|
||||||
|
vendor NEOWAVE 0x1e0d NEOWAVE
|
||||||
|
vendor EXCELSECU 0x1ea8 Shenzhen Excelsecu Data Technology Co., Ltd.
|
||||||
|
vendor NXP 0x1fc9 NXP Semiconductors
|
||||||
|
vendor CLAYLOGIC 0x20a0 Clay Logic
|
||||||
|
vendor ALLADIN 0x24dc Aladdin Software Security R.D.
|
||||||
|
vendor PLUGUP 0x2581 Plug‐up
|
||||||
|
vendor BLUINK 0x2abe Bluink Ltd
|
||||||
|
vendor LEDGER 0x2c97 LEDGER
|
||||||
|
vendor HYPERSECU 0x2ccf Hypersecu Information Systems, Inc.
|
||||||
|
vendor EWBM 0x311f eWBM Co., Ltd.
|
||||||
|
vendor GOTRUST 0x32a3 GoTrustID Inc.
|
||||||
|
vendor UNKNOWN1 0x4c4d Unknown vendor
|
||||||
|
vendor SATOSHI 0x534c SatoshiLabs
|
||||||
|
|
||||||
|
# List of known products. Grouped by vendor; sorted by product ID.
|
||||||
|
|
||||||
|
product STMICRO 0xa2ac ellipticSecure MIRKey
|
||||||
|
product STMICRO 0xa2ca Unknown product
|
||||||
|
product STMICRO 0xcdab Unknown product
|
||||||
|
|
||||||
|
product INFINEON 0x022d Infineon FIDO
|
||||||
|
|
||||||
|
product SYNAPTICS 0x0088 Kensington VeriMark
|
||||||
|
|
||||||
|
product FEITIAN 0x0850 FS ePass FIDO
|
||||||
|
product FEITIAN 0x0852 Unknown product
|
||||||
|
product FEITIAN 0x0853 Unknown product
|
||||||
|
product FEITIAN 0x0854 Unknown product
|
||||||
|
product FEITIAN 0x0856 Unknown product
|
||||||
|
product FEITIAN 0x0858 Unknown product
|
||||||
|
product FEITIAN 0x085a FS MultiPass FIDO U2F
|
||||||
|
product FEITIAN 0x085b Unknown product
|
||||||
|
product FEITIAN 0x085d Unknown product
|
||||||
|
product FEITIAN 0x0866 BioPass FIDO2 K33
|
||||||
|
product FEITIAN 0x0867 BioPass FIDO2 K43
|
||||||
|
product FEITIAN 0x0880 Hypersecu HyperFIDO
|
||||||
|
|
||||||
|
product YUBICO 0x0113 YubiKey NEO FIDO
|
||||||
|
product YUBICO 0x0114 YubiKey NEO OTP+FIDO
|
||||||
|
product YUBICO 0x0115 YubiKey NEO FIDO+CCID
|
||||||
|
product YUBICO 0x0116 YubiKey NEO OTP+FIDO+CCID
|
||||||
|
product YUBICO 0x0120 Security Key by Yubico
|
||||||
|
product YUBICO 0x0121 Unknown product
|
||||||
|
product YUBICO 0x0200 Gnubby U2F
|
||||||
|
product YUBICO 0x0402 YubiKey 4 FIDO
|
||||||
|
product YUBICO 0x0403 YubiKey 4 OTP+FIDO
|
||||||
|
product YUBICO 0x0406 YubiKey 4 FIDO+CCID
|
||||||
|
product YUBICO 0x0407 YubiKey 4 OTP+FIDO+CCID
|
||||||
|
product YUBICO 0x0410 YubiKey Plus
|
||||||
|
|
||||||
|
product SILICON 0x8acf U2F Zero
|
||||||
|
|
||||||
|
product PIDCODES 0x5070 SoloKeys SoloHacker
|
||||||
|
product PIDCODES 0x50b0 SoloKeys SoloBoot
|
||||||
|
product PIDCODES 0x53c1 SatoshiLabs TREZOR
|
||||||
|
product PIDCODES 0xbeee SoloKeys v2
|
||||||
|
|
||||||
|
product GOOGLE 0x5026 Google Titan U2F
|
||||||
|
|
||||||
|
product VASCO 0x00bb VASCO SecureClick
|
||||||
|
|
||||||
|
product OPENMOKO 0x60fc OnlyKey (FIDO2/U2F)
|
||||||
|
|
||||||
|
product NEOWAVE 0xf1ae Neowave Keydo AES
|
||||||
|
product NEOWAVE 0xf1d0 Neowave Keydo
|
||||||
|
|
||||||
|
product EXCELSECU 0xf025 Thethis Key
|
||||||
|
product EXCELSECU 0xfc25 ExcelSecu FIDO2 Security Key
|
||||||
|
|
||||||
|
product NXP 0xf143 GoTrust Idem Key
|
||||||
|
|
||||||
|
product CLAYLOGIC 0x4287 Nitrokey FIDO U2F
|
||||||
|
product CLAYLOGIC 0x42b1 Nitrokey FIDO2
|
||||||
|
product CLAYLOGIC 0x42b2 Nitrokey 3C NFC
|
||||||
|
product CLAYLOGIC 0x42b3 Safetech SafeKey
|
||||||
|
product CLAYLOGIC 0x42d4 CanoKey
|
||||||
|
|
||||||
|
product ALLADIN 0x0101 JaCarta U2F
|
||||||
|
product ALLADIN 0x0501 JaCarta U2F
|
||||||
|
|
||||||
|
product PLUGUP 0xf1d0 Happlink Security Key
|
||||||
|
|
||||||
|
product BLUINK 0x1002 Bluink Key
|
||||||
|
|
||||||
|
product LEDGER 0x0000 Ledger Blue
|
||||||
|
product LEDGER 0x0001 Ledger Nano S Old firmware
|
||||||
|
product LEDGER 0x0004 Ledger Nano X Old firmware
|
||||||
|
product LEDGER 0x0011 Ledger Blue
|
||||||
|
product LEDGER 0x0015 Ledger Blue Legacy
|
||||||
|
product LEDGER 0x1005 Ledger Nano S HID+U2F
|
||||||
|
product LEDGER 0x1011 Ledger Nano S HID+WEBUSB
|
||||||
|
product LEDGER 0x1015 Ledger Nano S HID+U2F+WEBUSB
|
||||||
|
product LEDGER 0x4005 Ledger Nano X HID+U2F
|
||||||
|
product LEDGER 0x4011 Ledger Nano X HID+WEBUSB
|
||||||
|
product LEDGER 0x4015 Ledger Nano X HID+U2F+WEBUSB
|
||||||
|
product LEDGER 0x5005 Ledger Nano S+ HID+U2F
|
||||||
|
product LEDGER 0x5011 Ledger Nano S+ HID+WEBUSB
|
||||||
|
product LEDGER 0x5015 Ledger Nano S+ HID+U2F+WEBUSB
|
||||||
|
product LEDGER 0x6005 Ledger Stax HID+U2F
|
||||||
|
product LEDGER 0x6011 Ledger Stax HID+WEBUSB
|
||||||
|
product LEDGER 0x6015 Ledger stax HID+U2F+WEBUSB
|
||||||
|
|
||||||
|
product HYPERSECU 0x0880 Hypersecu HyperFIDO
|
||||||
|
|
||||||
|
product EWBM 0x4a1a TrustKey Solutions FIDO2 G310
|
||||||
|
product EWBM 0x4a2a TrustKey Solutions FIDO2 G310H/G320H
|
||||||
|
product EWBM 0x4c2a TrustKey Solutions FIDO2 G320
|
||||||
|
product EWBM 0x5c2f eWBM FIDO2 Goldengate G500
|
||||||
|
product EWBM 0xa6e9 TrustKey Solutions FIDO2 T120
|
||||||
|
product EWBM 0xa7f9 TrustKey Solutions FIDO2 T110
|
||||||
|
product EWBM 0xf47c eWBM FIDO2 Goldengate G450
|
||||||
|
|
||||||
|
product GOTRUST 0x3201 Idem Key
|
||||||
|
|
||||||
|
product UNKNOWN1 0xf703 Longmai mFIDO
|
||||||
|
|
||||||
|
product SATOSHI 0x0001 SatoshiLabs TREZOR
|
||||||
79
udev/genrules.awk
Normal file
79
udev/genrules.awk
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/awk -f
|
||||||
|
|
||||||
|
# Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
NR == 1 {
|
||||||
|
print "# Copyright (c) 2020 Yubico AB. All rights reserved."
|
||||||
|
print "#"
|
||||||
|
print "# Redistribution and use in source and binary forms, with or without"
|
||||||
|
print "# modification, are permitted provided that the following conditions are"
|
||||||
|
print "# met:"
|
||||||
|
print "# "
|
||||||
|
print "# 1. Redistributions of source code must retain the above copyright"
|
||||||
|
print "# notice, this list of conditions and the following disclaimer."
|
||||||
|
print "# 2. Redistributions in binary form must reproduce the above copyright"
|
||||||
|
print "# notice, this list of conditions and the following disclaimer in"
|
||||||
|
print "# the documentation and/or other materials provided with the"
|
||||||
|
print "# distribution."
|
||||||
|
print "# "
|
||||||
|
print "# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS"
|
||||||
|
print "# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT"
|
||||||
|
print "# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR"
|
||||||
|
print "# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT"
|
||||||
|
print "# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,"
|
||||||
|
print "# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT"
|
||||||
|
print "# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,"
|
||||||
|
print "# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY"
|
||||||
|
print "# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT"
|
||||||
|
print "# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE"
|
||||||
|
print "# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
print "#"
|
||||||
|
print "# SPDX-License-Identifier: BSD-2-Clause"
|
||||||
|
print ""
|
||||||
|
print "# This file is automatically generated, and should be used with udev 188"
|
||||||
|
print "# or newer."
|
||||||
|
print ""
|
||||||
|
print "ACTION!=\"add|change\", GOTO=\"fido_end\""
|
||||||
|
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
$1 == "vendor" {
|
||||||
|
sub("0x", "", $3)
|
||||||
|
vendors[$2, "id"] = $3
|
||||||
|
|
||||||
|
f = 4
|
||||||
|
while (f <= NF) {
|
||||||
|
vendors[$2, "name"] = vendors[$2, "name"] " " $f
|
||||||
|
f++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$1 == "product" {
|
||||||
|
sub("0x", "", $3)
|
||||||
|
name = ""
|
||||||
|
|
||||||
|
f = 4
|
||||||
|
while (f <= NF) {
|
||||||
|
name = name " " $f
|
||||||
|
f++
|
||||||
|
}
|
||||||
|
|
||||||
|
line = "\n#" name " by" vendors[$2, "name"]"\n"
|
||||||
|
line = line"KERNEL==\"hidraw*\""
|
||||||
|
line = line", SUBSYSTEM==\"hidraw\""
|
||||||
|
line = line", ATTRS{idVendor}==\""vendors[$2, "id"]"\""
|
||||||
|
line = line", ATTRS{idProduct}==\""$3"\""
|
||||||
|
line = line", TAG+=\"uaccess\""
|
||||||
|
line = line", GROUP=\"plugdev\""
|
||||||
|
line = line", MODE=\"0660\""
|
||||||
|
|
||||||
|
print line
|
||||||
|
}
|
||||||
|
|
||||||
|
END {
|
||||||
|
print "\nLABEL=\"fido_end\""
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user