Skip to content

Commit

Permalink
passkey: input PIN via stdin
Browse files Browse the repository at this point in the history
For the registration process add a new "quiet" option to suppress the
prompts and read the PIN from stdin. For the authentication process
always read the PIN from stdin.

Signed-off-by: Iker Pedrosa <[email protected]>

Reviewed-by: Justin Stephenson <[email protected]>
Reviewed-by: Sumit Bose <[email protected]>
  • Loading branch information
ikerexxe authored and pbrezina committed Nov 22, 2022
1 parent 2b0a8f2 commit 6b0d175
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 25 deletions.
15 changes: 14 additions & 1 deletion src/passkey_child/passkey_child.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ struct passkey_data {
enum action_opt action;
const char *shortname;
const char *domain;
const char *pin;
char **public_key_list;
char **key_handle_list;
int keys_size;
int type;
fido_opt_t user_verification;
bool quiet;
bool debug_libfido2;
};

Expand Down Expand Up @@ -165,6 +165,19 @@ select_from_multiple_devices(fido_dev_info_t *dev_list,
fido_assert_t *assert,
fido_dev_t **_dev);

/**
* @brief Receive PIN via stdin
*
* @param[in] mem_ctx Memory context
* @param[in] fd File descriptor
* @param[out] pin Pin
*
* @return 0 if the authenticator data was received properly,
* error code otherwise.
*/
errno_t
passkey_recv_pin(TALLOC_CTX *mem_ctx, int fd, char **_pin);

