ssh token: Add the token to the first keyslot with matching passphrase

Currently the "add" action adds the token to all keyslots, this
changes the behaviour to make sure the token is added to the first
keyslot that can be unlocked using the provided passphrase.
This commit is contained in:
Vojtech Trefny
2021-06-22 14:24:47 +02:00
parent 3e52aa820c
commit 6545523df3
3 changed files with 138 additions and 8 deletions

View File

@@ -129,6 +129,11 @@ bin_check sshpass
format format
echo -n "Adding SSH token: " echo -n "Adding SSH token: "
ssh_check
create_user
ssh_setup
$CRYPTSETUP_SSH add $LOOPDEV --ssh-server $SSH_SERVER --ssh-user $USER --ssh-path $SSH_PATH --ssh-keypath $SSH_KEY_PATH $CRYPTSETUP_SSH add $LOOPDEV --ssh-server $SSH_SERVER --ssh-user $USER --ssh-path $SSH_PATH --ssh-keypath $SSH_KEY_PATH
[ $? -ne 0 ] && fail "Failed to add SSH token to $LOOPDEV" [ $? -ne 0 ] && fail "Failed to add SSH token to $LOOPDEV"
@@ -137,9 +142,6 @@ check_dump "$out"
echo "[OK]" echo "[OK]"
echo -n "Activating using SSH token: " echo -n "Activating using SSH token: "
ssh_check
create_user
ssh_setup
$CRYPTSETUP luksOpen --token-only --disable-external-tokens -r $LOOPDEV $MAP && fail "Tokens should be disabled" $CRYPTSETUP luksOpen --token-only --disable-external-tokens -r $LOOPDEV $MAP && fail "Tokens should be disabled"
$CRYPTSETUP luksOpen -r $LOOPDEV $MAP -q >/dev/null 2>&1 <&- $CRYPTSETUP luksOpen -r $LOOPDEV $MAP -q >/dev/null 2>&1 <&-

View File

@@ -12,8 +12,16 @@ libcryptsetup_token_ssh_la_SOURCES = tokens/ssh/libcryptsetup-token-ssh.c \
libcryptsetup_token_ssh_la_LIBADD = -lssh libcryptsetup.la @JSON_C_LIBS@ libcryptsetup_token_ssh_la_LIBADD = -lssh libcryptsetup.la @JSON_C_LIBS@
lib_LTLIBRARIES += libcryptsetup-token-ssh.la lib_LTLIBRARIES += libcryptsetup-token-ssh.la
cryptsetup_ssh_SOURCES = tokens/ssh/cryptsetup-ssh.c tokens/ssh/ssh-utils.h cryptsetup_ssh_SOURCES = tokens/ssh/cryptsetup-ssh.c \
cryptsetup_ssh_LDADD = libcryptsetup.la @JSON_C_LIBS@ tokens/ssh/ssh-utils.c \
tokens/ssh/ssh-utils.h \
src/utils_tools.c \
src/utils_password.c \
lib/utils_io.c \
lib/utils_loop.c
cryptsetup_ssh_LDADD = -lssh -lm libcryptsetup.la @JSON_C_LIBS@ @POPT_LIBS@
cryptsetup_ssh_CFLAGS = $(AM_CFLAGS)
sbin_PROGRAMS += cryptsetup-ssh sbin_PROGRAMS += cryptsetup-ssh
endif endif

View File

