Add files via upload

This commit is contained in:
Token2
2024-05-24 11:47:45 +02:00
committed by GitHub
parent 04bcffc0d2
commit 2b182947ce
46 changed files with 10879 additions and 0 deletions

59
examples/CMakeLists.txt Normal file
View File

@@ -0,0 +1,59 @@
# 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
list(APPEND COMPAT_SOURCES
../openbsd-compat/clock_gettime.c
../openbsd-compat/getopt_long.c
../openbsd-compat/strlcat.c
../openbsd-compat/strlcpy.c
)
if(WIN32 AND BUILD_SHARED_LIBS AND NOT CYGWIN AND NOT MSYS)
list(APPEND COMPAT_SOURCES ../openbsd-compat/posix_win.c)
endif()
# enable -Wconversion -Wsign-conversion
if(NOT MSVC)
set_source_files_properties(assert.c cred.c info.c manifest.c reset.c
retries.c setpin.c util.c PROPERTIES COMPILE_FLAGS
"-Wconversion -Wsign-conversion")
endif()
# manifest
add_executable(manifest manifest.c ${COMPAT_SOURCES})
target_link_libraries(manifest ${_FIDO2_LIBRARY})
# info
add_executable(info info.c ${COMPAT_SOURCES})
target_link_libraries(info ${_FIDO2_LIBRARY})
# reset
add_executable(reset reset.c util.c ${COMPAT_SOURCES})
target_link_libraries(reset ${_FIDO2_LIBRARY})
# cred
add_executable(cred cred.c util.c ${COMPAT_SOURCES})
target_link_libraries(cred ${_FIDO2_LIBRARY})
# assert
add_executable(assert assert.c util.c ${COMPAT_SOURCES})
target_link_libraries(assert ${_FIDO2_LIBRARY})
# setpin
add_executable(setpin setpin.c ${COMPAT_SOURCES})
target_link_libraries(setpin ${_FIDO2_LIBRARY})
# retries
add_executable(retries retries.c ${COMPAT_SOURCES})
target_link_libraries(retries ${_FIDO2_LIBRARY})
# select
add_executable(select select.c ${COMPAT_SOURCES})
target_link_libraries(select ${_FIDO2_LIBRARY})
if(MINGW)
# needed for nanosleep() in mingw
target_link_libraries(select winpthread)
endif()

100
examples/README.adoc Normal file
View File

@@ -0,0 +1,100 @@
= Examples
=== Definitions
The following definitions are used in the description below:
- <device>
The file system path or subsystem-specific identification string of a
FIDO device.
- <pin>, [oldpin]
Strings passed directly in the executed command's argument vector.
- <cred_id>
The file system path of a file containing a FIDO credential ID in
binary representation.
- <pubkey>
The file system path of a file containing a public key in PEM format.
- <blobkey>
A credential's associated CTAP 2.1 "largeBlob" symmetric key.
=== Description
The following examples are provided:
- manifest
Prints a list of configured FIDO devices.
- info <device>
Prints information about <device>.
- reset <device>
Performs a factory reset on <device>.
- setpin <pin> [oldpin] <device>
Configures <pin> as the new PIN of <device>. If [oldpin] is provided,
the device's PIN is changed from [oldpin] to <pin>.
- cred [-t es256|es384|rs256|eddsa] [-k pubkey] [-ei cred_id] [-P pin]
[-T seconds] [-b blobkey] [-hruv] [-c cred_protect] <device>
Creates a new credential on <device> and verify that the credential
was signed by the authenticator. The device's attestation certificate
is not verified. If option -k is specified, the credential's public
key is stored in <pubkey>. If option -i is specified, the credential
ID is stored in <cred_id>. The -e option may be used to add <cred_id>
to the list of excluded credentials. If option -h is specified,
the hmac-secret FIDO2 extension is enabled on the generated
credential. If option -r is specified, the generated credential
will involve a resident key. User verification may be requested
through the -v option. If option -u is specified, the credential
is generated using U2F (CTAP1) instead of FIDO2 (CTAP2) commands.
The -T option may be used to enforce a timeout of <seconds>. If the
option -b is specified, the credential's "largeBlob" key is stored in
<blobkey>. If the option -c is specified the the generated credential
will be bound by the specified protection policy.
- assert [-t es256|es384|rs256|eddsa] [-a cred_id] [-h hmac_secret] [-P pin]
[-s hmac_salt] [-T seconds] [-b blobkey] [-puv] <pubkey> <device>
Asks <device> for a FIDO2 assertion corresponding to [cred_id],
which may be omitted for resident keys. The obtained assertion
is verified using <pubkey>. The -p option requests that the user
be present and checks whether the user presence bit was signed by the
authenticator. The -v option requests user verification and checks
whether the user verification bit was signed by the authenticator.
If option -u is specified, the assertion is generated using
U2F (CTAP1) instead of FIDO2 (CTAP2) commands. If option -s is
specified, a FIDO2 hmac-secret is requested from the authenticator,
and the contents of <hmac_salt> are used as the salt. If option -h
is specified, the resulting hmac-secret is stored in <hmac_secret>.
The -T option may be used to enforce a timeout of <seconds>. If the
option -b specified, the credential's "largeBlob" key is stored in
<blobkey>.
- retries <device>
Get the number of PIN attempts left on <device> before lockout.
- select
Enumerates available FIDO devices and, if more than one is present,
simultaneously requests touch on all of them, printing information
about the device touched.
Debugging is possible through the use of the FIDO_DEBUG environment variable.
If set, libfido2 will produce a log of its transactions with the authenticator.
Additionally, an example of a WebAuthn client using libfido2 is available at
https://github.com/martelletto/fido2-webauthn-client.