/**
* @brief Disable echoing and read PIN from stdin
*
Expand Down
25 changes: 19 additions & 6 deletions src/passkey_child/passkey_child_assert.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,18 @@ errno_t
request_assert(struct passkey_data *data, fido_dev_t *dev,
fido_assert_t *_assert)
{
TALLOC_CTX *tmp_ctx = NULL;
char *pin = NULL;
bool has_pin;
bool has_uv;
errno_t ret;

tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_new() failed.\n");
return ENOMEM;
}

has_pin = fido_dev_has_pin(dev);
has_uv = fido_dev_has_uv(dev);
if (has_uv == true && data->user_verification != FIDO_OPT_FALSE) {
Expand All @@ -179,14 +187,14 @@ request_assert(struct passkey_data *data, fido_dev_t *dev,
}
}

if (has_pin == true && data->user_verification != FIDO_OPT_FALSE
&& data->pin == NULL) {
ret = ERR_INPUT_PARSE;
ERROR("PIN required.\n");
goto done;
if (has_pin == true && data->user_verification != FIDO_OPT_FALSE) {
ret = passkey_recv_pin(tmp_ctx, STDIN_FILENO, &pin);
if (ret != EOK) {
goto done;
}
}

ret = fido_dev_get_assert(dev, _assert, data->pin);
ret = fido_dev_get_assert(dev, _assert, pin);
if (ret != FIDO_OK) {
DEBUG(SSSDBG_OP_FAILURE, "fido_dev_get_assert failed [%d]: %s.\n",
ret, fido_strerr(ret));
Expand All @@ -202,6 +210,11 @@ request_assert(struct passkey_data *data, fido_dev_t *dev,
}

done:
if (pin != NULL) {
sss_erase_mem_securely(pin, strlen(pin));
}
talloc_free(tmp_ctx);

return ret;
}

Expand Down
9 changes: 6 additions & 3 deletions src/passkey_child/passkey_child_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,12 @@ parse_arguments(TALLOC_CTX *mem_ctx, int argc, const char *argv[],
data->action = ACTION_NONE;
data->shortname = NULL;
data->domain = NULL;
data->pin = NULL;
data->public_key_list = NULL;
data->key_handle_list = NULL;
data->keys_size = 0;
data->type = COSE_ES256;
data->user_verification = FIDO_OPT_OMIT;
data->quiet = false;
data->debug_libfido2 = false;

struct poptOption long_options[] = {
Expand All @@ -150,8 +150,6 @@ parse_arguments(TALLOC_CTX *mem_ctx, int argc, const char *argv[],
_("Shortname"), NULL },
{"domain", 0, POPT_ARG_STRING, &data->domain, 0,
_("Domain"), NULL},
{"pin", 0, POPT_ARG_STRING, &data->pin, 0,
_("Passkey PIN"), NULL},
{"public-key", 0, POPT_ARG_STRING, &public_keys, 0,
_("Public key"), NULL },
{"key-handle", 0, POPT_ARG_STRING, &key_handles, 0,
Expand All @@ -160,6 +158,8 @@ parse_arguments(TALLOC_CTX *mem_ctx, int argc, const char *argv[],
_("COSE type to use"), "es256|rs256|eddsa"},
{"user-verification", 0, POPT_ARG_STRING, &user_verification, 0,
_("Require user-verification"), "true|false"},
{"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
Expand Down Expand Up @@ -195,6 +195,9 @@ parse_arguments(TALLOC_CTX *mem_ctx, int argc, const char *argv[],
}
data->action = ACTION_AUTHENTICATE;
break;
case 'q':
data->quiet = true;
break;
case 'd':
data->debug_libfido2 = true;
break;
Expand Down
91 changes: 78 additions & 13 deletions src/passkey_child/passkey_child_credentials.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@

#include "passkey_child.h"

#define IN_BUF_SIZE 512

errno_t
prepare_credentials(struct passkey_data *data, fido_dev_t *dev,
fido_cred_t *cred)
Expand Down Expand Up @@ -137,6 +139,47 @@ prepare_credentials(struct passkey_data *data, fido_dev_t *dev,
return ret;
}

errno_t
passkey_recv_pin(TALLOC_CTX *mem_ctx, int fd, char **_pin)
{
uint8_t buf[IN_BUF_SIZE];
ssize_t len;
errno_t ret;
char *str;

errno = 0;
len = sss_atomic_read_s(fd, buf, IN_BUF_SIZE);
if (len == -1) {
ret = errno;
ret = (ret == 0) ? EINVAL: ret;
DEBUG(SSSDBG_CRIT_FAILURE,
"read failed [%d][%s].\n", ret, strerror(ret));
return ret;
}

if (len == 0 || *buf == '\0') {
DEBUG(SSSDBG_CRIT_FAILURE, "Missing PIN.\n");
return EINVAL;
}

str = talloc_strdup(mem_ctx, (char *) buf);
if (str == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
return ENOMEM;
}

if (strlen(str) != len) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Input contains additional data, only PIN expected.\n");
talloc_free(str);
return EINVAL;
}

*_pin = str;

return EOK;
}

ssize_t
read_pin(char **pin)
{
Expand All @@ -149,18 +192,20 @@ read_pin(char **pin)
ret = tcgetattr(STDIN_FILENO, &old);
if (ret != 0) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable get the parameters associated with stdin.\n");
"Unable to get the parameters associated with stdin [%d]: %s.\n",
errno, sss_strerror(errno));
goto done;
}
new = old;
new.c_lflag &= ~ECHO;
ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, &new);
if (ret != 0) {
DEBUG(SSSDBG_OP_FAILURE, "Unable to turn echoing off.\n");
DEBUG(SSSDBG_OP_FAILURE, "Unable to turn echoing off [%d]: %s.\n",
errno, sss_strerror(errno));
goto done;
}

ERROR("Enter PIN: ");
printf("Enter PIN: ");
bytes_read = getline(&line_ptr, &line_len, stdin);
if (bytes_read == -1) {
DEBUG(SSSDBG_OP_FAILURE, "getline failed [%d]: %s.\n",
Expand All @@ -169,12 +214,13 @@ read_pin(char **pin)
/* Remove the end of line '\n' character */
line_ptr[--bytes_read] = '\0';
}
ERROR("\n");
printf("\n");

ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, &old);
if (ret != 0) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable to restore parameters associated with stdin.\n");
"Unable to restore parameters associated with stdin [%d]: %s.\n",
errno, sss_strerror(errno));
goto done;
}

Expand All @@ -189,26 +235,43 @@ errno_t
generate_credentials(struct passkey_data *data, fido_dev_t *dev,
fido_cred_t *cred)
{
TALLOC_CTX *tmp_ctx = NULL;
char *pin = NULL;
char *tmp_pin = NULL;
bool has_pin;
ssize_t pin_len = 0;
errno_t ret;

tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_new() failed.\n");
return ENOMEM;
}

