diff options
Diffstat (limited to 'tokens/ssh/libcryptsetup-token-ssh.c')
-rw-r--r-- | tokens/ssh/libcryptsetup-token-ssh.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/tokens/ssh/libcryptsetup-token-ssh.c b/tokens/ssh/libcryptsetup-token-ssh.c new file mode 100644 index 0000000..639b25d --- /dev/null +++ b/tokens/ssh/libcryptsetup-token-ssh.c @@ -0,0 +1,193 @@ +/* + * Example of LUKS2 ssh token handler (EXPERIMENTAL) + * + * Copyright (C) 2016-2023 Milan Broz + * Copyright (C) 2020-2023 Vojtech Trefny + * + * Use: + * - generate LUKS device + * - store passphrase used in previous step remotely (single line w/o \r\n) + * - add new token using this example + * - activate device by token + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This file 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <json-c/json.h> +#include "libcryptsetup.h" +#include "ssh-utils.h" + +#define TOKEN_NAME "ssh" +#define TOKEN_VERSION_MAJOR "1" +#define TOKEN_VERSION_MINOR "0" + +#define SERVER_ARG "plugin-ssh-server" +#define USER_ARG "plugin-ssh-user" +#define PATH_ARG "plugin-ssh-path" +#define KEYPATH_ARG "plugin-ssh-keypath" + +#define l_dbg(cd, x...) crypt_logf(cd, CRYPT_LOG_DEBUG, x) + + +const char *cryptsetup_token_version(void); +int cryptsetup_token_open_pin(struct crypt_device *cd, int token, const char *pin, + size_t pin_size, char **password, size_t *password_len, void *usrptr); +int cryptsetup_token_open(struct crypt_device *cd, int token, + char **password, size_t *password_len, void *usrptr); +void cryptsetup_token_dump(struct crypt_device *cd, const char *json); +int cryptsetup_token_validate(struct crypt_device *cd, const char *json); + + +const char *cryptsetup_token_version(void) +{ + return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR; +} + +static json_object *get_token_jobj(struct crypt_device *cd, int token) +{ + const char *json_slot; + + /* libcryptsetup API call */ + if (crypt_token_json_get(cd, token, &json_slot)) + return NULL; + + return json_tokener_parse(json_slot); +} + +int cryptsetup_token_open_pin(struct crypt_device *cd, int token, const char *pin, + size_t pin_size __attribute__((unused)), char **password, size_t *password_len, + void *usrptr __attribute__((unused))) +{ + int r; + json_object *jobj_server, *jobj_user, *jobj_path, *jobj_token, *jobj_keypath; + ssh_key pkey; + ssh_session ssh; + + jobj_token = get_token_jobj(cd, token); + if (!jobj_token) + return -ENOMEM; + + json_object_object_get_ex(jobj_token, "ssh_server", &jobj_server); + json_object_object_get_ex(jobj_token, "ssh_user", &jobj_user); + json_object_object_get_ex(jobj_token, "ssh_path", &jobj_path); + json_object_object_get_ex(jobj_token, "ssh_keypath",&jobj_keypath); + + r = ssh_pki_import_privkey_file(json_object_get_string(jobj_keypath), pin, NULL, NULL, &pkey); + if (r != SSH_OK) { + json_object_put(jobj_token); + if (r == SSH_EOF) { + crypt_log(cd, CRYPT_LOG_ERROR, "Failed to open and import private key.\n"); + return -EINVAL; + } + crypt_log(cd, CRYPT_LOG_ERROR, "Failed to import private key (password protected?).\n"); + return -EAGAIN; + } + + ssh = sshplugin_session_init(cd, json_object_get_string(jobj_server), + json_object_get_string(jobj_user)); + if (!ssh) { + json_object_put(jobj_token); + ssh_key_free(pkey); + return -EINVAL; + } + + r = sshplugin_public_key_auth(cd, ssh, pkey); + ssh_key_free(pkey); + + if (r == SSH_AUTH_SUCCESS) + r = sshplugin_download_password(cd, ssh, json_object_get_string(jobj_path), + password, password_len); + + ssh_disconnect(ssh); + ssh_free(ssh); + json_object_put(jobj_token); + + return r ? -EINVAL : r; +} + +int cryptsetup_token_open(struct crypt_device *cd, int token, + char **password, size_t *password_len, void *usrptr) +{ + return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr); +} + +void cryptsetup_token_dump(struct crypt_device *cd, const char *json) +{ + json_object *jobj_token, *jobj_server, *jobj_user, *jobj_path, *jobj_keypath; + char buf[4096]; + + jobj_token = json_tokener_parse(json); + if (!jobj_token) + return; + + json_object_object_get_ex(jobj_token, "ssh_server", &jobj_server); + json_object_object_get_ex(jobj_token, "ssh_user", &jobj_user); + json_object_object_get_ex(jobj_token, "ssh_path", &jobj_path); + json_object_object_get_ex(jobj_token, "ssh_keypath",&jobj_keypath); + + if (snprintf(buf, sizeof(buf) - 1, "\tssh_server: %s\n\tssh_user: %s\n" + "\tssh_path: %s\n\tssh_key_path: %s\n", + json_object_get_string(jobj_server), + json_object_get_string(jobj_user), + json_object_get_string(jobj_path), + json_object_get_string(jobj_keypath)) > 0) + crypt_log(cd, CRYPT_LOG_NORMAL, buf); + + json_object_put(jobj_token); +} + +int cryptsetup_token_validate(struct crypt_device *cd, const char *json) +{ + enum json_tokener_error jerr; + json_object *jobj_token, *jobj; + int r = -EINVAL; + + jobj_token = json_tokener_parse_verbose(json, &jerr); + if (!jobj_token) + return -EINVAL; + + if (!json_object_object_get_ex(jobj_token, "ssh_server", &jobj) || + !json_object_is_type(jobj, json_type_string)) { + l_dbg(cd, "ssh_server element is missing or not string."); + goto out; + } + + if (!json_object_object_get_ex(jobj_token, "ssh_user", &jobj) || + !json_object_is_type(jobj, json_type_string)) { + l_dbg(cd, "ssh_user element is missing or not string."); + goto out; + } + + if (!json_object_object_get_ex(jobj_token, "ssh_path", &jobj) || + !json_object_is_type(jobj, json_type_string)) { + l_dbg(cd, "ssh_path element is missing or not string."); + goto out; + } + + if (!json_object_object_get_ex(jobj_token, "ssh_keypath", &jobj) || + !json_object_is_type(jobj, json_type_string)) { + l_dbg(cd, "ssh_keypath element is missing or not string."); + goto out; + } + + r = 0; +out: + json_object_put(jobj_token); + return r; +} |