1
0
Fork 0
cryptsetup/tokens/ssh/libcryptsetup-token-ssh.c
Daniel Baumann 309c0fd158
Adding upstream version 2:2.7.5.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 10:45:47 +02:00

187 lines
5.5 KiB
C

// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* Example of LUKS2 ssh token handler (EXPERIMENTAL)
*
* Copyright (C) 2016-2024 Milan Broz
* Copyright (C) 2020-2024 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
*/
#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);
void cryptsetup_token_buffer_free(void *buffer, size_t buffer_len);
const char *cryptsetup_token_version(void)
{
return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR;
}
void cryptsetup_token_buffer_free(void *buffer, size_t buffer_len)
{
/* libcryptsetup API call */
crypt_safe_memzero(buffer, buffer_len);
free(buffer);
}
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;
}