349
examples/assert.c Normal file
View File

@@ -0,0 +1,349 @@
/*
* 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 <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 const unsigned char cd[32] = {
0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7,
0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56,
0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52,
0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76,
};
static void
usage(void)
{
fprintf(stderr, "usage: assert [-t es256|es384|rs256|eddsa] "
"[-a cred_id] [-h hmac_secret] [-s hmac_salt] [-P pin] "
"[-T seconds] [-b blobkey] [-puv] <pubkey> <device>\n");
exit(EXIT_FAILURE);
}
static void
verify_assert(int type, const unsigned char *authdata_ptr, size_t authdata_len,
const unsigned char *sig_ptr, size_t sig_len, bool up, bool uv, int ext,
const char *key)
{
fido_assert_t *assert = NULL;
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;
int r;
/* credential pubkey */
switch (type) {
case COSE_ES256:
if ((ec = read_ec_pubkey(key)) == 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);
ec = NULL;
break;
case COSE_ES384:
if ((ec = read_ec_pubkey(key)) == 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);
ec = NULL;
break;
case COSE_RS256:
if ((rsa = read_rsa_pubkey(key)) == 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);
rsa = NULL;
break;
case COSE_EDDSA:
if ((eddsa = read_eddsa_pubkey(key)) == 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);
eddsa = NULL;
break;
default:
errx(1, "unknown credential type %d", type);
}
if ((assert = fido_assert_new()) == NULL)
errx(1, "fido_assert_new");
/* client data hash */
r = fido_assert_set_clientdata(assert, cd, sizeof(cd));
if (r != FIDO_OK)
errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r);
/* relying party */
r = fido_assert_set_rp(assert, "localhost");
if (r != FIDO_OK)
errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
/* authdata */
r = fido_assert_set_count(assert, 1);
if (r != FIDO_OK)
errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r);
r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len);
if (r != FIDO_OK)
errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r);
/* extension */
r = fido_assert_set_extensions(assert, ext);
if (r != FIDO_OK)
errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
r);
/* user presence */
if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
/* user verification */
if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
/* sig */
r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
if (r != FIDO_OK)
errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r);
r = fido_assert_verify(assert, 0, type, pk);
if (r != FIDO_OK)
errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r);
es256_pk_free(&es256_pk);
es384_pk_free(&es384_pk);
rs256_pk_free(&rs256_pk);
eddsa_pk_free(&eddsa_pk);
fido_assert_free(&assert);
}
int
main(int argc, char **argv)
{
bool up = false;
bool uv = false;
bool u2f = false;
fido_dev_t *dev = NULL;
fido_assert_t *assert = NULL;
const char *pin = NULL;
const char *blobkey_out = NULL;
const char *hmac_out = NULL;
unsigned char *body = NULL;
long long ms = 0;
size_t len;
int type = COSE_ES256;
int ext = 0;
int ch;
int r;
if ((assert = fido_assert_new()) == NULL)
errx(1, "fido_assert_new");
while ((ch = getopt(argc, argv, "P:T:a:b:h:ps:t:uv")) != -1) {
switch (ch) {
case 'P':
pin = optarg;
break;
case 'T':
if (base10(optarg, &ms) < 0)
errx(1, "base10: %s", optarg);
if (ms <= 0 || ms > 30)
errx(1, "-T: %s must be in (0,30]", optarg);
ms *= 1000; /* seconds to milliseconds */
break;
case 'a':
if (read_blob(optarg, &body, &len) < 0)
errx(1, "read_blob: %s", optarg);
if ((r = fido_assert_allow_cred(assert, body,
len)) != FIDO_OK)
errx(1, "fido_assert_allow_cred: %s (0x%x)",
fido_strerr(r), r);
free(body);
body = NULL;
break;
case 'b':
ext |= FIDO_EXT_LARGEBLOB_KEY;
blobkey_out = optarg;
break;
case 'h':
hmac_out = optarg;
break;
case 'p':
up = true;
break;
case 's':
ext |= FIDO_EXT_HMAC_SECRET;
if (read_blob(optarg, &body, &len) < 0)
errx(1, "read_blob: %s", optarg);
if ((r = fido_assert_set_hmac_salt(assert, body,
len)) != FIDO_OK)
errx(1, "fido_assert_set_hmac_salt: %s (0x%x)",
fido_strerr(r), r);
free(body);
body = NULL;
break;
case 't':
if (strcmp(optarg, "es256") == 0)
type = COSE_ES256;
else if (strcmp(optarg, "es384") == 0)
type = COSE_ES384;
else if (strcmp(optarg, "rs256") == 0)
type = COSE_RS256;
else if (strcmp(optarg, "eddsa") == 0)
type = COSE_EDDSA;
else
errx(1, "unknown type %s", optarg);
break;
case 'u':
u2f = true;
break;
case 'v':
uv = true;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 2)
usage();
fido_init(0);
if ((dev = fido_dev_new()) == NULL)
errx(1, "fido_dev_new");
r = fido_dev_open(dev, argv[1]);
if (r != FIDO_OK)
errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
if (u2f)
fido_dev_force_u2f(dev);
/* client data hash */
r = fido_assert_set_clientdata(assert, cd, sizeof(cd));
if (r != FIDO_OK)
errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r);
/* relying party */
r = fido_assert_set_rp(assert, "localhost");
if (r != FIDO_OK)
errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
/* extensions */
r = fido_assert_set_extensions(assert, ext);
if (r != FIDO_OK)
errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
r);
/* user presence */
if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
/* user verification */
if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
/* timeout */
if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK)
errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r);
if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) {
fido_dev_cancel(dev);
errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r);
}
r = fido_dev_close(dev);
if (r != FIDO_OK)
errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
fido_dev_free(&dev);
if (fido_assert_count(assert) != 1)
errx(1, "fido_assert_count: %d signatures returned",
(int)fido_assert_count(assert));
/* when verifying, pin implies uv */
if (pin)
uv = true;
verify_assert(type, fido_assert_authdata_ptr(assert, 0),
fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0),
fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]);
if (hmac_out != NULL) {
/* extract the hmac secret */
if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0),
fido_assert_hmac_secret_len(assert, 0)) < 0)
errx(1, "write_blob");
}
if (blobkey_out != NULL) {
/* extract the hmac secret */
if (write_blob(blobkey_out,
fido_assert_largeblob_key_ptr(assert, 0),
fido_assert_largeblob_key_len(assert, 0)) < 0)
errx(1, "write_blob");
}
fido_assert_free(&assert);
exit(0);
}

