Imported Upstream version 2.6.1
[platform/upstream/cryptsetup.git] / tokens / ssh / libcryptsetup-token-ssh.c
1 /*
2  * Example of LUKS2 ssh token handler (EXPERIMENTAL)
3  *
4  * Copyright (C) 2016-2023 Milan Broz
5  * Copyright (C) 2020-2023 Vojtech Trefny
6  *
7  * Use:
8  *  - generate LUKS device
9  *  - store passphrase used in previous step remotely (single line w/o \r\n)
10  *  - add new token using this example
11  *  - activate device by token
12  *
13  * This file is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This file is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this file; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <json-c/json.h>
33 #include "libcryptsetup.h"
34 #include "ssh-utils.h"
35
36 #define TOKEN_NAME "ssh"
37 #define TOKEN_VERSION_MAJOR "1"
38 #define TOKEN_VERSION_MINOR "0"
39
40 #define SERVER_ARG      "plugin-ssh-server"
41 #define USER_ARG        "plugin-ssh-user"
42 #define PATH_ARG        "plugin-ssh-path"
43 #define KEYPATH_ARG     "plugin-ssh-keypath"
44
45 #define l_dbg(cd, x...) crypt_logf(cd, CRYPT_LOG_DEBUG, x)
46
47
48 const char *cryptsetup_token_version(void);
49 int cryptsetup_token_open_pin(struct crypt_device *cd, int token, const char *pin,
50         size_t pin_size, char **password, size_t *password_len, void *usrptr);
51 int cryptsetup_token_open(struct crypt_device *cd, int token,
52         char **password, size_t *password_len, void *usrptr);
53 void cryptsetup_token_dump(struct crypt_device *cd, const char *json);
54 int cryptsetup_token_validate(struct crypt_device *cd, const char *json);
55
56
57 const char *cryptsetup_token_version(void)
58 {
59         return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR;
60 }
61
62 static json_object *get_token_jobj(struct crypt_device *cd, int token)
63 {
64         const char *json_slot;
65
66         /* libcryptsetup API call */
67         if (crypt_token_json_get(cd, token, &json_slot))
68                 return NULL;
69
70         return json_tokener_parse(json_slot);
71 }
72
73 int cryptsetup_token_open_pin(struct crypt_device *cd, int token, const char *pin,
74         size_t pin_size __attribute__((unused)), char **password, size_t *password_len,
75         void *usrptr __attribute__((unused)))
76 {
77         int r;
78         json_object *jobj_server, *jobj_user, *jobj_path, *jobj_token, *jobj_keypath;
79         ssh_key pkey;
80         ssh_session ssh;
81
82         jobj_token = get_token_jobj(cd, token);
83         if (!jobj_token)
84                 return -ENOMEM;
85
86         json_object_object_get_ex(jobj_token, "ssh_server", &jobj_server);
87         json_object_object_get_ex(jobj_token, "ssh_user",   &jobj_user);
88         json_object_object_get_ex(jobj_token, "ssh_path",   &jobj_path);
89         json_object_object_get_ex(jobj_token, "ssh_keypath",&jobj_keypath);
90
91         r = ssh_pki_import_privkey_file(json_object_get_string(jobj_keypath), pin, NULL, NULL, &pkey);
92         if (r != SSH_OK) {
93                 json_object_put(jobj_token);
94                 if (r == SSH_EOF) {
95                         crypt_log(cd, CRYPT_LOG_ERROR, "Failed to open and import private key.\n");
96                         return -EINVAL;
97                 }
98                 crypt_log(cd, CRYPT_LOG_ERROR, "Failed to import private key (password protected?).\n");
99                 return -EAGAIN;
100         }
101
102         ssh = sshplugin_session_init(cd, json_object_get_string(jobj_server),
103                                    json_object_get_string(jobj_user));
104         if (!ssh) {
105                 json_object_put(jobj_token);
106                 ssh_key_free(pkey);
107                 return -EINVAL;
108         }
109
110         r = sshplugin_public_key_auth(cd, ssh, pkey);
111         ssh_key_free(pkey);
112
113         if (r == SSH_AUTH_SUCCESS)
114                 r = sshplugin_download_password(cd, ssh, json_object_get_string(jobj_path),
115                                               password, password_len);
116
117         ssh_disconnect(ssh);
118         ssh_free(ssh);
119         json_object_put(jobj_token);
120
121         return r ? -EINVAL : r;
122 }
123
124 int cryptsetup_token_open(struct crypt_device *cd, int token,
125         char **password, size_t *password_len, void *usrptr)
126 {
127         return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr);
128 }
129
130 void cryptsetup_token_dump(struct crypt_device *cd, const char *json)
131 {
132         json_object *jobj_token, *jobj_server, *jobj_user, *jobj_path, *jobj_keypath;
133         char buf[4096];
134
135         jobj_token = json_tokener_parse(json);
136         if (!jobj_token)
137                 return;
138
139         json_object_object_get_ex(jobj_token, "ssh_server", &jobj_server);
140         json_object_object_get_ex(jobj_token, "ssh_user",   &jobj_user);
141         json_object_object_get_ex(jobj_token, "ssh_path",   &jobj_path);
142         json_object_object_get_ex(jobj_token, "ssh_keypath",&jobj_keypath);
143
144         if (snprintf(buf, sizeof(buf) - 1, "\tssh_server: %s\n\tssh_user: %s\n"
145             "\tssh_path: %s\n\tssh_key_path: %s\n",
146             json_object_get_string(jobj_server),
147             json_object_get_string(jobj_user),
148             json_object_get_string(jobj_path),
149             json_object_get_string(jobj_keypath)) > 0)
150                 crypt_log(cd, CRYPT_LOG_NORMAL, buf);
151
152         json_object_put(jobj_token);
153 }
154
155 int cryptsetup_token_validate(struct crypt_device *cd, const char *json)
156 {
157         enum json_tokener_error jerr;
158         json_object *jobj_token, *jobj;
159         int r = -EINVAL;
160
161         jobj_token = json_tokener_parse_verbose(json, &jerr);
162         if (!jobj_token)
163                 return -EINVAL;
164
165         if (!json_object_object_get_ex(jobj_token, "ssh_server", &jobj) ||
166             !json_object_is_type(jobj, json_type_string)) {
167                 l_dbg(cd, "ssh_server element is missing or not string.");
168                 goto out;
169         }
170
171         if (!json_object_object_get_ex(jobj_token, "ssh_user", &jobj) ||
172             !json_object_is_type(jobj, json_type_string)) {
173                 l_dbg(cd, "ssh_user element is missing or not string.");
174                 goto out;
175         }
176
177         if (!json_object_object_get_ex(jobj_token, "ssh_path", &jobj) ||
178             !json_object_is_type(jobj, json_type_string)) {
179                 l_dbg(cd, "ssh_path element is missing or not string.");
180                 goto out;
181         }
182
183         if (!json_object_object_get_ex(jobj_token, "ssh_keypath", &jobj) ||
184             !json_object_is_type(jobj, json_type_string)) {
185                 l_dbg(cd, "ssh_keypath element is missing or not string.");
186                 goto out;
187         }
188
189         r = 0;
190 out:
191         json_object_put(jobj_token);
192         return r;
193 }