Merge conflicts between libfido2-1.8.0 and libfido2-1.13.0

This commit is contained in:
christos 2023-08-11 23:02:08 +00:00
parent 2d40c4512a
commit 0b4509d2c9
7 changed files with 449 additions and 462 deletions

View File

@ -1,124 +0,0 @@
/* $OpenBSD: hkdf.c,v 1.4 2019/11/21 20:02:20 tim Exp $ */
/* Copyright (c) 2014, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "openbsd-compat.h"
#include "fido.h"
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#include <assert.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#define CRYPTOerror(r) CRYPTOerr(ERR_LIB_CRYPTO, (r))
/* https://tools.ietf.org/html/rfc5869#section-2 */
int
HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
const uint8_t *secret, size_t secret_len, const uint8_t *salt,
size_t salt_len, const uint8_t *info, size_t info_len)
{
uint8_t prk[EVP_MAX_MD_SIZE];
size_t prk_len;
if (!HKDF_extract(prk, &prk_len, digest, secret, secret_len, salt,
salt_len))
return 0;
if (!HKDF_expand(out_key, out_len, digest, prk, prk_len, info,
info_len))
return 0;
return 1;
}
/* https://tools.ietf.org/html/rfc5869#section-2.2 */
int
HKDF_extract(uint8_t *out_key, size_t *out_len,
const EVP_MD *digest, const uint8_t *secret, size_t secret_len,
const uint8_t *salt, size_t salt_len)
{
unsigned int len;
/*
* If salt is not given, HashLength zeros are used. However, HMAC does
* that internally already so we can ignore it.
*/
if (salt_len > INT_MAX || HMAC(digest, salt, (int)salt_len, secret,
secret_len, out_key, &len) == NULL) {
CRYPTOerror(ERR_R_CRYPTO_LIB);
return 0;
}
*out_len = len;
return 1;
}
/* https://tools.ietf.org/html/rfc5869#section-2.3 */
int
HKDF_expand(uint8_t *out_key, size_t out_len,
const EVP_MD *digest, const uint8_t *prk, size_t prk_len,
const uint8_t *info, size_t info_len)
{
const size_t digest_len = EVP_MD_size(digest);
uint8_t previous[EVP_MAX_MD_SIZE];
size_t n, done = 0;
unsigned int i;
int ret = 0;
HMAC_CTX hmac;
/* Expand key material to desired length. */
n = (out_len + digest_len - 1) / digest_len;
if (out_len + digest_len < out_len || n > 255 || prk_len > INT_MAX) {
CRYPTOerror(EVP_R_TOO_LARGE);
return 0;
}
HMAC_CTX_init(&hmac);
if (!HMAC_Init_ex(&hmac, prk, (int)prk_len, digest, NULL))
goto out;
for (i = 0; i < n; i++) {
uint8_t ctr = i + 1;
size_t todo;
if (i != 0 && (!HMAC_Init_ex(&hmac, NULL, 0, NULL, NULL) ||
!HMAC_Update(&hmac, previous, digest_len)))
goto out;
if (!HMAC_Update(&hmac, info, info_len) ||
!HMAC_Update(&hmac, &ctr, 1) ||
!HMAC_Final(&hmac, previous, NULL))
goto out;
todo = digest_len;
if (done + todo > out_len)
todo = out_len - done;
memcpy(out_key + done, previous, todo);
done += todo;
}
ret = 1;
out:
HMAC_CTX_cleanup(&hmac);
explicit_bzero(previous, sizeof(previous));
if (ret != 1)
CRYPTOerror(ERR_R_CRYPTO_LIB);
return ret;
}
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */

View File

@ -1,65 +0,0 @@
/* $OpenBSD: hkdf.h,v 1.2 2018/04/03 13:33:53 tb Exp $ */
/* Copyright (c) 2014, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef OPENSSL_HEADER_HKDF_H
#define OPENSSL_HEADER_HKDF_H
#include <openssl/evp.h>
#if defined(__cplusplus)
extern "C" {
#endif
/*
* HKDF computes HKDF (as specified by RFC 5869) of initial keying
* material |secret| with |salt| and |info| using |digest|, and
* outputs |out_len| bytes to |out_key|. It returns one on success and
* zero on error.
*
* HKDF is an Extract-and-Expand algorithm. It does not do any key
* stretching, and as such, is not suited to be used alone to generate
* a key from a password.
*/
int HKDF(uint8_t *out_key, size_t out_len, const struct env_md_st *digest,
const uint8_t *secret, size_t secret_len, const uint8_t *salt,
size_t salt_len, const uint8_t *info, size_t info_len);
/*
* HKDF_extract computes a HKDF PRK (as specified by RFC 5869) from
* initial keying material |secret| and salt |salt| using |digest|,
* and outputs |out_len| bytes to |out_key|. The maximum output size
* is |EVP_MAX_MD_SIZE|. It returns one on success and zero on error.
*/
int HKDF_extract(uint8_t *out_key, size_t *out_len,
const struct env_md_st *digest, const uint8_t *secret,
size_t secret_len, const uint8_t *salt, size_t salt_len);
/*
* HKDF_expand computes a HKDF OKM (as specified by RFC 5869) of
* length |out_len| from the PRK |prk| and info |info| using |digest|,
* and outputs the result to |out_key|. It returns one on success and
* zero on error.
*/
int HKDF_expand(uint8_t *out_key, size_t out_len,
const EVP_MD *digest, const uint8_t *prk, size_t prk_len,
const uint8_t *info, size_t info_len);
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_HKDF_H */