331
examples/cred.c Normal file
View File

@@ -0,0 +1,331 @@
/*
* 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 <errno.h>
#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 const unsigned char cd[32] = {
0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb,
0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26,
0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31,
0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b,
};
static const unsigned char user_id[32] = {
0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63,
0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2,
0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5,
0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49,
};
static void
usage(void)
{
fprintf(stderr, "usage: cred [-t es256|es384|rs256|eddsa] [-k pubkey] "
"[-ei cred_id] [-P pin] [-T seconds] [-b blobkey] [-c cred_protect] [-hruv] "
"<device>\n");
exit(EXIT_FAILURE);
}
static void
verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr,
size_t authdata_len, const unsigned char *attstmt_ptr, size_t attstmt_len,
bool rk, bool uv, int ext, int cred_protect, const char *key_out,
const char *id_out)
{
fido_cred_t *cred;
int r;
if ((cred = fido_cred_new()) == NULL)
errx(1, "fido_cred_new");
/* type */
r = fido_cred_set_type(cred, type);
if (r != FIDO_OK)
errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r);
/* client data */
r = fido_cred_set_clientdata(cred, cd, sizeof(cd));
if (r != FIDO_OK)
errx(1, "fido_cred_set_clientdata: %s (0x%x)", fido_strerr(r), r);
/* relying party */
r = fido_cred_set_rp(cred, "localhost", "sweet home localhost");
if (r != FIDO_OK)
errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r);
/* authdata */
r = fido_cred_set_authdata(cred, authdata_ptr, authdata_len);
if (r != FIDO_OK)
errx(1, "fido_cred_set_authdata: %s (0x%x)", fido_strerr(r), r);
/* extensions */
r = fido_cred_set_extensions(cred, ext);
if (r != FIDO_OK)
errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r);
/* resident key */
if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r);
/* user verification */
if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r);
/* credProt */
if (cred_protect != 0 && (r = fido_cred_set_prot(cred,
cred_protect)) != FIDO_OK)
errx(1, "fido_cred_set_prot: %s (0x%x)", fido_strerr(r), r);
/* fmt */
r = fido_cred_set_fmt(cred, fmt);
if (r != FIDO_OK)
errx(1, "fido_cred_set_fmt: %s (0x%x)", fido_strerr(r), r);
if (!strcmp(fido_cred_fmt(cred), "none")) {
warnx("no attestation data, skipping credential verification");
goto out;
}
/* attestation statement */
r = fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len);
if (r != FIDO_OK)
errx(1, "fido_cred_set_attstmt: %s (0x%x)", fido_strerr(r), r);
r = fido_cred_verify(cred);
if (r != FIDO_OK)
errx(1, "fido_cred_verify: %s (0x%x)", fido_strerr(r), r);
out:
if (key_out != NULL) {
/* extract the credential pubkey */
if (type == COSE_ES256) {
if (write_es256_pubkey(key_out,
fido_cred_pubkey_ptr(cred),
fido_cred_pubkey_len(cred)) < 0)
errx(1, "write_es256_pubkey");
} else if (type == COSE_ES384) {
if (write_es384_pubkey(key_out,
fido_cred_pubkey_ptr(cred),
fido_cred_pubkey_len(cred)) < 0)
errx(1, "write_es384_pubkey");
} else if (type == COSE_RS256) {
if (write_rs256_pubkey(key_out,
fido_cred_pubkey_ptr(cred),
fido_cred_pubkey_len(cred)) < 0)
errx(1, "write_rs256_pubkey");
} else if (type == COSE_EDDSA) {
if (write_eddsa_pubkey(key_out,
fido_cred_pubkey_ptr(cred),
fido_cred_pubkey_len(cred)) < 0)
errx(1, "write_eddsa_pubkey");
}
}
if (id_out != NULL) {
/* extract the credential id */
if (write_blob(id_out, fido_cred_id_ptr(cred),
fido_cred_id_len(cred)) < 0)
errx(1, "write_blob");
}
fido_cred_free(&cred);
}
int
main(int argc, char **argv)
{
bool rk = false;
bool uv = false;
bool u2f = false;
fido_dev_t *dev;
fido_cred_t *cred = NULL;
const char *pin = NULL;
const char *blobkey_out = NULL;
const char *key_out = NULL;
const char *id_out = NULL;
unsigned char *body = NULL;
long long ms = 0;
size_t len;
int type = COSE_ES256;
int ext = 0;
int ch;
int r;
long long cred_protect = 0;
if ((cred = fido_cred_new()) == NULL)
errx(1, "fido_cred_new");
while ((ch = getopt(argc, argv, "P:T:b:e:hi:k:rt:uvc:")) != -1) {
switch (ch) {
case 'P':
pin = optarg;
break;
case 'T':
if (base10(optarg, &ms) < 0)
errx(1, "base10: %s", optarg);
if (ms <= 0 || ms > 30)
errx(1, "-T: %s must be in (0,30]", optarg);
ms *= 1000; /* seconds to milliseconds */
break;
case 'b':
ext |= FIDO_EXT_LARGEBLOB_KEY;
blobkey_out = optarg;
break;
case 'e':
if (read_blob(optarg, &body, &len) < 0)
errx(1, "read_blob: %s", optarg);
r = fido_cred_exclude(cred, body, len);
if (r != FIDO_OK)
errx(1, "fido_cred_exclude: %s (0x%x)",
fido_strerr(r), r);
free(body);
body = NULL;
break;
case 'h':
ext |= FIDO_EXT_HMAC_SECRET;
break;
case 'c':
if (base10(optarg, &cred_protect) < 0)
errx(1, "base10: %s", optarg);
if (cred_protect <= 0 || cred_protect > 3)
errx(1, "-c: %s must be in (1,3)", optarg);
ext |= FIDO_EXT_CRED_PROTECT;
break;
case 'i':
id_out = optarg;
break;
case 'k':
key_out = optarg;
break;
case 'r':
rk = true;
break;
case 't':
if (strcmp(optarg, "es256") == 0)
type = COSE_ES256;
else if (strcmp(optarg, "es384") == 0)
type = COSE_ES384;
else if (strcmp(optarg, "rs256") == 0)
type = COSE_RS256;
else if (strcmp(optarg, "eddsa") == 0)
type = COSE_EDDSA;
else
errx(1, "unknown type %s", optarg);
break;
case 'u':
u2f = true;
break;
case 'v':
uv = true;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
fido_init(0);
if ((dev = fido_dev_new()) == NULL)
errx(1, "fido_dev_new");
r = fido_dev_open(dev, argv[0]);
if (r != FIDO_OK)
errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
if (u2f)
fido_dev_force_u2f(dev);
/* type */
r = fido_cred_set_type(cred, type);
if (r != FIDO_OK)
errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r);
/* client data */
r = fido_cred_set_clientdata(cred, cd, sizeof(cd));
if (r != FIDO_OK)
errx(1, "fido_cred_set_clientdata: %s (0x%x)", fido_strerr(r), r);
/* relying party */
r = fido_cred_set_rp(cred, "localhost", "sweet home localhost");
if (r != FIDO_OK)
errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r);
/* user */
r = fido_cred_set_user(cred, user_id, sizeof(user_id), "john smith",
"jsmith", NULL);
if (r != FIDO_OK)
errx(1, "fido_cred_set_user: %s (0x%x)", fido_strerr(r), r);
/* extensions */
r = fido_cred_set_extensions(cred, ext);
if (r != FIDO_OK)
errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r);
/* resident key */
if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r);
/* user verification */
if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r);
/* credProt */
if (cred_protect != 0 && (r = fido_cred_set_prot(cred,
(int)cred_protect)) != FIDO_OK)
errx(1, "fido_cred_set_prot: %s (0x%x)", fido_strerr(r), r);
/* timeout */
if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK)
errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r);
if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) {
fido_dev_cancel(dev);
errx(1, "fido_makecred: %s (0x%x)", fido_strerr(r), r);
}
r = fido_dev_close(dev);
if (r != FIDO_OK)
errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
fido_dev_free(&dev);
/* when verifying, pin implies uv */
if (pin)
uv = true;
verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred),
fido_cred_authdata_len(cred), fido_cred_attstmt_ptr(cred),
fido_cred_attstmt_len(cred), rk, uv, ext, fido_cred_prot(cred),
key_out, id_out);
if (blobkey_out != NULL) {
/* extract the "largeBlob" key */
if (write_blob(blobkey_out, fido_cred_largeblob_key_ptr(cred),
fido_cred_largeblob_key_len(cred)) < 0)
errx(1, "write_blob");
}
fido_cred_free(&cred);
exit(0);
}

