187 lines
5.5 KiB
C
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;
|
|
}
|