has_pin = fido_dev_has_pin(dev);
if (has_pin == true) {
pin_len = read_pin(&pin);
if (pin_len == -1) {
ret = ERR_INPUT_PARSE;
goto done;
if (data->quiet == true) {
ret = passkey_recv_pin(tmp_ctx, STDIN_FILENO, &pin);
if (ret != EOK) {
goto done;
}
} else {
pin_len = read_pin(&tmp_pin);
if (pin_len == -1) {
ret = ERR_INPUT_PARSE;
goto done;
}
pin = talloc_strdup(tmp_ctx, tmp_pin);
sss_erase_mem_securely(tmp_pin, pin_len);
free(tmp_pin);
}
}

ERROR("Please touch the device.\n");
if (data->quiet == false) {
printf("Please touch the device.\n");
}
ret = fido_dev_make_cred(dev, cred, pin);
sss_erase_mem_securely(pin, pin_len);
if (pin != NULL) {
free(pin);
}

if (ret != FIDO_OK) {
if (ret == FIDO_ERR_PIN_INVALID) {
Expand All @@ -229,6 +292,8 @@ generate_credentials(struct passkey_data *data, fido_dev_t *dev,
}

done:
talloc_free(tmp_ctx);

return ret;
}

Expand Down
7 changes: 5 additions & 2 deletions src/tests/cmocka/test_passkey_child.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,6 @@ void test_parse_all_args(void **state)
argv[argc++] = "--authenticate";
argv[argc++] = "--username=user";
argv[argc++] = "--domain=test.com";
argv[argc++] = "--pin=123456";
argv[argc++] = "--public-key=publicKey";
argv[argc++] = "--key-handle=keyHandle";
argv[argc++] = "--type=rs256";
Expand All @@ -476,7 +475,6 @@ void test_parse_all_args(void **state)
assert_int_equal(data.action, ACTION_AUTHENTICATE);
assert_string_equal(data.shortname, "user");
assert_string_equal(data.domain, "test.com");
assert_string_equal(data.pin, "123456");
assert_string_equal(data.public_key_list[0], "publicKey");
assert_string_equal(data.key_handle_list[0], "keyHandle");
assert_int_equal(data.type, COSE_RS256);
Expand Down Expand Up @@ -639,6 +637,7 @@ void test_generate_credentials_user_verification(void **state)
struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
errno_t ret;

ts->data.quiet = false;
will_return(__wrap_fido_dev_has_pin, false);
will_return(__wrap_fido_dev_make_cred, FIDO_OK);

Expand All @@ -654,6 +653,7 @@ void test_generate_credentials_pin(void **state)
char *pin = malloc(test_len);
errno_t ret;

ts->data.quiet = false;
snprintf(pin, test_len, "%s\n", "1234");
will_return(__wrap_fido_dev_has_pin, true);
will_return(__wrap_tcgetattr, 0);
Expand All @@ -674,6 +674,7 @@ void test_generate_credentials_pin_error(void **state)
char *expected_pin;
errno_t ret;

ts->data.quiet = false;
will_return(__wrap_fido_dev_has_pin, true);
will_return(__wrap_tcgetattr, 0);
will_return(__wrap_tcsetattr, 0);
Expand Down Expand Up @@ -767,6 +768,7 @@ void test_register_key_integration(void **state)
data.domain = "test.com";
data.type = COSE_ES256;
data.user_verification = FIDO_OPT_FALSE;
data.quiet = false;
will_return(__wrap_fido_dev_info_manifest, FIDO_OK);
will_return(__wrap_fido_dev_info_manifest, 1);
will_return(__wrap_fido_dev_info_path, TEST_PATH);
Expand Down Expand Up @@ -1027,6 +1029,7 @@ void test_authenticate_integration(void **state)
data.keys_size = 1;
data.type = COSE_ES256;
data.user_verification = FIDO_OPT_FALSE;
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);
Expand Down

0 comments on commit 6b0d175

Please sign in to comment.