27
examples/extern.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* 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
*/
#ifndef _EXTERN_H_
#define _EXTERN_H_
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
/* util.c */
EC_KEY *read_ec_pubkey(const char *);
RSA *read_rsa_pubkey(const char *);
EVP_PKEY *read_eddsa_pubkey(const char *);
int base10(const char *, long long *);
int read_blob(const char *, unsigned char **, size_t *);
int write_blob(const char *, const unsigned char *, size_t);
int write_es256_pubkey(const char *, const void *, size_t);
int write_es384_pubkey(const char *, const void *, size_t);
int write_rs256_pubkey(const char *, const void *, size_t);
int write_eddsa_pubkey(const char *, const void *, size_t);
#endif /* _EXTERN_H_ */

382
examples/info.c Normal file
View File

@@ -0,0 +1,382 @@
/*
* 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../openbsd-compat/openbsd-compat.h"
/*
* Pretty-print a device's capabilities flags and return the result.
*/
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);
}
/*
* Print a FIDO device's attributes on stdout.
*/
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);
}
/*
* Auxiliary function to print an array of strings on stdout.
*/
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");
}
/*
* Auxiliary function to print (char *, bool) pairs on stdout.
*/
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");
}
/*
* Auxiliary function to print (char *, uint64_t) pairs on stdout.
*/
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");
}
/*
* Auxiliary function to print a list of supported COSE algorithms on stdout.
*/
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");
}
/*
* Auxiliary function to print an authenticator's AAGUID on stdout.
*/
static void
print_aaguid(const unsigned char *buf, size_t buflen)
{
printf("aaguid: ");
while (buflen--)
printf("%02x", *buf++);
printf("\n");
}
/*
* Auxiliary function to print an authenticator's maximum message size on
* stdout.
*/
static void
print_maxmsgsiz(uint64_t maxmsgsiz)
{
printf("maxmsgsiz: %d\n", (int)maxmsgsiz);
}
/*
* Auxiliary function to print an authenticator's maximum number of credentials
* in a credential list on stdout.
*/
static void
print_maxcredcntlst(uint64_t maxcredcntlst)
{
printf("maxcredcntlst: %d\n", (int)maxcredcntlst);
}
/*
* Auxiliary function to print an authenticator's maximum credential ID length
* on stdout.
*/
static void
print_maxcredidlen(uint64_t maxcredidlen)
{
printf("maxcredlen: %d\n", (int)maxcredidlen);
}
/*
* Auxiliary function to print the maximum size of an authenticator's
* serialized largeBlob array.
*/
static void
print_maxlargeblob(uint64_t maxlargeblob)
{
printf("maxlargeblob: %d\n", (int)maxlargeblob);
}
/*
* Auxiliary function to print the authenticator's estimated number of
* remaining resident credentials.
*/
static void
print_rk_remaining(int64_t rk_remaining)
{
printf("remaining rk(s): ");
if (rk_remaining == -1)
printf("undefined\n");
else
printf("%d\n", (int)rk_remaining);
}
/*
* Auxiliary function to print the minimum pin length observed by the
* authenticator.
*/
static void
print_minpinlen(uint64_t minpinlen)
{
printf("minpinlen: %d\n", (int)minpinlen);
}
/*
* Auxiliary function to print the authenticator's preferred (platform)
* UV attempts.
*/
static void
print_uv_attempts(uint64_t uv_attempts)
{
printf("platform uv attempt(s): %d\n", (int)uv_attempts);
}
/*
* Auxiliary function to print an authenticator's firmware version on stdout.
*/
static void
print_fwversion(uint64_t fwversion)
{
printf("fwversion: 0x%x\n", (int)fwversion);
}
/*
* Auxiliary function to print an array of bytes on stdout.
*/
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");
}
static void
getinfo(const char *path)
{
fido_dev_t *dev;
fido_cbor_info_t *ci;
int r;
fido_init(0);
if ((dev = fido_dev_new()) == NULL)
errx(1, "fido_dev_new");
if ((r = fido_dev_open(dev, path)) != FIDO_OK)
errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
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 largeBlob array */
print_maxlargeblob(fido_cbor_info_maxlargeblob(ci));
/* print number of remaining 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));
/* print whether a new pin is required */
printf("pin change required: %s\n",
fido_cbor_info_new_pin_required(ci) ? "true" : "false");
/* print platform uv attempts */
print_uv_attempts(fido_cbor_info_uv_attempts(ci));
fido_cbor_info_free(&ci);
end:
if ((r = fido_dev_close(dev)) != FIDO_OK)
errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
fido_dev_free(&dev);
}
int
main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "usage: info <device>\n");
exit(EXIT_FAILURE);
}
getinfo(argv[1]);
exit(0);
}

