mirror of
https://github.com/token2/fido2-manage.git
synced 2026-04-09 10:45:39 +00:00
Add files via upload
This commit is contained in:
59
examples/CMakeLists.txt
Normal file
59
examples/CMakeLists.txt
Normal 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
100
examples/README.adoc
Normal 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
349
examples/assert.c
Normal 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
331
examples/cred.c
Normal 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
27
examples/extern.h
Normal 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
382
examples/info.c
Normal 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
42
examples/manifest.c
Normal 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
49
examples/reset.c
Normal 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
49
examples/retries.c
Normal 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
215
examples/select.c
Normal 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
55
examples/setpin.c
Normal 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
444
examples/util.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user