View File

@ -1,10 +1,10 @@
/*
* Copyright (c) 2018-2021 Yubico AB. All rights reserved.
* 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 <openssl/ecdsa.h>
#include <openssl/sha.h>
#include "fido.h"
@ -79,7 +79,7 @@ parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
static int
fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin)
const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms)
{
fido_blob_t f;
fido_opt_t uv = assert->uv;
@ -127,7 +127,7 @@ fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
if (pin != NULL || (uv == FIDO_OPT_TRUE &&
fido_dev_supports_permissions(dev))) {
if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh,
pin, assert->rp_id, &argv[5], &argv[6])) != FIDO_OK) {
pin, assert->rp_id, &argv[5], &argv[6], ms)) != FIDO_OK) {
fido_log_debug("%s: cbor_add_uv_params", __func__);
goto fail;
}
@ -144,7 +144,7 @@ fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
/* frame and transmit */
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -159,52 +159,61 @@ fail:
}
static int
fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
int r;
unsigned char *msg;
int msglen;
int r;
fido_assert_reset_rx(assert);
if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
ms)) < 0) {
if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
r = FIDO_ERR_INTERNAL;
goto out;
}
if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
fido_log_debug("%s: fido_rx", __func__);
return (FIDO_ERR_RX);
r = FIDO_ERR_RX;
goto out;
}
/* start with room for a single assertion */
if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL)
return (FIDO_ERR_INTERNAL);
if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) {
r = FIDO_ERR_INTERNAL;
goto out;
}
assert->stmt_len = 0;
assert->stmt_cnt = 1;
/* adjust as needed */
if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert,
if ((r = cbor_parse_reply(msg, (size_t)msglen, assert,
adjust_assert_count)) != FIDO_OK) {
fido_log_debug("%s: adjust_assert_count", __func__);
return (r);
goto out;
}
/* parse the first assertion */
if ((r = cbor_parse_reply(reply, (size_t)reply_len,
&assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) {
if ((r = cbor_parse_reply(msg, (size_t)msglen, &assert->stmt[0],
parse_assert_reply)) != FIDO_OK) {
fido_log_debug("%s: parse_assert_reply", __func__);
return (r);
goto out;
}
assert->stmt_len = 1;
assert->stmt_len++;
r = FIDO_OK;
out:
freezero(msg, FIDO_MAXMSG);
return (FIDO_OK);
return (r);
}
static int
fido_get_next_assert_tx(fido_dev_t *dev)
fido_get_next_assert_tx(fido_dev_t *dev, int *ms)
{
const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT };
if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) {
if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
return (FIDO_ERR_TX);
}
@ -213,46 +222,57 @@ fido_get_next_assert_tx(fido_dev_t *dev)
}
static int
fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
int r;
unsigned char *msg;
int msglen;
int r;
if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
ms)) < 0) {
if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
r = FIDO_ERR_INTERNAL;
goto out;
}
if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
fido_log_debug("%s: fido_rx", __func__);
return (FIDO_ERR_RX);
r = FIDO_ERR_RX;
goto out;
}
/* sanity check */
if (assert->stmt_len >= assert->stmt_cnt) {
fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__,
assert->stmt_len, assert->stmt_cnt);
return (FIDO_ERR_INTERNAL);
r = FIDO_ERR_INTERNAL;
goto out;
}
if ((r = cbor_parse_reply(reply, (size_t)reply_len,
if ((r = cbor_parse_reply(msg, (size_t)msglen,
&assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) {
fido_log_debug("%s: parse_assert_reply", __func__);
return (r);
goto out;
}
return (FIDO_OK);
r = FIDO_OK;
out:
freezero(msg, FIDO_MAXMSG);
return (r);
}
static int
fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert,
const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms)
const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms)
{
int r;
if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK ||
if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin,
ms)) != FIDO_OK ||
(r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK)
return (r);
while (assert->stmt_len < assert->stmt_cnt) {
if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK ||
if ((r = fido_get_next_assert_tx(dev, ms)) != FIDO_OK ||
(r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK)
return (r);
assert->stmt_len++;
@ -286,11 +306,12 @@ fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
{
fido_blob_t *ecdh = NULL;
es256_pk_t *pk = NULL;
int ms = dev->timeout_ms;
int r;
#ifdef USE_WINHELLO
if (dev->flags & FIDO_DEV_WINHELLO)
return (fido_winhello_get_assert(dev, assert, pin));
return (fido_winhello_get_assert(dev, assert, pin, ms));
#endif
if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
@ -302,19 +323,19 @@ fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
if (fido_dev_is_fido2(dev) == false) {
if (pin != NULL || assert->ext.mask != 0)
return (FIDO_ERR_UNSUPPORTED_OPTION);
return (u2f_authenticate(dev, assert, -1));
return (u2f_authenticate(dev, assert, &ms));
}
if (pin != NULL || (assert->uv == FIDO_OPT_TRUE &&
fido_dev_supports_permissions(dev)) ||
(assert->ext.mask & FIDO_EXT_HMAC_SECRET)) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
}
r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1);
r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, &ms);
if (r == FIDO_OK && (assert->ext.mask & FIDO_EXT_HMAC_SECRET))
if (decrypt_hmac_secrets(dev, assert, ecdh) < 0) {
fido_log_debug("%s: decrypt_hmac_secrets", __func__);
@ -364,49 +385,104 @@ check_extensions(int authdata_ext, int ext)
return (0);
}
static int
get_es256_hash(fido_blob_t *dgst, const fido_blob_t *clientdata,
const fido_blob_t *authdata)
{
const EVP_MD *md;
EVP_MD_CTX *ctx = NULL;
if (dgst->len < SHA256_DIGEST_LENGTH ||
(md = EVP_sha256()) == NULL ||
(ctx = EVP_MD_CTX_new()) == NULL ||
EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 ||
EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
EVP_MD_CTX_free(ctx);
return (-1);
}
dgst->len = SHA256_DIGEST_LENGTH;
EVP_MD_CTX_free(ctx);
return (0);
}
static int
get_es384_hash(fido_blob_t *dgst, const fido_blob_t *clientdata,
const fido_blob_t *authdata)
{
const EVP_MD *md;
EVP_MD_CTX *ctx = NULL;
if (dgst->len < SHA384_DIGEST_LENGTH ||
(md = EVP_sha384()) == NULL ||
(ctx = EVP_MD_CTX_new()) == NULL ||
EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 ||
EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
EVP_MD_CTX_free(ctx);
return (-1);
}
dgst->len = SHA384_DIGEST_LENGTH;
EVP_MD_CTX_free(ctx);
return (0);
}
static int
get_eddsa_hash(fido_blob_t *dgst, const fido_blob_t *clientdata,
const fido_blob_t *authdata)
{
if (SIZE_MAX - authdata->len < clientdata->len ||
dgst->len < authdata->len + clientdata->len)
return (-1);
memcpy(dgst->ptr, authdata->ptr, authdata->len);
memcpy(dgst->ptr + authdata->len, clientdata->ptr, clientdata->len);
dgst->len = authdata->len + clientdata->len;
return (0);
}
int
fido_get_signed_hash(int cose_alg, fido_blob_t *dgst,
const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor)
{
cbor_item_t *item = NULL;
unsigned char *authdata_ptr = NULL;
size_t authdata_len;
fido_blob_t authdata;
struct cbor_load_result cbor;
SHA256_CTX ctx;
int ok = -1;
fido_log_debug("%s: cose_alg=%d", __func__, cose_alg);
if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len,
&cbor)) == NULL || cbor_isa_bytestring(item) == false ||
cbor_bytestring_is_definite(item) == false) {
fido_log_debug("%s: authdata", __func__);
goto fail;
}
authdata.ptr = cbor_bytestring_handle(item);
authdata.len = cbor_bytestring_length(item);
authdata_ptr = cbor_bytestring_handle(item);
authdata_len = cbor_bytestring_length(item);
if (cose_alg != COSE_EDDSA) {
if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 ||
SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
SHA256_Final(dgst->ptr, &ctx) == 0) {
fido_log_debug("%s: sha256", __func__);
goto fail;
}
dgst->len = SHA256_DIGEST_LENGTH;
} else {
if (SIZE_MAX - authdata_len < clientdata->len ||
dgst->len < authdata_len + clientdata->len) {
fido_log_debug("%s: memcpy", __func__);
goto fail;
}
memcpy(dgst->ptr, authdata_ptr, authdata_len);
memcpy(dgst->ptr + authdata_len, clientdata->ptr,
clientdata->len);
dgst->len = authdata_len + clientdata->len;
switch (cose_alg) {
case COSE_ES256:
case COSE_RS256:
ok = get_es256_hash(dgst, clientdata, &authdata);
break;
case COSE_ES384:
ok = get_es384_hash(dgst, clientdata, &authdata);
break;
case COSE_EDDSA:
ok = get_eddsa_hash(dgst, clientdata, &authdata);
break;
default:
fido_log_debug("%s: unknown cose_alg", __func__);
break;
}
ok = 0;
fail:
if (item != NULL)
cbor_decref(&item);
@ -414,123 +490,6 @@ fail:
return (ok);
}
int
fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk,
const fido_blob_t *sig)
{
EVP_PKEY *pkey = NULL;
EC_KEY *ec = NULL;
int ok = -1;
/* ECDSA_verify needs ints */
if (dgst->len > INT_MAX || sig->len > INT_MAX) {
fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
dgst->len, sig->len);
return (-1);
}
if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL ||
(ec = __UNCONST(EVP_PKEY_get0_EC_KEY(pkey))) == NULL) {
fido_log_debug("%s: pk -> ec", __func__);
goto fail;
}
if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
(int)sig->len, ec) != 1) {
fido_log_debug("%s: ECDSA_verify", __func__);
goto fail;
}
ok = 0;
fail:
if (pkey != NULL)
EVP_PKEY_free(pkey);
return (ok);
}
int
fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk,
const fido_blob_t *sig)
{
EVP_PKEY *pkey = NULL;
RSA *rsa = NULL;
int ok = -1;
/* RSA_verify needs unsigned ints */
if (dgst->len > UINT_MAX || sig->len > UINT_MAX) {
fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
dgst->len, sig->len);
return (-1);
}
if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
(rsa = __UNCONST(EVP_PKEY_get0_RSA(pkey))) == NULL) {
fido_log_debug("%s: pk -> ec", __func__);
goto fail;
}
if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr,
(unsigned int)sig->len, rsa) != 1) {
fido_log_debug("%s: RSA_verify", __func__);
goto fail;
}
ok = 0;
fail:
if (pkey != NULL)
EVP_PKEY_free(pkey);
return (ok);
}
int
fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk,
const fido_blob_t *sig)
{
EVP_PKEY *pkey = NULL;
EVP_MD_CTX *mdctx = NULL;
int ok = -1;
/* EVP_DigestVerify needs ints */
if (dgst->len > INT_MAX || sig->len > INT_MAX) {
fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
dgst->len, sig->len);
return (-1);
}
if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
fido_log_debug("%s: pk -> pkey", __func__);
goto fail;
}
if ((mdctx = EVP_MD_CTX_new()) == NULL) {
fido_log_debug("%s: EVP_MD_CTX_new", __func__);
goto fail;
}
if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
goto fail;
}
if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
dgst->len) != 1) {
fido_log_debug("%s: EVP_DigestVerify", __func__);
goto fail;
}
ok = 0;
fail:
if (mdctx != NULL)
EVP_MD_CTX_free(mdctx);
if (pkey != NULL)
EVP_PKEY_free(pkey);
return (ok);
}
int
fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg,
const void *pk)
@ -589,13 +548,16 @@ fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg,
switch (cose_alg) {
case COSE_ES256:
ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig);
ok = es256_pk_verify_sig(&dgst, pk, &stmt->sig);
break;
case COSE_ES384:
ok = es384_pk_verify_sig(&dgst, pk, &stmt->sig);
break;
case COSE_RS256:
ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig);
ok = rs256_pk_verify_sig(&dgst, pk, &stmt->sig);
break;
case COSE_EDDSA:
ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig);
ok = eddsa_pk_verify_sig(&dgst, pk, &stmt->sig);
break;
default:
fido_log_debug("%s: unsupported cose_alg %d", __func__,
@ -711,7 +673,15 @@ fail:
free(id.ptr);
return (r);
}
int
fido_assert_empty_allow_list(fido_assert_t *assert)
{
fido_free_blob_array(&assert->allow_list);
memset(&assert->allow_list, 0, sizeof(assert->allow_list));
return (FIDO_OK);
}
int
@ -778,15 +748,15 @@ fido_assert_reset_tx(fido_assert_t *assert)
fido_blob_reset(&assert->cd);
fido_blob_reset(&assert->cdh);
fido_blob_reset(&assert->ext.hmac_salt);
fido_free_blob_array(&assert->allow_list);
fido_assert_empty_allow_list(assert);
memset(&assert->ext, 0, sizeof(assert->ext));
memset(&assert->allow_list, 0, sizeof(assert->allow_list));
assert->rp_id = NULL;
assert->up = FIDO_OPT_OMIT;
assert->uv = FIDO_OPT_OMIT;
}
static void fido_assert_reset_extattr(fido_assert_extattr_t *ext)
static void
fido_assert_reset_extattr(fido_assert_extattr_t *ext)
{
fido_blob_reset(&ext->hmac_secret_enc);
fido_blob_reset(&ext->blob);

View File

@ -1,7 +1,8 @@
/*
* Copyright (c) 2018 Yubico AB. All rights reserved.
* 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 <openssl/sha.h>
@ -10,6 +11,10 @@
#include "fido.h"
#include "fido/es256.h"
#ifndef FIDO_MAXMSG_CRED
#define FIDO_MAXMSG_CRED 4096
#endif
static int
parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
{
@ -43,7 +48,8 @@ parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
}
static int
fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
int *ms)
{
fido_blob_t f;
fido_blob_t *ecdh = NULL;
@ -92,12 +98,12 @@ fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
/* user verification */
if (pin != NULL || (uv == FIDO_OPT_TRUE &&
fido_dev_supports_permissions(dev))) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh,
pin, cred->rp.id, &argv[7], &argv[8])) != FIDO_OK) {
pin, cred->rp.id, &argv[7], &argv[8], ms)) != FIDO_OK) {
fido_log_debug("%s: cbor_add_uv_params", __func__);
goto fail;
}
@ -114,7 +120,7 @@ fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
/* framing and transmission */
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -131,42 +137,55 @@ fail:
}
static int
fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms)
fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
int r;
unsigned char *reply;
int reply_len;
int r;
fido_cred_reset_rx(cred);
if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
if ((reply = malloc(FIDO_MAXMSG_CRED)) == NULL) {
r = FIDO_ERR_INTERNAL;
goto fail;
}
if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, reply, FIDO_MAXMSG_CRED,
ms)) < 0) {
fido_log_debug("%s: fido_rx", __func__);
return (FIDO_ERR_RX);
r = FIDO_ERR_RX;
goto fail;
}
if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
parse_makecred_reply)) != FIDO_OK) {
fido_log_debug("%s: parse_makecred_reply", __func__);
return (r);
goto fail;
}
if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
fido_blob_is_empty(&cred->attcred.id)) {
fido_cred_reset_rx(cred);
return (FIDO_ERR_INVALID_CBOR);
r = FIDO_ERR_INVALID_CBOR;
goto fail;
}
return (FIDO_OK);
r = FIDO_OK;
fail:
free(reply);
if (r != FIDO_OK)
fido_cred_reset_rx(cred);
return (r);
}
static int
fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
int ms)
int *ms)
{
int r;
if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK ||
if ((r = fido_dev_make_cred_tx(dev, cred, pin, ms)) != FIDO_OK ||
(r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
return (r);
@ -176,18 +195,20 @@ fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
int
fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
{
int ms = dev->timeout_ms;
#ifdef USE_WINHELLO
if (dev->flags & FIDO_DEV_WINHELLO)
return (fido_winhello_make_cred(dev, cred, pin));
return (fido_winhello_make_cred(dev, cred, pin, ms));
#endif
if (fido_dev_is_fido2(dev) == false) {
if (pin != NULL || cred->rk == FIDO_OPT_TRUE ||
cred->ext.mask != 0)
return (FIDO_ERR_UNSUPPORTED_OPTION);
return (u2f_register(dev, cred, -1));
return (u2f_register(dev, cred, &ms));
}
return (fido_dev_make_cred_wait(dev, cred, pin, -1));
return (fido_dev_make_cred_wait(dev, cred, pin, &ms));
}
static int
@ -225,66 +246,85 @@ get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
const es256_pk_t *pk)
{
const uint8_t zero = 0;
const uint8_t four = 4; /* uncompressed point */
SHA256_CTX ctx;
const uint8_t zero = 0;
const uint8_t four = 4; /* uncompressed point */
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx = NULL;
int ok = -1;
if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 ||
SHA256_Update(&ctx, rp_id, rp_id_len) == 0 ||
SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
SHA256_Update(&ctx, id->ptr, id->len) == 0 ||
SHA256_Update(&ctx, &four, sizeof(four)) == 0 ||
SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 ||
SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 ||
SHA256_Final(dgst->ptr, &ctx) == 0) {
if (dgst->len < SHA256_DIGEST_LENGTH ||
(md = EVP_sha256()) == NULL ||
(ctx = EVP_MD_CTX_new()) == NULL ||
EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 ||
EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 ||
EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 ||
EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 ||
EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 ||
EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 ||
EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
fido_log_debug("%s: sha256", __func__);
return (-1);
goto fail;
}
dgst->len = SHA256_DIGEST_LENGTH;
return (0);
ok = 0;
fail:
EVP_MD_CTX_free(ctx);
return (ok);
}
static int
verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c,
const fido_blob_t *sig)
verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt)
{
BIO *rawcert = NULL;
X509 *cert = NULL;
EVP_PKEY *pkey = NULL;
EC_KEY *ec;
int ok = -1;
/* openssl needs ints */
if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) {
fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu",
__func__, dgst->len, x5c->len, sig->len);
if (attstmt->x5c.len > INT_MAX) {
fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len);
return (-1);
}
/* fetch key from x509 */
if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL ||
if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr,
(int)attstmt->x5c.len)) == NULL ||
(cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
(pkey = X509_get_pubkey(cert)) == NULL ||
(ec = __UNCONST(EVP_PKEY_get0_EC_KEY(pkey))) == NULL) {
(pkey = X509_get_pubkey(cert)) == NULL) {
fido_log_debug("%s: x509 key", __func__);
goto fail;
}
if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
(int)sig->len, ec) != 1) {
fido_log_debug("%s: ECDSA_verify", __func__);
goto fail;
switch (attstmt->alg) {
case COSE_UNSPEC:
case COSE_ES256:
ok = es256_verify_sig(dgst, pkey, &attstmt->sig);
break;
case COSE_ES384:
ok = es384_verify_sig(dgst, pkey, &attstmt->sig);
break;
case COSE_RS256:
ok = rs256_verify_sig(dgst, pkey, &attstmt->sig);
break;
case COSE_RS1:
ok = rs1_verify_sig(dgst, pkey, &attstmt->sig);
break;
case COSE_EDDSA:
ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig);
break;
default:
fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg);
break;
}
ok = 0;
fail:
if (rawcert != NULL)
BIO_free(rawcert);
if (cert != NULL)
X509_free(cert);
if (pkey != NULL)
EVP_PKEY_free(pkey);
BIO_free(rawcert);
X509_free(cert);
EVP_PKEY_free(pkey);
return (ok);
}
@ -292,8 +332,9 @@ fail:
int
fido_cred_verify(const fido_cred_t *cred)
{
unsigned char buf[SHA256_DIGEST_LENGTH];
unsigned char buf[1024]; /* XXX */
fido_blob_t dgst;
int cose_alg;
int r;
dgst.ptr = buf;
@ -333,8 +374,11 @@ fido_cred_verify(const fido_cred_t *cred)
goto out;
}
if ((cose_alg = cred->attstmt.alg) == COSE_UNSPEC)
cose_alg = COSE_ES256; /* backwards compat */
if (!strcmp(cred->fmt, "packed")) {
if (fido_get_signed_hash(COSE_ES256, &dgst, &cred->cdh,
if (fido_get_signed_hash(cose_alg, &dgst, &cred->cdh,
&cred->authdata_cbor) < 0) {
fido_log_debug("%s: fido_get_signed_hash", __func__);
r = FIDO_ERR_INTERNAL;
@ -348,14 +392,21 @@ fido_cred_verify(const fido_cred_t *cred)
r = FIDO_ERR_INTERNAL;
goto out;
}
} else if (!strcmp(cred->fmt, "tpm")) {
if (fido_get_signed_hash_tpm(&dgst, &cred->cdh,
&cred->authdata_raw, &cred->attstmt, &cred->attcred) < 0) {
fido_log_debug("%s: fido_get_signed_hash_tpm", __func__);
r = FIDO_ERR_INTERNAL;
goto out;
}
} else {
fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
r = FIDO_ERR_INVALID_ARGUMENT;
goto out;
}
if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) {
fido_log_debug("%s: verify_sig", __func__);
if (verify_attstmt(&dgst, &cred->attstmt) < 0) {
fido_log_debug("%s: verify_attstmt", __func__);
r = FIDO_ERR_INVALID_SIG;
goto out;
}
@ -435,15 +486,19 @@ fido_cred_verify_self(const fido_cred_t *cred)
switch (cred->attcred.type) {
case COSE_ES256:
ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256,
ok = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256,
&cred->attstmt.sig);
break;
case COSE_ES384:
ok = es384_pk_verify_sig(&dgst, &cred->attcred.pubkey.es384,
&cred->attstmt.sig);
break;
case COSE_RS256:
ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256,
ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256,
&cred->attstmt.sig);
break;
case COSE_EDDSA:
ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa,
ok = eddsa_pk_verify_sig(&dgst, &cred->attcred.pubkey.eddsa,
&cred->attstmt.sig);
break;
default:
@ -482,6 +537,18 @@ fido_cred_clean_authdata(fido_cred_t *cred)
memset(&cred->attcred, 0, sizeof(cred->attcred));
}
static void
fido_cred_clean_attstmt(fido_attstmt_t *attstmt)
{
fido_blob_reset(&attstmt->certinfo);
fido_blob_reset(&attstmt->pubarea);
fido_blob_reset(&attstmt->cbor);
fido_blob_reset(&attstmt->x5c);
fido_blob_reset(&attstmt->sig);
memset(attstmt, 0, sizeof(*attstmt));
}
void
fido_cred_reset_tx(fido_cred_t *cred)
{
@ -495,11 +562,10 @@ fido_cred_reset_tx(fido_cred_t *cred)
free(cred->user.icon);
free(cred->user.name);
free(cred->user.display_name);
fido_free_blob_array(&cred->excl);
fido_cred_empty_exclude_list(cred);
memset(&cred->rp, 0, sizeof(cred->rp));
memset(&cred->user, 0, sizeof(cred->user));
memset(&cred->excl, 0, sizeof(cred->excl));
memset(&cred->ext, 0, sizeof(cred->ext));
cred->type = 0;
@ -513,8 +579,7 @@ fido_cred_reset_rx(fido_cred_t *cred)
free(cred->fmt);
cred->fmt = NULL;
fido_cred_clean_authdata(cred);
fido_blob_reset(&cred->attstmt.x5c);
fido_blob_reset(&cred->attstmt.sig);
fido_cred_clean_attstmt(&cred->attstmt);
fido_blob_reset(&cred->largeblob_key);
}
@ -568,7 +633,6 @@ fail:
fido_cred_clean_authdata(cred);
return (r);
}
int
@ -610,7 +674,6 @@ fail:
fido_cred_clean_authdata(cred);
return (r);
}
int
@ -640,6 +703,39 @@ fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
return (FIDO_OK);
}
int
fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len)
{
cbor_item_t *item = NULL;
struct cbor_load_result cbor;
int r = FIDO_ERR_INVALID_ARGUMENT;
fido_cred_clean_attstmt(&cred->attstmt);
if (ptr == NULL || len == 0)
goto fail;
if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
fido_log_debug("%s: cbor_load", __func__);
goto fail;
}
if (cbor_decode_attstmt(item, &cred->attstmt) < 0) {
fido_log_debug("%s: cbor_decode_attstmt", __func__);
goto fail;
}
r = FIDO_OK;
fail:
if (item != NULL)
cbor_decref(&item);
if (r != FIDO_OK)
fido_cred_clean_attstmt(&cred->attstmt);
return (r);
}
int
fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
{
@ -668,6 +764,15 @@ fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
return (FIDO_OK);
}
int
fido_cred_empty_exclude_list(fido_cred_t *cred)
{
fido_free_blob_array(&cred->excl);
memset(&cred->excl, 0, sizeof(cred->excl));
return (FIDO_OK);
}
int
fido_cred_set_clientdata(fido_cred_t *cred, const unsigned char *data,
size_t data_len)
@ -833,6 +938,19 @@ fido_cred_set_prot(fido_cred_t *cred, int prot)
return (FIDO_OK);
}
int
fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len)
{
if (len == 0)
cred->ext.mask &= ~FIDO_EXT_MINPINLEN;
else
cred->ext.mask |= FIDO_EXT_MINPINLEN;
cred->ext.minpinlen = len;
return (FIDO_OK);
}
int
fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len)
{
@ -856,7 +974,7 @@ fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
return (FIDO_ERR_INVALID_ARGUMENT);
if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f") &&
strcmp(fmt, "none"))
strcmp(fmt, "none") && strcmp(fmt, "tpm"))
return (FIDO_ERR_INVALID_ARGUMENT);
if ((cred->fmt = strdup(fmt)) == NULL)
@ -868,8 +986,10 @@ fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
int
fido_cred_set_type(fido_cred_t *cred, int cose_alg)
{
if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 &&
cose_alg != COSE_EDDSA) || cred->type != 0)
if (cred->type != 0)
return (FIDO_ERR_INVALID_ARGUMENT);
if (cose_alg != COSE_ES256 && cose_alg != COSE_ES384 &&
cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA)
return (FIDO_ERR_INVALID_ARGUMENT);
cred->type = cose_alg;
@ -955,6 +1075,18 @@ fido_cred_authdata_raw_len(const fido_cred_t *cred)
return (cred->authdata_raw.len);
}
const unsigned char *
fido_cred_attstmt_ptr(const fido_cred_t *cred)
{
return (cred->attstmt.cbor.ptr);
}
size_t
fido_cred_attstmt_len(const fido_cred_t *cred)
{
return (cred->attstmt.cbor.len);
}
const unsigned char *
fido_cred_pubkey_ptr(const fido_cred_t *cred)
{
@ -964,6 +1096,9 @@ fido_cred_pubkey_ptr(const fido_cred_t *cred)
case COSE_ES256:
ptr = &cred->attcred.pubkey.es256;
break;
case COSE_ES384:
ptr = &cred->attcred.pubkey.es384;
break;
case COSE_RS256:
ptr = &cred->attcred.pubkey.rs256;
break;
@ -987,6 +1122,9 @@ fido_cred_pubkey_len(const fido_cred_t *cred)
case COSE_ES256:
len = sizeof(cred->attcred.pubkey.es256);
break;
case COSE_ES384:
len = sizeof(cred->attcred.pubkey.es384);
break;
case COSE_RS256:
len = sizeof(cred->attcred.pubkey.rs256);
break;
@ -1031,6 +1169,12 @@ fido_cred_prot(const fido_cred_t *cred)
return (cred->ext.prot);
}
size_t
fido_cred_pin_minlen(const fido_cred_t *cred)
{
return (cred->ext.minpinlen);
}
const char *
fido_cred_fmt(const fido_cred_t *cred)
{

View File

@ -2,6 +2,7 @@
* Copyright (c) 2020 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <sys/types.h>

View File

@ -1,7 +1,8 @@
/*
* Copyright (c) 2018-2021 Yubico AB. All rights reserved.
* 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>
@ -13,6 +14,7 @@
#include <fido.h>
#include <fido/es256.h>
#include <fido/es384.h>
#include <fido/rs256.h>
#include <fido/eddsa.h>
@ -245,7 +247,7 @@ fail:
}
int
write_ec_pubkey(FILE *f, const void *ptr, size_t len)
write_es256_pubkey(FILE *f, const void *ptr, size_t len)
{
EVP_PKEY *pkey = NULL;
es256_pk_t *pk = NULL;
@ -282,6 +284,44 @@ fail:
return (ok);
}
int
write_es384_pubkey(FILE *f, const void *ptr, size_t len)
{
EVP_PKEY *pkey = NULL;
es384_pk_t *pk = NULL;
int ok = -1;
if ((pk = es384_pk_new()) == NULL) {
warnx("es384_pk_new");
goto fail;
}
if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
warnx("es384_pk_from_ptr");
goto fail;
}
if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) {
warnx("es384_pk_to_EVP_PKEY");
goto fail;
}
if (PEM_write_PUBKEY(f, pkey) == 0) {
warnx("PEM_write_PUBKEY");
goto fail;
}
ok = 0;
fail:
es384_pk_free(&pk);
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
return (ok);
}
RSA *
read_rsa_pubkey(const char *path)
{
@ -426,16 +466,24 @@ print_cred(FILE *out_f, int type, const fido_cred_t *cred)
fprintf(out_f, "%s\n", id);
if (type == COSE_ES256) {
write_ec_pubkey(out_f, fido_cred_pubkey_ptr(cred),
switch (type) {
case COSE_ES256:
write_es256_pubkey(out_f, fido_cred_pubkey_ptr(cred),
fido_cred_pubkey_len(cred));
} else if (type == COSE_RS256) {
break;
case COSE_ES384:
write_es384_pubkey(out_f, fido_cred_pubkey_ptr(cred),
fido_cred_pubkey_len(cred));
break;
case COSE_RS256:
write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
fido_cred_pubkey_len(cred));
} else if (type == COSE_EDDSA) {
break;
case COSE_EDDSA:
write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
fido_cred_pubkey_len(cred));
} else {
break;
default:
errx(1, "print_cred: unknown type");
}
@ -447,6 +495,8 @@ cose_type(const char *str, int *type)
{
if (strcmp(str, "es256") == 0)
*type = COSE_ES256;
else if (strcmp(str, "es384") == 0)
*type = COSE_ES384;
else if (strcmp(str, "rs256") == 0)
*type = COSE_RS256;
else if (strcmp(str, "eddsa") == 0)
@ -463,12 +513,14 @@ const char *
cose_string(int type)
{
switch (type) {
case COSE_EDDSA:
return ("eddsa");
case COSE_ES256:
return ("es256");
case COSE_ES384:
return ("es384");
case COSE_RS256:
return ("rs256");
case COSE_EDDSA:
return ("eddsa");
default:
return ("unknown");
}

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.10 2023/05/13 13:04:03 riastradh Exp $
# $NetBSD: Makefile,v 1.11 2023/08/11 23:02:08 christos Exp $
NOLINT=
.include <bsd.own.mk>
@ -32,6 +32,7 @@ ecdh.c \
eddsa.c \
err.c \
es256.c \
es384.c \
hid.c \
hid_netbsd.c \
hid_unix.c \
@ -43,7 +44,12 @@ log.c \
pin.c \
random.c \
reset.c \
rs1.c \
rs256.c \
time.c \
tpm.c \
touch.c \
types.c \
u2f.c
SRCS+= \
@ -60,6 +66,7 @@ fido/credman.h \
fido/eddsa.h \
fido/err.h \
fido/es256.h \
fido/es384.h \
fido/param.h \
fido/rs256.h \
fido/types.h
@ -69,6 +76,7 @@ INCSDIR=/usr/include
MAN+= \
eddsa_pk_new.3 \
es256_pk_new.3 \
es384_pk_new.3 \
fido_assert_allow_cred.3 \
fido_assert_new.3 \
fido_assert_set_authdata.3 \
@ -96,7 +104,7 @@ fido_init.3 \
fido_strerr.3 \
rs256_pk_new.3
SHLIB_MAJOR=4
SHLIB_MAJOR=5
SHLIB_MINOR=0
.SUFFIXES: .in
@ -118,6 +126,7 @@ COPTS.cred.c+=-Wno-error=deprecated-declarations
COPTS.ecdh.c+=-Wno-error=deprecated-declarations
COPTS.ecdh.c+=-Wno-error=pointer-sign
COPTS.es256.c+=-Wno-error=deprecated-declarations
COPTS.es384.c+=-Wno-error=deprecated-declarations
COPTS.rs256.c+=-Wno-error=deprecated-declarations
.include <bsd.lib.mk>