42
examples/manifest.c Normal file
View File

@@ -0,0 +1,42 @@
/*
* 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"
int
main(void)
{
fido_dev_info_t *devlist;
size_t ndevs;
int r;
fido_init(0);
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);
}

49
examples/reset.c Normal file
View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2018-2021 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
*/
/*
* Perform a factory reset on a given authenticator.
*/
#include <fido.h>
#include <stdio.h>
#include <stdlib.h>
#include "../openbsd-compat/openbsd-compat.h"
#include "extern.h"
int
main(int argc, char **argv)
{
fido_dev_t *dev;
int r;
if (argc != 2) {
fprintf(stderr, "usage: reset <device>\n");
exit(EXIT_FAILURE);
}
fido_init(0);
if ((dev = fido_dev_new()) == NULL)
errx(1, "fido_dev_new");
if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK)
errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
if ((r = fido_dev_reset(dev)) != FIDO_OK) {
fido_dev_cancel(dev);
errx(1, "fido_dev_reset: %s (0x%x)", fido_strerr(r), r);
}
if ((r = fido_dev_close(dev)) != FIDO_OK)
errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
fido_dev_free(&dev);
exit(0);
}

49
examples/retries.c Normal file
View File

@@ -0,0 +1,49 @@
/*
* 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
*/
/*
* Get an authenticator's number of PIN attempts left.
*/
#include <fido.h>
#include <stdio.h>
#include <stdlib.h>
#include "../openbsd-compat/openbsd-compat.h"
int
main(int argc, char **argv)
{
fido_dev_t *dev;
int n;
int r;
if (argc != 2) {
fprintf(stderr, "usage: retries <device>\n");
exit(EXIT_FAILURE);
}
fido_init(0);
if ((dev = fido_dev_new()) == NULL)
errx(1, "fido_dev_new");
if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK)
errx(1, "fido_open: %s (0x%x)", fido_strerr(r), r);
if ((r = fido_dev_get_retry_count(dev, &n)) != FIDO_OK)
errx(1, "fido_dev_get_retry_count: %s (0x%x)", fido_strerr(r), r);
if ((r = fido_dev_close(dev)) != FIDO_OK)
errx(1, "fido_close: %s (0x%x)", fido_strerr(r), r);
fido_dev_free(&dev);
printf("%d\n", n);
exit(0);
}

