diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
commit | 74aa0bc6779af38018a03fd2cf4419fe85917904 (patch) | |
tree | 9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/passkey_child/passkey_child_common.c | |
parent | Initial commit. (diff) | |
download | sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip |
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/passkey_child/passkey_child_common.c')
-rw-r--r-- | src/passkey_child/passkey_child_common.c | 885 |
1 files changed, 885 insertions, 0 deletions
diff --git a/src/passkey_child/passkey_child_common.c b/src/passkey_child/passkey_child_common.c new file mode 100644 index 0000000..000a7ee --- /dev/null +++ b/src/passkey_child/passkey_child_common.c @@ -0,0 +1,885 @@ +/* + SSSD + + Helper child to commmunicate with passkey devices + + Authors: + Iker Pedrosa <ipedrosa@redhat.com> + + Copyright (C) 2022 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <popt.h> +#include <sys/prctl.h> +#include <fido/param.h> +#include <openssl/err.h> +#include <openssl/pem.h> + +#include <openssl/err.h> +#include <openssl/pem.h> + +#include "util/crypto/sss_crypto.h" +#include "util/debug.h" +#include "util/util.h" +#include "util/crypto/sss_crypto.h" + +#include "passkey_child.h" + +#if OPENSSL_VERSION_NUMBER >= 0x30000000 +#define get_id(x) EVP_PKEY_get_base_id((x)) +#else +#define get_id(x) EVP_PKEY_base_id((x)) +#endif /* OPENSSL_VERSION_NUMBER */ + +errno_t +cose_str_to_int(const char *type, int *out) +{ + if (strcasecmp(type, "es256") == 0) { + *out = COSE_ES256; + } else if (strcasecmp(type, "rs256") == 0) { + *out = COSE_RS256; + } else if (strcasecmp(type, "eddsa") == 0) { + *out = COSE_EDDSA; + } else { + *out = 0; + return ERR_INVALID_CRED_TYPE; + } + + return EOK; +} + +static errno_t +cred_type_str_to_enum(const char *type, enum credential_type *out) +{ + if (strcasecmp(type, "server-side") == 0) { + *out = CRED_SERVER_SIDE; + } else if (strcasecmp(type, "discoverable") == 0) { + *out = CRED_DISCOVERABLE; + } else { + *out = 0; + return ERR_INVALID_CRED_TYPE; + } + + return EOK; +} + +static errno_t +parse_public_keys_and_handlers(TALLOC_CTX *mem_ctx, + const char *public_keys, + const char *key_handles, + struct passkey_data *_data) +{ + TALLOC_CTX *tmp_ctx = NULL; + char **pk_list = NULL; + char **kh_list = NULL; + int pk_num = 0; + int kh_num = 0; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ERROR("talloc_new() failed\n"); + return ENOMEM; + } + + ret = split_on_separator(tmp_ctx, public_keys, ',', true, true, &pk_list, &pk_num); + if (ret != EOK && _data->action == ACTION_AUTHENTICATE) { + ERROR("Incorrectly formatted public keys.\n"); + goto done; + } + + ret = split_on_separator(tmp_ctx, key_handles, ',', true, true, &kh_list, &kh_num); + if (ret != EOK) { + ERROR("Incorrectly formatted public keys.\n"); + goto done; + } + + if (_data->action == ACTION_AUTHENTICATE && pk_num != kh_num) { + ERROR("The number of public keys and key handles don't match.\n"); + goto done; + } + + _data->public_key_list = talloc_steal(mem_ctx, pk_list); + _data->key_handle_list = talloc_steal(mem_ctx, kh_list); + _data->public_key_size = pk_num; + _data->key_handle_size = kh_num; + +done: + talloc_free(tmp_ctx); + + return ret; +} + +errno_t +parse_arguments(TALLOC_CTX *mem_ctx, int argc, const char *argv[], + struct passkey_data *data) +{ + int opt; + int dumpable = 1; + int debug_fd = -1; + char *user_verification = NULL; + char *public_keys = NULL; + char *key_handles = NULL; + const char *opt_logger = NULL; + const char *type = NULL; + const char *cred_type = NULL; + poptContext pc; + errno_t ret; + + /* Set defaults */ + data->action = ACTION_NONE; + data->shortname = NULL; + data->domain = NULL; + data->public_key_list = NULL; + data->key_handle_list = NULL; + data->public_key_size = 0; + data->key_handle_size = 0; + data->crypto_challenge = NULL; + data->auth_data = NULL; + data->signature = NULL; + data->type = COSE_ES256; + data->user_verification = FIDO_OPT_OMIT; + data->cred_type = CRED_SERVER_SIDE; + data->user_id = NULL; + data->mapping_file = NULL; + data->quiet = false; + data->debug_libfido2 = false; + + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_DEBUG_OPTS + {"dumpable", 0, POPT_ARG_INT, &dumpable, 0, + _("Allow core dumps"), NULL }, + {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0, + _("An open file descriptor for the debug logs"), NULL}, + SSSD_LOGGER_OPTS + {"register", 0, POPT_ARG_NONE, NULL, 'r', + _("Register a passkey for a user"), NULL }, + {"authenticate", 0, POPT_ARG_NONE, NULL, 'a', + _("Authenticate a user with a passkey"), NULL }, + {"get-assert", 0, POPT_ARG_NONE, NULL, 'g', + _("Obtain assertion data"), NULL }, + {"verify-assert", 0, POPT_ARG_NONE, NULL, 'v', + _("Verify assertion data"), NULL }, + {"username", 0, POPT_ARG_STRING, &data->shortname, 0, + _("Shortname"), NULL }, + {"domain", 0, POPT_ARG_STRING, &data->domain, 0, + _("Domain"), NULL}, + {"public-key", 0, POPT_ARG_STRING, &public_keys, 0, + _("Public key"), NULL }, + {"key-handle", 0, POPT_ARG_STRING, &key_handles, 0, + _("Key handle"), NULL}, + {"cryptographic-challenge", 0, POPT_ARG_STRING, + &data->crypto_challenge, 0, + _("Cryptographic challenge"), NULL}, + {"auth-data", 0, POPT_ARG_STRING, &data->auth_data, 0, + _("Authenticator data"), NULL}, + {"signature", 0, POPT_ARG_STRING, &data->signature, 0, + _("Signature"), NULL}, + {"type", 0, POPT_ARG_STRING, &type, 0, + _("COSE type to use"), "es256|rs256|eddsa"}, + {"user-verification", 0, POPT_ARG_STRING, &user_verification, 0, + _("Require user-verification"), "true|false"}, + {"cred-type", 0, POPT_ARG_STRING, &cred_type, 0, + _("Credential type"), "server-side|discoverable"}, + {"output-file", 0, POPT_ARG_STRING, &data->mapping_file, 0, + _("Write key mapping data to file"), NULL}, + {"quiet", 0, POPT_ARG_NONE, NULL, 'q', + _("Supress prompts"), NULL}, + {"debug-libfido2", 0, POPT_ARG_NONE, NULL, 'd', + _("Enable debug in libfido2 library"), NULL}, + SSSD_LOGGER_OPTS + POPT_TABLEEND + }; + + /* Set debug level to invalid value so we can decide if -d 0 was used. */ + debug_level = SSSDBG_INVALID; + + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + + while((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + case 'r': + if (data->action != ACTION_NONE + && data->action != ACTION_REGISTER) { + fprintf(stderr, "\nActions are mutually exclusive and should" \ + " be used only once.\n\n"); + poptPrintUsage(pc, stderr, 0); + ret = EINVAL; + goto done; + } + data->action = ACTION_REGISTER; + break; + case 'a': + if (data->action != ACTION_NONE + && data->action != ACTION_AUTHENTICATE) { + fprintf(stderr, "\nActions are mutually exclusive and should" \ + " be used only once.\n\n"); + poptPrintUsage(pc, stderr, 0); + ret = EINVAL; + goto done; + } + data->action = ACTION_AUTHENTICATE; + break; + case 'g': + if (data->action != ACTION_NONE + && data->action != ACTION_GET_ASSERT) { + fprintf(stderr, "\nActions are mutually exclusive and should" \ + " be used only once.\n\n"); + poptPrintUsage(pc, stderr, 0); + ret = EINVAL; + goto done; + } + data->action = ACTION_GET_ASSERT; + break; + case 'v': + if (data->action != ACTION_NONE + && data->action != ACTION_VERIFY_ASSERT) { + fprintf(stderr, "\nActions are mutually exclusive and should" \ + " be used only once.\n\n"); + poptPrintUsage(pc, stderr, 0); + ret = EINVAL; + goto done; + } + data->action = ACTION_VERIFY_ASSERT; + break; + case 'q': + data->quiet = true; + break; + case 'd': + data->debug_libfido2 = true; + break; + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + ret = EINVAL; + goto done; + } + } + + poptFreeContext(pc); + + prctl(PR_SET_DUMPABLE, (dumpable == 0) ? 0 : 1); + + if (user_verification != NULL) { + if (strcmp(user_verification, "true") == 0) { + data->user_verification = FIDO_OPT_TRUE; + } else if (strcmp(user_verification, "false") == 0) { + data->user_verification = FIDO_OPT_FALSE; + } else if (user_verification != NULL) { + ERROR("[%s] is not a valid user-verification value.\n", + user_verification); + ret = EINVAL; + goto done; + } + } + + if (type != NULL) { + ret = cose_str_to_int(type, &data->type); + if (ret != EOK) { + ERROR("[%s] is not a valid COSE type (es256, rs256 or eddsa).\n", + type); + goto done; + } + } + + if (public_keys != NULL || key_handles != NULL) { + ret = parse_public_keys_and_handlers(mem_ctx, public_keys, key_handles, + data); + if (ret != EOK) { + goto done; + } + } + + if (cred_type != NULL) { + ret = cred_type_str_to_enum(cred_type, &data->cred_type); + if (ret != EOK) { + ERROR("[%s] is not a valid credential type (server-side or" + " discoverable).\n", + cred_type); + goto done; + } + } + + debug_prg_name = talloc_asprintf(NULL, "passkey_child[%d]", getpid()); + if (debug_prg_name == NULL) { + ERROR("talloc_asprintf failed.\n"); + ret = ENOMEM; + goto done; + } + + if (debug_fd != -1) { + opt_logger = sss_logger_str[FILES_LOGGER]; + ret = set_debug_file_from_fd(debug_fd); + if (ret != EOK) { + opt_logger = sss_logger_str[STDERR_LOGGER]; + ERROR("set_debug_file_from_fd failed.\n"); + } + } + + DEBUG_INIT(debug_level, opt_logger); + + ret = EOK; + +done: + return ret; +} + +errno_t +check_arguments(const struct passkey_data *data) +{ + errno_t ret = EOK; + + DEBUG(SSSDBG_TRACE_FUNC, "Argument values after parsing\n"); + DEBUG(SSSDBG_TRACE_FUNC, "action: %d\n", data->action); + DEBUG(SSSDBG_TRACE_FUNC, "shortname: %s, domain: %s\n", + data->shortname, data->domain); + DEBUG(SSSDBG_TRACE_FUNC, "Number of key handles %d\n", + data->key_handle_size); + for (int i = 0; i < data->key_handle_size; i++) { + DEBUG(SSSDBG_TRACE_FUNC, "key %d, key_handle: %s\n", + i + 1, data->key_handle_list[i]); + } + DEBUG(SSSDBG_TRACE_FUNC, "Number of public keys %d\n", + data->public_key_size); + for (int i = 0; i < data->public_key_size; i++) { + DEBUG(SSSDBG_TRACE_FUNC, "key %d, public_key: %s\n", + i + 1, data->public_key_list[i]); + } + DEBUG(SSSDBG_TRACE_FUNC, "cryptographic-challenge: %s\n", + data->crypto_challenge); + DEBUG(SSSDBG_TRACE_FUNC, "auth-data: %s\n", + data->auth_data); + DEBUG(SSSDBG_TRACE_FUNC, "signature: %s\n", + data->signature); + DEBUG(SSSDBG_TRACE_FUNC, "type: %d\n", data->type); + DEBUG(SSSDBG_TRACE_FUNC, "user_verification: %d\n", + data->user_verification); + DEBUG(SSSDBG_TRACE_FUNC, "cred_type: %d\n", + data->cred_type); + DEBUG(SSSDBG_TRACE_FUNC, "Mapping file: %s\n", data->mapping_file); + DEBUG(SSSDBG_TRACE_FUNC, "debug_libfido2: %d\n", data->debug_libfido2); + + if (data->action == ACTION_NONE) { + DEBUG(SSSDBG_OP_FAILURE, "No action set.\n"); + ret = ERR_INPUT_PARSE; + goto done; + } + + if (data->action == ACTION_REGISTER + && (data->shortname == NULL || data->domain == NULL)) { + DEBUG(SSSDBG_OP_FAILURE, "Too few arguments for register action.\n"); + ret = ERR_INPUT_PARSE; + goto done; + } + + if (data->action == ACTION_AUTHENTICATE + && (data->domain == NULL || data->public_key_list == NULL + || data->key_handle_list == NULL)) { + DEBUG(SSSDBG_OP_FAILURE, + "Too few arguments for authenticate action.\n"); + ret = ERR_INPUT_PARSE; + goto done; + } + + if (data->action == ACTION_GET_ASSERT + && (data->domain == NULL || data->key_handle_list == NULL + || data->crypto_challenge == NULL)) { + DEBUG(SSSDBG_OP_FAILURE, + "Too few arguments for get-assert action.\n"); + ret = ERR_INPUT_PARSE; + goto done; + } + + if (data->action == ACTION_VERIFY_ASSERT + && (data->domain == NULL || data->public_key_list == NULL + || data->key_handle_list == NULL || data->crypto_challenge == NULL + || data->auth_data == NULL || data->signature == NULL)) { + DEBUG(SSSDBG_OP_FAILURE, + "Too few arguments for verify-assert action.\n"); + ret = ERR_INPUT_PARSE; + goto done; + } + +done: + return ret; +} + +errno_t +register_key(struct passkey_data *data) +{ + TALLOC_CTX *tmp_ctx = NULL; + fido_cred_t *cred = NULL; + fido_dev_t *dev = NULL; + fido_dev_info_t *dev_list = NULL; + size_t dev_number = 0; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new() failed.\n"); + return ENOMEM; + } + + data->user_id = talloc_array(tmp_ctx, unsigned char, USER_ID_SIZE); + if (data->user_id == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_array() failed.\n"); + ret = ENOMEM; + goto done; + } + + cred = fido_cred_new(); + if (cred == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "fido_cred_new failed.\n"); + ret = ENOMEM; + goto done; + } + + dev_list = fido_dev_info_new(DEVLIST_SIZE); + if (dev_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "fido_dev_info_new failed.\n"); + ret = ENOMEM; + goto done; + } + + ret = list_devices(dev_list, &dev_number); + if (ret != EOK) { + goto done; + } + + ret = select_device(data->action, dev_list, dev_number, NULL, &dev); + if (ret != EOK) { + goto done; + } + + ret = prepare_credentials(data, dev, cred); + if (ret != EOK) { + goto done; + } + + ret = generate_credentials(data, dev, cred); + if (ret != EOK) { + ERROR("A problem occurred while generating the credentials.\n"); + goto done; + } + + ret = verify_credentials(cred); + if (ret != EOK) { + goto done; + } + + ret = print_credentials(data, cred); + if (ret != EOK) { + goto done; + } + + ret = EOK; + +done: + fido_cred_free(&cred); + fido_dev_info_free(&dev_list, dev_number); + if (dev != NULL) { + fido_dev_close(dev); + } + fido_dev_free(&dev); + talloc_free(tmp_ctx); + + return ret; +} + +errno_t +public_key_to_base64(TALLOC_CTX *mem_ctx, const struct passkey_data *data, + const unsigned char *public_key, size_t pk_len, + char **_pem_key) +{ + EVP_PKEY *evp_pkey = NULL; + unsigned char *pub = NULL; + char *pem_key = NULL; + unsigned long err; + errno_t ret; + + if (_pem_key == NULL) { + ret = EINVAL; + goto done; + } + + switch (data->type) { + case COSE_ES256: + ret = es256_pubkey_to_evp_pkey(mem_ctx, public_key, pk_len, &evp_pkey); + break; + case COSE_RS256: + ret = rs256_pubkey_to_evp_pkey(mem_ctx, public_key, pk_len, &evp_pkey); + break; + case COSE_EDDSA: + ret = eddsa_pubkey_to_evp_pkey(mem_ctx, public_key, pk_len, &evp_pkey); + break; + default: + DEBUG(SSSDBG_OP_FAILURE, "Invalid key type.\n"); + ret = EINVAL; + break; + } + + if (ret != EOK) { + goto done; + } + + ret = i2d_PUBKEY(evp_pkey, &pub); + if (ret < 1) { + err = ERR_get_error(); + DEBUG(SSSDBG_OP_FAILURE, "i2d_PUBKEY failed [%lu][%s].\n", + err, ERR_error_string(err, NULL)); + ret = EIO; + goto done; + } + + pem_key = sss_base64_encode(mem_ctx, pub, ret); + if (pem_key == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sss_base64_encode failed.\n"); + ret = ENOMEM; + goto done; + } + + *_pem_key = pem_key; + ret = EOK; + +done: + free(pub); + + if (evp_pkey != NULL) { + EVP_PKEY_free(evp_pkey); + } + + return ret; +} + +errno_t +select_authenticator(struct passkey_data *data, fido_dev_t **_dev, + fido_assert_t **_assert, int *_index) +{ + fido_dev_info_t *dev_list = NULL; + fido_dev_t *dev = NULL; + size_t dev_list_len = 0; + fido_assert_t *assert = NULL; + int index = 0; + errno_t ret; + + dev_list = fido_dev_info_new(DEVLIST_SIZE); + if (dev_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "fido_dev_info_new failed.\n"); + ret = ENOMEM; + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Checking for devices.\n"); + ret = list_devices(dev_list, &dev_list_len); + if (ret != EOK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "%d key handles provided.\n", + data->key_handle_size); + + while (index < data->key_handle_size) { + DEBUG(SSSDBG_TRACE_FUNC, + "Preparing assert request data with key handle %d.\n", index + 1); + + assert = fido_assert_new(); + if (assert == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "fido_assert_new failed.\n"); + ret = ENOMEM; + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Preparing assert request data.\n"); + ret = prepare_assert(data, index, assert); + if (ret != FIDO_OK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Selecting device.\n"); + ret = select_device(data->action, dev_list, dev_list_len, assert, &dev); + if (ret == EOK) { + /* Key handle found in device */ + break; + } + + if (dev != NULL) { + fido_dev_close(dev); + } + fido_dev_free(&dev); + fido_assert_free(&assert); + index++; + } + + *_dev = dev; + *_assert = assert; + *_index = index; + +done: + if (ret != EOK) { + fido_assert_free(&assert); + } + fido_dev_info_free(&dev_list, dev_list_len); + + return ret; +} + +errno_t +public_key_to_libfido2(const char *pem_public_key, struct pk_data_t *_pk_data) +{ + TALLOC_CTX *tmp_ctx = NULL; + const unsigned char *public_key = NULL; + size_t pk_len; + const EVP_PKEY *evp_pkey = NULL; + int base_id; + unsigned long err; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + goto done; + } + + public_key = sss_base64_decode(tmp_ctx, pem_public_key, &pk_len); + if (public_key == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to decode public key.\n"); + ret = ENOMEM; + goto done; + } + + evp_pkey = d2i_PUBKEY(NULL, &public_key, pk_len); + if (evp_pkey == NULL) { + err = ERR_get_error(); + DEBUG(SSSDBG_OP_FAILURE, "d2i_pubkey failed [%lu][%s].\n", + err, ERR_error_string(err, NULL)); + ret = EIO; + goto done; + } + + base_id = get_id(evp_pkey); + if (base_id == EVP_PKEY_EC) { + _pk_data->type = COSE_ES256; + ret = evp_pkey_to_es256_pubkey(evp_pkey, _pk_data); + } else if (base_id == EVP_PKEY_RSA) { + _pk_data->type = COSE_RS256; + ret = evp_pkey_to_rs256_pubkey(evp_pkey, _pk_data); + } else if (base_id == EVP_PKEY_ED25519) { + _pk_data->type = COSE_EDDSA; + ret = evp_pkey_to_eddsa_pubkey(evp_pkey, _pk_data); + } else { + DEBUG(SSSDBG_OP_FAILURE, + "Unrecognized key type.\n"); + ret = EINVAL; + } + if (ret != EOK) { + goto done; + } + + ret = EOK; + +done: + if (evp_pkey != NULL) { + EVP_PKEY_free(discard_const(evp_pkey)); + } + talloc_free(tmp_ctx); + + return ret; +} + +errno_t +authenticate(struct passkey_data *data) +{ + TALLOC_CTX *tmp_ctx = NULL; + fido_assert_t *assert = NULL; + fido_dev_t *dev = NULL; + struct pk_data_t pk_data = { 0 }; + int index; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ERROR("talloc_new() failed\n"); + return ENOMEM; + } + + ret = select_authenticator(data, &dev, &assert, &index); + if (ret != EOK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Comparing the device and policy options.\n"); + ret = get_device_options(dev, data); + if (ret != FIDO_OK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Resetting assert options.\n"); + ret = set_assert_options(FIDO_OPT_TRUE, data->user_verification, assert); + if (ret != FIDO_OK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to reset assert options.\n"); + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Resetting assert client data.\n"); + ret = set_assert_client_data_hash(data, assert); + if (ret != FIDO_OK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to reset client data hash.\n"); + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Decoding public key.\n"); + ret = public_key_to_libfido2(data->public_key_list[index], &pk_data); + if (ret != FIDO_OK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Getting assert.\n"); + ret = request_assert(data, dev, assert); + if (ret != FIDO_OK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Verifying assert.\n"); + ret = verify_assert(&pk_data, assert); + if (ret != FIDO_OK) { + goto done; + } + + ret = FIDO_OK; + +done: + reset_public_key(&pk_data); + if (dev != NULL) { + fido_dev_close(dev); + } + fido_dev_free(&dev); + fido_assert_free(&assert); + talloc_free(tmp_ctx); + + return ret; +} + +errno_t +get_assert_data(struct passkey_data *data) +{ + TALLOC_CTX *tmp_ctx = NULL; + fido_dev_t *dev = NULL; + fido_assert_t *assert = NULL; + const char *auth_data = NULL; + const char *signature = NULL; + int index; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new() failed.\n"); + return ENOMEM; + } + + ret = select_authenticator(data, &dev, &assert, &index); + if (ret != EOK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Comparing the device and policy options.\n"); + ret = get_device_options(dev, data); + if (ret != FIDO_OK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Resetting assert options.\n"); + ret = set_assert_options(FIDO_OPT_TRUE, data->user_verification, assert); + if (ret != FIDO_OK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to reset assert options.\n"); + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Getting assert.\n"); + ret = request_assert(data, dev, assert); + if (ret != FIDO_OK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Getting authentication data and signature.\n"); + ret = get_assert_auth_data_signature(tmp_ctx, assert, &auth_data, + &signature); + if (ret != EOK) { + goto done; + } + + print_assert_data(data->key_handle_list[index], data->crypto_challenge, + auth_data, signature); + +done: + if (dev != NULL) { + fido_dev_close(dev); + } + fido_dev_free(&dev); + fido_assert_free(&assert); + talloc_free(tmp_ctx); + + return ret; +} + +errno_t +verify_assert_data(struct passkey_data *data) +{ + fido_assert_t *assert = NULL; + struct pk_data_t pk_data = { 0 }; + errno_t ret; + + assert = fido_assert_new(); + if (assert == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "fido_assert_new failed.\n"); + ret = ENOMEM; + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Preparing assert data.\n"); + ret = prepare_assert(data, 0, assert); + if (ret != FIDO_OK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "Preparing assert authenticator data and signature.\n"); + ret = set_assert_auth_data_signature(data, assert); + if (ret != FIDO_OK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Decoding public key.\n"); + ret = public_key_to_libfido2(data->public_key_list[0], &pk_data); + if (ret != FIDO_OK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Verifying assert.\n"); + ret = verify_assert(&pk_data, assert); + if (ret != FIDO_OK) { + goto done; + } + + ret = FIDO_OK; + +done: + reset_public_key(&pk_data); + fido_assert_free(&assert); + + return ret; +} |