Add files via upload

This commit is contained in:
Token2
2024-05-24 11:45:21 +02:00
committed by GitHub
parent ca68f70495
commit 976966cc30
25 changed files with 5322 additions and 0 deletions

55
tools/CMakeLists.txt Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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 Plugup
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
View 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
View 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
View 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 Plugup
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
View 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\""
}