215
examples/select.c Normal file
View File

@@ -0,0 +1,215 @@
/*
* 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 <errno.h>
#include <fido.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "../openbsd-compat/openbsd-compat.h"
#define FIDO_POLL_MS 50
#if defined(_MSC_VER)
static int
nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
if (rmtp != NULL) {
errno = EINVAL;
return (-1);
}
Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000));
return (0);
}
#endif
static fido_dev_t *
open_dev(const fido_dev_info_t *di)
{
fido_dev_t *dev;
int r;
if ((dev = fido_dev_new()) == NULL) {
warnx("%s: fido_dev_new", __func__);
return (NULL);
}
if ((r = fido_dev_open(dev, fido_dev_info_path(di))) != FIDO_OK) {
warnx("%s: fido_dev_open %s: %s", __func__,
fido_dev_info_path(di), fido_strerr(r));
fido_dev_free(&dev);
return (NULL);
}
printf("%s (0x%04x:0x%04x) is %s\n", fido_dev_info_path(di),
fido_dev_info_vendor(di), fido_dev_info_product(di),
fido_dev_is_fido2(dev) ? "fido2" : "u2f");
return (dev);
}
static int
select_dev(const fido_dev_info_t *devlist, size_t ndevs, fido_dev_t **dev,
size_t *idx, int secs)
{
const fido_dev_info_t *di;
fido_dev_t **devtab;
struct timespec ts_start;
struct timespec ts_now;
struct timespec ts_delta;
struct timespec ts_pause;
size_t nopen = 0;
int touched;
int r;
long ms_remain;
*dev = NULL;
*idx = 0;
printf("%u authenticator(s) detected\n", (unsigned)ndevs);
if (ndevs == 0)
return (0); /* nothing to do */
if ((devtab = calloc(ndevs, sizeof(*devtab))) == NULL) {
warn("%s: calloc", __func__);
return (-1);
}
for (size_t i = 0; i < ndevs; i++) {
di = fido_dev_info_ptr(devlist, i);
if ((devtab[i] = open_dev(di)) != NULL) {
*idx = i;
nopen++;
}
}
printf("%u authenticator(s) opened\n", (unsigned)nopen);
if (nopen < 2) {
if (nopen == 1)
*dev = devtab[*idx]; /* single candidate */
r = 0;
goto out;
}
for (size_t i = 0; i < ndevs; i++) {
di = fido_dev_info_ptr(devlist, i);
if (devtab[i] == NULL)
continue; /* failed to open */
if ((r = fido_dev_get_touch_begin(devtab[i])) != FIDO_OK) {
warnx("%s: fido_dev_get_touch_begin %s: %s", __func__,
fido_dev_info_path(di), fido_strerr(r));
r = -1;
goto out;
}
}
if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) {
warn("%s: clock_gettime", __func__);
r = -1;
goto out;
}
ts_pause.tv_sec = 0;
ts_pause.tv_nsec = 200000000; /* 200ms */
do {
nanosleep(&ts_pause, NULL);
for (size_t i = 0; i < ndevs; i++) {
di = fido_dev_info_ptr(devlist, i);
if (devtab[i] == NULL) {
/* failed to open or discarded */
continue;
}
if ((r = fido_dev_get_touch_status(devtab[i], &touched,
FIDO_POLL_MS)) != FIDO_OK) {
warnx("%s: fido_dev_get_touch_status %s: %s",
__func__, fido_dev_info_path(di),
fido_strerr(r));
fido_dev_close(devtab[i]);
fido_dev_free(&devtab[i]);
continue; /* discard */
}
if (touched) {
*dev = devtab[i];
*idx = i;
r = 0;
goto out;
}
}
if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) {
warn("%s: clock_gettime", __func__);
r = -1;
goto out;
}
timespecsub(&ts_now, &ts_start, &ts_delta);
ms_remain = (secs * 1000) - ((long)ts_delta.tv_sec * 1000) +
((long)ts_delta.tv_nsec / 1000000);
} while (ms_remain > FIDO_POLL_MS);
printf("timeout after %d seconds\n", secs);
r = -1;
out:
if (r != 0) {
*dev = NULL;
*idx = 0;
}
for (size_t i = 0; i < ndevs; i++) {
if (devtab[i] && devtab[i] != *dev) {
fido_dev_cancel(devtab[i]);
fido_dev_close(devtab[i]);
fido_dev_free(&devtab[i]);
}
}
free(devtab);
return (r);
}
int
main(void)
{
const fido_dev_info_t *di;
fido_dev_info_t *devlist;
fido_dev_t *dev;
size_t idx;
size_t ndevs;
int r;
fido_init(0);
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);
if (select_dev(devlist, ndevs, &dev, &idx, 15) != 0)
errx(1, "select_dev");
if (dev == NULL)
errx(1, "no authenticator found");
di = fido_dev_info_ptr(devlist, idx);
printf("%s: %s by %s (PIN %sset)\n", fido_dev_info_path(di),
fido_dev_info_product_string(di),
fido_dev_info_manufacturer_string(di),
fido_dev_has_pin(dev) ? "" : "un");
fido_dev_close(dev);
fido_dev_free(&dev);
fido_dev_info_free(&devlist, ndevs);
exit(0);
}