@@ -29,7 +29,11 @@
#include <fcntl.h> #include <fcntl.h>
#include <argp.h> #include <argp.h>
#include <json-c/json.h> #include <json-c/json.h>
#include <termios.h>
#include <stdbool.h>
#include "libcryptsetup.h" #include "libcryptsetup.h"
#include "ssh-utils.h"
#include "../src/cryptsetup.h"
#define TOKEN_NAME "ssh" #define TOKEN_NAME "ssh"
@@ -43,12 +47,18 @@
#define OPT_DEBUG 5 #define OPT_DEBUG 5
#define OPT_DEBUG_JSON 6 #define OPT_DEBUG_JSON 6
void tools_cleanup(void)
{
}
static int token_add( static int token_add(
const char *device, const char *device,
const char *server, const char *server,
const char *user, const char *user,
const char *path, const char *path,
const char *keypath) const char *keypath,
int keyslot)
{ {
struct crypt_device *cd; struct crypt_device *cd;
@@ -99,7 +109,7 @@ static int token_add(
} }
token = r; token = r;
r = crypt_token_assign_keyslot(cd, token, CRYPT_ANY_SLOT); r = crypt_token_assign_keyslot(cd, token, keyslot);
if (r != token) { if (r != token) {
crypt_token_json_set(cd, token, NULL); crypt_token_json_set(cd, token, NULL);
r = -EINVAL; r = -EINVAL;
@@ -220,9 +230,112 @@ void _log(int level, const char *msg, void *usrptr)
} }
} }
static int get_keyslot_for_passphrase(struct arguments *arguments, const char *pin, int *keyslot)
{
int r = 0;
ssh_key pkey;
ssh_session ssh;
char *password = NULL;
size_t password_len = 0;
struct crypt_device *cd = NULL;
char *ssh_pass = NULL;
size_t key_size = 0;
char *prompt = NULL;
r = crypt_init(&cd, arguments->device);
if (r < 0)
return r;
crypt_set_log_callback(cd, &_log, arguments);
r = ssh_pki_import_privkey_file(arguments->ssh_keypath, pin, NULL, NULL, &pkey);
if (r != SSH_OK) {
if (r == SSH_EOF) {
crypt_log(cd, CRYPT_LOG_ERROR, "Failed to open and import private key:\n");
crypt_free(cd);
return -EINVAL;
} else {
_log(CRYPT_LOG_ERROR, "Failed to import private key (password protected?).\n", NULL);
r = asprintf(&prompt, "%s@%s's password: ", arguments->ssh_user, arguments->ssh_server);
if (r < 0) {
crypt_safe_free(ssh_pass);
crypt_free(cd);
return -EINVAL;
}
r = tools_get_key(prompt, &ssh_pass, &key_size, 0, 0, NULL, 0, 0, 0, cd);
if (r < 0) {
free(prompt);
crypt_safe_free(ssh_pass);
crypt_free(cd);
return -EINVAL;
}
/* now try again with the password */
r = get_keyslot_for_passphrase(arguments, ssh_pass, keyslot);
crypt_safe_free(ssh_pass);
crypt_free(cd);
free(prompt);
return r;
}
}
ssh = sshplugin_session_init(cd, arguments->ssh_server, arguments->ssh_user);
if (!ssh) {
ssh_key_free(pkey);
crypt_free(cd);
return -EINVAL;
}
r = sshplugin_public_key_auth(cd, ssh, pkey);
ssh_key_free(pkey);
if (r != SSH_AUTH_SUCCESS) {
crypt_free(cd);
return r;
}
r = sshplugin_download_password(cd, ssh, arguments->ssh_path, &password, &password_len);
if (r < 0) {
ssh_disconnect(ssh);
ssh_free(ssh);
crypt_free(cd);
return r;
}
ssh_disconnect(ssh);
ssh_free(ssh);
r = crypt_load(cd, CRYPT_LUKS2, NULL);
if (r < 0) {
crypt_safe_memzero(password, password_len);
free(password);
crypt_free(cd);
return r;
}
r = crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, password, password_len, 0);
if (r < 0) {
crypt_safe_memzero(password, password_len);
free(password);
crypt_free(cd);
return r;
}
*keyslot = r;
crypt_safe_memzero(password, password_len);
free(password);
crypt_free(cd);
return 0;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int ret = 0; int ret = 0;
int keyslot = 0;
struct arguments arguments = { 0 }; struct arguments arguments = { 0 };
ret = argp_parse (&argp, argc, argv, 0, 0, &arguments); ret = argp_parse (&argp, argc, argv, 0, 0, &arguments);
@@ -268,11 +381,18 @@ int main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
ret = get_keyslot_for_passphrase(&arguments, NULL, &keyslot);
if (ret != 0) {
printf("Failed open %s using provided credentials.\n", arguments.device);
return EXIT_FAILURE;
}
return token_add(arguments.device, return token_add(arguments.device,
arguments.ssh_server, arguments.ssh_server,
arguments.ssh_user, arguments.ssh_user,
arguments.ssh_path, arguments.ssh_path,
arguments.ssh_keypath); arguments.ssh_keypath,
keyslot);
} else { } else {
printf("Only 'add' action is currently supported by this plugin.\n"); printf("Only 'add' action is currently supported by this plugin.\n");
return EXIT_FAILURE; return EXIT_FAILURE;