diff --git a/Makefile.am b/Makefile.am index 97394efb16c..75d7431b907 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3807,7 +3807,8 @@ test_passkey_LDFLAGS = \ -Wl,-wrap,fido_assert_sig_len \ -Wl,-wrap,fido_assert_set_count \ -Wl,-wrap,fido_assert_set_authdata \ - -Wl,-wrap,fido_assert_set_sig + -Wl,-wrap,fido_assert_set_sig \ + -Wl,-wrap,fido_dev_get_retry_count test_passkey_LDADD = \ $(CMOCKA_LIBS) \ $(SSSD_LIBS) \ diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 9fa19312749..ed9330379f9 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -703,6 +703,9 @@ do sss-certmap*) echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> libsss_certmap.lang ;; + sssd-passkey*) + echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd_passkey.lang + ;; *) echo \%lang\(${lang}\) \%{_mandir}/${man}\* >> sssd.lang ;; @@ -1034,6 +1037,7 @@ install -D -p -m 0644 %{SOURCE1} %{buildroot}%{_sysusersdir}/sssd.conf %{_udevrulesdir}/90-sssd-token-access.rules %endif %config(noreplace) %{_sysconfdir}/krb5.conf.d/sssd_enable_passkey +%{_mandir}/man5/sssd-passkey.5* %endif %if %{use_sssd_user} diff --git a/src/man/Makefile.am b/src/man/Makefile.am index 4e1cbd311ed..3880c669f1f 100644 --- a/src/man/Makefile.am +++ b/src/man/Makefile.am @@ -120,6 +120,10 @@ if BUILD_ID_PROVIDER_IDP man_MANS += sssd-idp.5 endif +if BUILD_PASSKEY +man_MANS += sssd-passkey.5 +endif + $(builddir)/src/man/sssd_user_name.include: @mkdir -p $(builddir)/src/man @echo -n $(SSSD_USER) > $(builddir)/src/man/sssd_user_name.include diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg index 41af1c22159..94dc729f3c4 100644 --- a/src/man/po/po4a.cfg +++ b/src/man/po/po4a.cfg @@ -29,6 +29,7 @@ [type:docbook] sssd-systemtap.5.xml $lang:$(builddir)/$lang/sssd-systemtap.5.xml [type:docbook] sssd-ldap-attributes.5.xml $lang:$(builddir)/$lang/sssd-ldap-attributes.5.xml [type:docbook] sssd_krb5_localauth_plugin.8.xml $lang:$(builddir)/$lang/sssd_krb5_localauth_plugin.8.xml +[type:docbook] sssd-passkey.5.xml $lang:$(builddir)/$lang/sssd-passkey.5.xml [type:docbook] include/autofs_attributes.xml $lang:$(builddir)/$lang/include/autofs_attributes.xml opt:"-k 0" [type:docbook] include/service_discovery.xml $lang:$(builddir)/$lang/include/service_discovery.xml opt:"-k 0" [type:docbook] include/upstream.xml $lang:$(builddir)/$lang/include/upstream.xml opt:"-k 0" diff --git a/src/man/sssd-passkey.5.xml b/src/man/sssd-passkey.5.xml new file mode 100644 index 00000000000..bcaff71f703 --- /dev/null +++ b/src/man/sssd-passkey.5.xml @@ -0,0 +1,128 @@ + + + +SSSD Manual pages + + + + + sssd-passkey + 5 + File Formats and Conventions + + + + sssd-passkey + SSSD passkey options + + + + DESCRIPTION + + This manual page describes the specifics for configuration of + passkey for + + sssd + 8 + . + Refer to the FILE FORMAT section of the + + sssd.conf + 5 + manual page for detailed syntax information. + + + + CONFIGURATION OPTIONS + + + + user_verification (boolean) + + + Enable or disable the requirement for user + verification (i.e. PIN, fingerprint) on the passkey + device during authentication. + + + Three different actors come into play when deciding + whether to request user verification: LDAP server, + sssd.conf + 5 + option and the passkey device itself. + + + If the IPA provider is used and online, Kerberos + based passkey authentication is available, the + server-side settings are applied for all passkey + usages. For other cases the settings in + sssd.conf are used. This + includes passkey authentication with any other + provider; and the IPA provider in case online + authentication is not available and local passkey + is allowed by the option + local_auth_policy = enable:passkey. + + + The interaction of the + user_verification option and + the passkey device option is explained in the + following table: + + + + + + + + + user_verificationDevice + Result + + + + True + User verification is configured + User verification is requested + + + True + User verification is not configured + + User verification is requested; however, the + authentication is expected to fail if the device is + not replaced with a device where user verification + is configured during the authentication process. + + + + False + User verification is configured + + sssd automatically detects it during device query + and user verification is requested + + + + False + User verification is not configured + User verification is not requested + + + + If 'enter' is pressed at the PIN prompt for user + verification without typing any characters, then + SSSD falls back from passkey to password + authentication. + + + + + + + + + + + diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 1a2d761af39..6afc965bf42 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -682,15 +682,16 @@ Enable or disable the user verification (i.e. PIN, fingerprint) - during authentication. If enabled, the - PIN will always be requested. + during authentication. - The default is that the key settings - decide what to do. In the IPA or - kerberos pre-authentication case, - this value will be overwritten by the - server. + See + + sssd-passkey + 5 + to + understand the behaviour of this option + in the different scenarios. diff --git a/src/passkey_child/passkey_child.c b/src/passkey_child/passkey_child.c index 320996608ec..1fe0076faa3 100644 --- a/src/passkey_child/passkey_child.c +++ b/src/passkey_child/passkey_child.c @@ -64,13 +64,13 @@ int main(int argc, const char *argv[]) fido_init(init_flags); if (data.action == ACTION_REGISTER) { - ret = register_key(&data); + ret = register_key(&data, TIMEOUT); if (ret != EOK) { ERROR("Error registering key.\n"); goto done; } } else if (data.action == ACTION_AUTHENTICATE) { - ret = authenticate(&data); + ret = authenticate(&data, TIMEOUT); if (ret == EOK) { PRINT("Authentication success.\n"); goto done; @@ -79,7 +79,7 @@ int main(int argc, const char *argv[]) goto done; } } else if (data.action == ACTION_GET_ASSERT) { - ret = get_assert_data(&data); + ret = get_assert_data(&data, TIMEOUT); if (ret != EOK) { ERROR("Error getting assertion data.\n"); goto done; @@ -93,12 +93,20 @@ int main(int argc, const char *argv[]) ERROR("Verification error.\n"); goto done; } + } else if (data.action == ACTION_PREFLIGHT) { + ret = preflight(&data, 1); + /* Errors are ignored, as in most cases they are due to the device not + * being connected to the system. If an error occurs, the default + * values are returned, and that is sufficient for the time being. + */ } done: talloc_free(main_ctx); - if (ret != EOK) { + if (ret == FIDO_ERR_PIN_AUTH_BLOCKED) { + return PIN_AUTH_BLOCKED_EXIT_CODE; + } else if (ret != EOK) { return EXIT_FAILURE; } else { return EXIT_SUCCESS; diff --git a/src/passkey_child/passkey_child.h b/src/passkey_child/passkey_child.h index 185e7e63af7..05fdae92508 100644 --- a/src/passkey_child/passkey_child.h +++ b/src/passkey_child/passkey_child.h @@ -34,13 +34,15 @@ #define USER_ID_SIZE 32 #define TIMEOUT 15 #define FREQUENCY 1 +#define MAX_PIN_RETRIES 8 enum action_opt { ACTION_NONE, ACTION_REGISTER, ACTION_AUTHENTICATE, ACTION_GET_ASSERT, - ACTION_VERIFY_ASSERT + ACTION_VERIFY_ASSERT, + ACTION_PREFLIGHT }; enum credential_type { @@ -103,12 +105,13 @@ check_arguments(const struct passkey_data *data); * @brief Register a key for a user * * @param[in] data passkey data + * @param[in] timeout Timeout to stop looking for a device * * @return 0 if the key was registered properly, * another value on error. */ errno_t -register_key(struct passkey_data *data); +register_key(struct passkey_data *data, int timeout); /** * @brief Translate COSE type from string to int @@ -139,13 +142,14 @@ prepare_credentials(struct passkey_data *data, fido_dev_t *dev, /** * @brief List connected passkey devices * + * @param[in] timeout Timeout to stop looking for a device * @param[out] dev_list passkey device list * @param[out] dev_number Number of passkey devices * * @return 0 if the list was retrieved properly, another value on error. */ errno_t -list_devices(fido_dev_info_t *dev_list, size_t *dev_number); +list_devices(int timeout, fido_dev_info_t *dev_list, size_t *dev_number); /** * @brief Select passkey device @@ -322,18 +326,20 @@ public_key_to_base64(TALLOC_CTX *mem_ctx, const struct passkey_data *data, * key, request the assert and verify it. * * @param[in] data passkey data + * @param[in] timeout Timeout to stop looking for a device * * @return 0 if the user was authenticated properly, * error code otherwise. */ errno_t -authenticate(struct passkey_data *data); +authenticate(struct passkey_data *data, int timeout); /* * @brief Select authenticator for verification * * * @param[in] data passkey data + * @param[in] timeout Timeout to stop looking for a device * @param[out] _dev Device information * @param[out] _assert Assert * @param[out] _index Index for key handle list @@ -342,7 +348,7 @@ authenticate(struct passkey_data *data); * error code otherwise. */ errno_t -select_authenticator(struct passkey_data *data, fido_dev_t **_dev, +select_authenticator(struct passkey_data *data, int timeout, fido_dev_t **_dev, fido_assert_t **_assert, int *_index); /** @@ -533,12 +539,13 @@ print_assert_data(const char *key_handle, const char *crypto_challenge, * and print this all information. * * @param[in] data passkey data + * @param[in] timeout Timeout to stop looking for a device * * @return 0 if the assertion was obtained properly, * error code otherwise. */ errno_t -get_assert_data(struct passkey_data *data); +get_assert_data(struct passkey_data *data, int timeout); /** * @brief Verify assertion data @@ -554,4 +561,47 @@ get_assert_data(struct passkey_data *data); errno_t verify_assert_data(struct passkey_data *data); +/** + * @brief Obtain PIN retries in the device + * + * @param[in] dev Device information + * @param[in] data passkey data + * @param[in] _pin_retries Number of PIN retries + * + * @return 0 if the PIN retries were obtained properly, + * error code otherwise. + */ +errno_t +get_device_pin_retries(fido_dev_t *dev, struct passkey_data *data, + int *_pin_retries); + +/** + * @brief Print preflight information + * + * Print user-verification and pin retries + * + * @param[in] data passkey data + * @param[in] _pin_retries Number of PIN retries + * + * @return EOK + * + */ +errno_t +print_preflight(const struct passkey_data *data, int pin_retries); + +/** + * @brief Obtain authentication data prior to processing + * + * Prepare the assertion request data, select the device to use, get the device + * options and compare them with the organization policy, get the PIN retries + * and print the preflight data. + * + * @param[in] data passkey data + * @param[in] timeout Timeout in seconds to stop looking for a device + * + * @return EOK + */ +errno_t +preflight(struct passkey_data *data, int timeout); + #endif /* __PASSKEY_CHILD_H__ */ diff --git a/src/passkey_child/passkey_child_assert.c b/src/passkey_child/passkey_child_assert.c index 5139dc82ef0..7920e6fd7fb 100644 --- a/src/passkey_child/passkey_child_assert.c +++ b/src/passkey_child/passkey_child_assert.c @@ -51,7 +51,8 @@ set_assert_client_data_hash(const struct passkey_data *data, return ENOMEM; } - if (data->action == ACTION_AUTHENTICATE) { + if (data->action == ACTION_AUTHENTICATE + || data->action == ACTION_PREFLIGHT) { ret = sss_generate_csprng_buffer(cdh, sizeof(cdh)); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, diff --git a/src/passkey_child/passkey_child_common.c b/src/passkey_child/passkey_child_common.c index 6fadd024333..ff80dcb6bdc 100644 --- a/src/passkey_child/passkey_child_common.c +++ b/src/passkey_child/passkey_child_common.c @@ -177,6 +177,8 @@ parse_arguments(TALLOC_CTX *mem_ctx, int argc, const char *argv[], _("Obtain assertion data"), NULL }, {"verify-assert", 0, POPT_ARG_NONE, NULL, 'v', _("Verify assertion data"), NULL }, + {"preflight", 0, POPT_ARG_NONE, NULL, 'p', + _("Obtain authentication data prior to processing"), NULL }, {"username", 0, POPT_ARG_STRING, &data->shortname, 0, _("Shortname"), NULL }, {"domain", 0, POPT_ARG_STRING, &data->domain, 0, @@ -259,6 +261,16 @@ parse_arguments(TALLOC_CTX *mem_ctx, int argc, const char *argv[], } data->action = ACTION_VERIFY_ASSERT; break; + case 'p': + if (data->action != ACTION_NONE) { + 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_PREFLIGHT; + break; case 'q': data->quiet = true; break; @@ -419,12 +431,20 @@ check_arguments(const struct passkey_data *data) goto done; } + if (data->action == ACTION_PREFLIGHT + && (data->domain == NULL || data->key_handle_list == NULL)) { + DEBUG(SSSDBG_OP_FAILURE, + "Too few arguments for preflight action.\n"); + ret = ERR_INPUT_PARSE; + goto done; + } + done: return ret; } errno_t -register_key(struct passkey_data *data) +register_key(struct passkey_data *data, int timeout) { TALLOC_CTX *tmp_ctx = NULL; fido_cred_t *cred = NULL; @@ -460,7 +480,7 @@ register_key(struct passkey_data *data) goto done; } - ret = list_devices(dev_list, &dev_number); + ret = list_devices(timeout, dev_list, &dev_number); if (ret != EOK) { goto done; } @@ -571,7 +591,7 @@ public_key_to_base64(TALLOC_CTX *mem_ctx, const struct passkey_data *data, } errno_t -select_authenticator(struct passkey_data *data, fido_dev_t **_dev, +select_authenticator(struct passkey_data *data, int timeout, fido_dev_t **_dev, fido_assert_t **_assert, int *_index) { fido_dev_info_t *dev_list = NULL; @@ -589,7 +609,7 @@ select_authenticator(struct passkey_data *data, fido_dev_t **_dev, } DEBUG(SSSDBG_TRACE_FUNC, "Checking for devices.\n"); - ret = list_devices(dev_list, &dev_list_len); + ret = list_devices(timeout, dev_list, &dev_list_len); if (ret != EOK) { goto done; } @@ -706,7 +726,7 @@ public_key_to_libfido2(const char *pem_public_key, struct pk_data_t *_pk_data) } errno_t -authenticate(struct passkey_data *data) +authenticate(struct passkey_data *data, int timeout) { TALLOC_CTX *tmp_ctx = NULL; fido_assert_t *assert = NULL; @@ -721,7 +741,7 @@ authenticate(struct passkey_data *data) return ENOMEM; } - ret = select_authenticator(data, &dev, &assert, &index); + ret = select_authenticator(data, timeout, &dev, &assert, &index); if (ret != EOK) { goto done; } @@ -779,7 +799,7 @@ authenticate(struct passkey_data *data) } errno_t -get_assert_data(struct passkey_data *data) +get_assert_data(struct passkey_data *data, int timeout) { TALLOC_CTX *tmp_ctx = NULL; fido_dev_t *dev = NULL; @@ -795,7 +815,7 @@ get_assert_data(struct passkey_data *data) return ENOMEM; } - ret = select_authenticator(data, &dev, &assert, &index); + ret = select_authenticator(data, timeout, &dev, &assert, &index); if (ret != EOK) { goto done; } @@ -887,3 +907,47 @@ verify_assert_data(struct passkey_data *data) return ret; } + +errno_t +preflight(struct passkey_data *data, int timeout) +{ + fido_assert_t *assert = NULL; + fido_dev_t *dev = NULL; + int index = 0; + int pin_retries = 0; + errno_t ret; + + ret = select_authenticator(data, timeout, &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, "Checking the number of remaining PIN retries.\n"); + ret = get_device_pin_retries(dev, data, &pin_retries); + if (ret != FIDO_OK) { + goto done; + } + + ret = EOK; + +done: + if (ret != EOK) { + data->user_verification = FIDO_OPT_TRUE; + pin_retries = MAX_PIN_RETRIES; + } + print_preflight(data, pin_retries); + + if (dev != NULL) { + fido_dev_close(dev); + } + fido_dev_free(&dev); + fido_assert_free(&assert); + + return EOK; +} diff --git a/src/passkey_child/passkey_child_credentials.c b/src/passkey_child/passkey_child_credentials.c index e27afb411bb..dc88fb8ccbf 100644 --- a/src/passkey_child/passkey_child_credentials.c +++ b/src/passkey_child/passkey_child_credentials.c @@ -23,6 +23,7 @@ */ #include +#include #include #include @@ -679,3 +680,40 @@ evp_pkey_to_eddsa_pubkey(const EVP_PKEY *evp_pkey, struct pk_data_t *_pk_data) done: return ret; } + +errno_t +print_preflight(const struct passkey_data *data, int pin_retries) +{ + json_t *jroot = NULL; + char* string = NULL; + bool user_verification; + + if (data->user_verification == FIDO_OPT_TRUE) { + user_verification = true; + } else { + user_verification = false; + } + + jroot = json_pack("{s:b, s:i}", + "pin_required", user_verification, + "attempts", pin_retries); + + if (jroot == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to create jroot object.\n"); + goto done; + } + + string = json_dumps(jroot, 0); + if (string == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "json_dumps() failed.\n"); + goto done; + } + + puts(string); + free(string); + +done: + json_decref(jroot); + + return EOK; +} diff --git a/src/passkey_child/passkey_child_devices.c b/src/passkey_child/passkey_child_devices.c index 2011b12f661..7ea0409f04f 100644 --- a/src/passkey_child/passkey_child_devices.c +++ b/src/passkey_child/passkey_child_devices.c @@ -28,11 +28,11 @@ #include "passkey_child.h" errno_t -list_devices(fido_dev_info_t *dev_list, size_t *dev_number) +list_devices(int timeout, fido_dev_info_t *dev_list, size_t *dev_number) { - errno_t ret; + errno_t ret = EOK; - for (int i = 0; i < TIMEOUT; i += FREQUENCY) { + for (int i = 0; i < timeout; i += FREQUENCY) { ret = fido_dev_info_manifest(dev_list, DEVLIST_SIZE, dev_number); if (ret != FIDO_OK) { DEBUG(SSSDBG_OP_FAILURE, @@ -45,7 +45,7 @@ list_devices(fido_dev_info_t *dev_list, size_t *dev_number) break; } - if (i < (TIMEOUT - 1)) { + if (i < (timeout - 1)) { DEBUG(SSSDBG_TRACE_FUNC, "No device available, retrying.\n"); sleep(FREQUENCY); } @@ -244,3 +244,25 @@ get_device_options(fido_dev_t *dev, struct passkey_data *_data) return ret; } + +errno_t +get_device_pin_retries(fido_dev_t *dev, struct passkey_data *data, + int *_pin_retries) +{ + int ret = EOK; + + if (data->user_verification == FIDO_OPT_TRUE) { + ret = fido_dev_get_retry_count(dev, _pin_retries); + if (ret != FIDO_OK) { + DEBUG(SSSDBG_OP_FAILURE, + "fido_dev_get_retry_count failed [%d]: %s.\n", + ret, fido_strerr(ret)); + goto done; + } + } else { + *_pin_retries = MAX_PIN_RETRIES; + } + +done: + return ret; +} diff --git a/src/tests/cmocka/test_passkey_child.c b/src/tests/cmocka/test_passkey_child.c index 5003152c453..5f79d4bbe21 100644 --- a/src/tests/cmocka/test_passkey_child.c +++ b/src/tests/cmocka/test_passkey_child.c @@ -524,6 +524,17 @@ __wrap_fido_assert_set_sig(fido_assert_t *assert, size_t idx, return ret; } +int +__wrap_fido_dev_get_retry_count(fido_dev_t *dev, int *pin_retries) +{ + int ret; + + ret = mock(); + (*pin_retries) = mock(); + + return ret; +} + /*********************** * TEST **********************/ @@ -658,7 +669,7 @@ void test_list_devices_one_device(void **state) will_return(__wrap_fido_dev_info_manifest, FIDO_OK); will_return(__wrap_fido_dev_info_manifest, 1); - ret = list_devices(ts->dev_list, &ts->dev_number); + ret = list_devices(TIMEOUT, ts->dev_list, &ts->dev_number); assert_int_equal(ret, FIDO_OK); assert_int_equal(ts->dev_number, 1); @@ -677,7 +688,7 @@ void test_list_devices_no_device(void **state) } } - ret = list_devices(ts->dev_list, &ts->dev_number); + ret = list_devices(TIMEOUT, ts->dev_list, &ts->dev_number); assert_int_equal(ret, FIDO_OK); assert_int_equal(ts->dev_number, 0); @@ -696,7 +707,7 @@ void test_list_devices_error(void **state) } } - ret = list_devices(ts->dev_list, &ts->dev_number); + ret = list_devices(TIMEOUT, ts->dev_list, &ts->dev_number); assert_int_equal(ret, FIDO_ERR_INVALID_ARGUMENT); } @@ -907,7 +918,7 @@ void test_register_key_integration(void **state) will_return(__wrap_fido_cred_pubkey_ptr, TEST_ES256_HEX_PUBLIC_KEY); will_return(__wrap_fido_cred_pubkey_len, 64); - ret = register_key(&data); + ret = register_key(&data, TIMEOUT); assert_int_equal(ret, EOK); } @@ -941,7 +952,7 @@ void test_select_authenticator(void **state) will_return(__wrap_fido_dev_is_fido2, true); will_return(__wrap_fido_dev_get_assert, FIDO_OK); - ret = select_authenticator(&data, &dev, &assert, &index); + ret = select_authenticator(&data, TIMEOUT, &dev, &assert, &index); assert_int_equal(ret, FIDO_OK); @@ -1244,7 +1255,7 @@ void test_authenticate_integration(void **state) will_return(__wrap_fido_assert_set_uv, FIDO_OK); will_return(__wrap_fido_assert_verify, FIDO_OK); - ret = authenticate(&data); + ret = authenticate(&data, TIMEOUT); assert_int_equal(ret, EOK); talloc_free(tmp_ctx); @@ -1297,7 +1308,7 @@ void test_get_assert_data_integration(void **state) will_return(__wrap_fido_assert_sig_ptr, TEST_HEX_SIGNATURE); will_return(__wrap_fido_assert_sig_len, TEST_SIGNATURE_LEN); - ret = get_assert_data(&data); + ret = get_assert_data(&data, TIMEOUT); assert_int_equal(ret, EOK); talloc_free(tmp_ctx); @@ -1339,6 +1350,38 @@ void test_verify_assert_data_integration(void **state) talloc_free(tmp_ctx); } +void test_get_device_pin_retries_success(void **state) +{ + struct passkey_data data; + fido_dev_t *dev = NULL; + int pin_retries = 0; + errno_t ret; + + data.user_verification = FIDO_OPT_TRUE; + will_return(__wrap_fido_dev_get_retry_count, FIDO_OK); + will_return(__wrap_fido_dev_get_retry_count, 8); + + ret = get_device_pin_retries(dev, &data, &pin_retries); + assert_int_equal(ret, FIDO_OK); + assert_int_equal(pin_retries, 8); +} + +void test_get_device_pin_retries_failure(void **state) +{ + struct passkey_data data; + fido_dev_t *dev = NULL; + int pin_retries = 0; + errno_t ret; + + data.user_verification = FIDO_OPT_TRUE; + will_return(__wrap_fido_dev_get_retry_count, FIDO_ERR_INVALID_ARGUMENT); + will_return(__wrap_fido_dev_get_retry_count, 8); + + ret = get_device_pin_retries(dev, &data, &pin_retries); + assert_int_equal(ret, FIDO_ERR_INVALID_ARGUMENT); + assert_int_equal(pin_retries, 8); +} + static void test_parse_supp_valgrind_args(void) { /* @@ -1349,6 +1392,54 @@ static void test_parse_supp_valgrind_args(void) DEBUG_CLI_INIT(debug_level); } +void test_preflight_integration(void **state) +{ + TALLOC_CTX *tmp_ctx; + struct passkey_data data; + size_t dev_number = 3; + char *key_handle; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + assert_non_null(tmp_ctx); + data.action = ACTION_PREFLIGHT; + data.shortname = "user"; + data.domain = "test.com"; + key_handle = talloc_strdup(tmp_ctx, TEST_KEY_HANDLE); + data.key_handle_list = &key_handle; + data.key_handle_size = 1; + data.type = COSE_ES256; + data.user_verification = FIDO_OPT_TRUE; + data.user_id = NULL; + data.quiet = false; + will_return(__wrap_fido_dev_info_manifest, FIDO_OK); + will_return(__wrap_fido_dev_info_manifest, dev_number); + will_return(__wrap_fido_assert_set_rp, FIDO_OK); + will_return(__wrap_fido_assert_allow_cred, FIDO_OK); + will_return(__wrap_fido_assert_set_uv, FIDO_OK); + will_return(__wrap_fido_assert_set_clientdata_hash, FIDO_OK); + for (size_t i = 0; i < (dev_number - 1); i++) { + will_return(__wrap_fido_dev_info_path, TEST_PATH); + will_return(__wrap_fido_dev_open, FIDO_OK); + will_return(__wrap_fido_dev_is_fido2, true); + if (i == 0) { + will_return(__wrap_fido_dev_get_assert, FIDO_ERR_INVALID_SIG); + } else { + will_return(__wrap_fido_dev_get_assert, FIDO_OK); + } + } + will_return(__wrap_fido_dev_has_uv, false); + will_return(__wrap_fido_dev_has_pin, true); + will_return(__wrap_fido_dev_supports_uv, false); + will_return(__wrap_fido_dev_get_retry_count, FIDO_OK); + will_return(__wrap_fido_dev_get_retry_count, 8); + + ret = preflight(&data, 1); + assert_int_equal(ret, EOK); + + talloc_free(tmp_ctx); +} + int main(int argc, const char *argv[]) { poptContext pc; @@ -1396,6 +1487,9 @@ int main(int argc, const char *argv[]) cmocka_unit_test(test_authenticate_integration), cmocka_unit_test(test_get_assert_data_integration), cmocka_unit_test(test_verify_assert_data_integration), + cmocka_unit_test(test_get_device_pin_retries_success), + cmocka_unit_test(test_get_device_pin_retries_failure), + cmocka_unit_test(test_preflight_integration), }; /* Set debug level to invalid value so we can decide if -d 0 was used. */ diff --git a/src/util/util.h b/src/util/util.h index 9906863e921..76bec23a344 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -122,6 +122,7 @@ extern int socket_activated; enum sssd_exit_status { CHILD_TIMEOUT_EXIT_CODE = 7, CA_DB_NOT_FOUND_EXIT_CODE = 50, + PIN_AUTH_BLOCKED_EXIT_CODE = 52, /* to match FIDO_ERR_PIN_AUTH_BLOCKED in fido2 error codes */ SSS_WATCHDOG_EXIT_CODE = 70 /* to match EX_SOFTWARE in sysexits.h */ };