55
examples/setpin.c Normal file
View File

@@ -0,0 +1,55 @@
/*
* 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
*/
/*
* Configure a PIN on a given authenticator.
*/
#include <fido.h>
#include <stdio.h>
#include <stdlib.h>
#include "../openbsd-compat/openbsd-compat.h"
static void
setpin(const char *path, const char *pin, const char *oldpin)
{
fido_dev_t *dev;
int r;
fido_init(0);
if ((dev = fido_dev_new()) == NULL)
errx(1, "fido_dev_new");
if ((r = fido_dev_open(dev, path)) != FIDO_OK)
errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
if ((r = fido_dev_set_pin(dev, pin, oldpin)) != FIDO_OK)
errx(1, "fido_dev_set_pin: %s (0x%x)", fido_strerr(r), r);
if ((r = fido_dev_close(dev)) != FIDO_OK)
errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
fido_dev_free(&dev);
}
int
main(int argc, char **argv)
{
if (argc < 3 || argc > 4) {
fprintf(stderr, "usage: setpin <pin> [oldpin] <device>\n");
exit(EXIT_FAILURE);
}
if (argc == 3)
setpin(argv[2], argv[1], NULL);
else
setpin(argv[3], argv[1], argv[2]);
exit(0);
}

444
examples/util.c Normal file
View File

@@ -0,0 +1,444 @@
/*
* 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 <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef _MSC_VER
#include "../openbsd-compat/posix_win.h"
#endif
#include "../openbsd-compat/openbsd-compat.h"
#include "extern.h"
int
base10(const char *str, long long *ll)
{
char *ep;
*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);
return (0);
}
int
write_blob(const char *path, const unsigned char *ptr, size_t len)
{
int fd, ok = -1;
ssize_t n;
if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) {
warn("open %s", path);
goto fail;
}
if ((n = write(fd, ptr, len)) < 0) {
warn("write");
goto fail;
}
if ((size_t)n != len) {
warnx("write");
goto fail;
}
ok = 0;
fail:
if (fd != -1) {
close(fd);
}
return (ok);
}
int
read_blob(const char *path, unsigned 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("open %s", path);
goto fail;
}
if (fstat(fd, &st) < 0) {
warn("stat %s", path);
goto fail;
}
if (st.st_size < 0) {
warnx("stat %s: invalid size", path);
goto fail;
}
*len = (size_t)st.st_size;
if ((*ptr = malloc(*len)) == NULL) {
warn("malloc");
goto fail;
}
if ((n = read(fd, *ptr, *len)) < 0) {
warn("read");
goto fail;
}
if ((size_t)n != *len) {
warnx("read");
goto fail;
}
ok = 0;
fail:
if (fd != -1) {
close(fd);
}
if (ok < 0) {
free(*ptr);
*ptr = NULL;
*len = 0;
}
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 != NULL) {
fclose(fp);
}
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
return (ec);
}
int
write_es256_pubkey(const char *path, const void *ptr, size_t len)
{
FILE *fp = NULL;
EVP_PKEY *pkey = NULL;
es256_pk_t *pk = NULL;
int fd = -1;
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 ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
warn("open %s", path);
goto fail;
}
if ((fp = fdopen(fd, "w")) == NULL) {
warn("fdopen");
goto fail;
}
fd = -1; /* owned by fp now */
if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
warnx("es256_pk_to_EVP_PKEY");
goto fail;
}
if (PEM_write_PUBKEY(fp, pkey) == 0) {
warnx("PEM_write_PUBKEY");
goto fail;
}
ok = 0;
fail:
es256_pk_free(&pk);
if (fp != NULL) {
fclose(fp);
}
if (fd != -1) {
close(fd);
}
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
return (ok);
}
int
write_es384_pubkey(const char *path, const void *ptr, size_t len)
{
FILE *fp = NULL;
EVP_PKEY *pkey = NULL;
es384_pk_t *pk = NULL;
int fd = -1;
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 ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
warn("open %s", path);
goto fail;
}
if ((fp = fdopen(fd, "w")) == NULL) {
warn("fdopen");
goto fail;
}
fd = -1; /* owned by fp now */
if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) {
warnx("es384_pk_to_EVP_PKEY");
goto fail;
}
if (PEM_write_PUBKEY(fp, pkey) == 0) {
warnx("PEM_write_PUBKEY");
goto fail;
}
ok = 0;
fail:
es384_pk_free(&pk);
if (fp != NULL) {
fclose(fp);
}
if (fd != -1) {
close(fd);
}
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 != NULL) {
fclose(fp);
}
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
return (rsa);
}
int
write_rs256_pubkey(const char *path, const void *ptr, size_t len)
{
FILE *fp = NULL;
EVP_PKEY *pkey = NULL;
rs256_pk_t *pk = NULL;
int fd = -1;
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 ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
warn("open %s", path);
goto fail;
}
if ((fp = fdopen(fd, "w")) == NULL) {
warn("fdopen");
goto fail;
}
fd = -1; /* owned by fp now */
if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
warnx("rs256_pk_to_EVP_PKEY");
goto fail;
}
if (PEM_write_PUBKEY(fp, pkey) == 0) {
warnx("PEM_write_PUBKEY");
goto fail;
}
ok = 0;
fail:
rs256_pk_free(&pk);
if (fp != NULL) {
fclose(fp);
}
if (fd != -1) {
close(fd);
}
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(const char *path, const void *ptr, size_t len)
{
FILE *fp = NULL;
EVP_PKEY *pkey = NULL;
eddsa_pk_t *pk = NULL;
int fd = -1;
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 ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
warn("open %s", path);
goto fail;
}
if ((fp = fdopen(fd, "w")) == NULL) {
warn("fdopen");
goto fail;
}
fd = -1; /* owned by fp now */
if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
warnx("eddsa_pk_to_EVP_PKEY");
goto fail;
}
if (PEM_write_PUBKEY(fp, pkey) == 0) {
warnx("PEM_write_PUBKEY");
goto fail;
}
ok = 0;
fail:
eddsa_pk_free(&pk);
if (fp != NULL) {
fclose(fp);
}
if (fd != -1) {
close(fd);
}
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
return (ok);
}