1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <errno.h>
4 #include <libcryptsetup.h>
5 
6 #include "cryptsetup-token.h"
7 #include "cryptsetup-token-util.h"
8 #include "hexdecoct.h"
9 #include "json.h"
10 #include "luks2-pkcs11.h"
11 #include "memory-util.h"
12 #include "pkcs11-util.h"
13 #include "version.h"
14 
15 #define TOKEN_NAME "systemd-pkcs11"
16 #define TOKEN_VERSION_MAJOR "1"
17 #define TOKEN_VERSION_MINOR "0"
18 
19 /* for libcryptsetup debug purpose */
cryptsetup_token_version(void)20 _public_ const char *cryptsetup_token_version(void) {
21         return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")";
22 }
23 
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)24 _public_ int cryptsetup_token_open_pin(
25                 struct crypt_device *cd, /* is always LUKS2 context */
26                 int token /* is always >= 0 */,
27                 const char *pin,
28                 size_t pin_size,
29                 char **password, /* freed by cryptsetup_token_buffer_free */
30                 size_t *password_len,
31                 void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
32 
33         const char *json;
34         int r;
35 
36         assert(!pin || pin_size);
37         assert(token >= 0);
38 
39         /* This must not fail at this moment (internal error) */
40         r = crypt_token_json_get(cd, token, &json);
41         assert(token == r);
42         assert(json);
43 
44         return acquire_luks2_key(cd, json, usrptr, pin, pin_size, password, password_len);
45 }
46 
47 /*
48  * This function is called from within following libcryptsetup calls
49  * provided conditions further below are met:
50  *
51  * crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-pkcs11'):
52  *
53  * - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
54  *   (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
55  *    and token is assigned to at least single keyslot).
56  *
57  * - if plugin defines validate function (see cryptsetup_token_validate below) it must have
58  *   passed the check (aka return 0)
59  */
cryptsetup_token_open(struct crypt_device * cd,int token,char ** password,size_t * password_len,void * usrptr)60 _public_ int cryptsetup_token_open(
61                 struct crypt_device *cd, /* is always LUKS2 context */
62                 int token /* is always >= 0 */,
63                 char **password, /* freed by cryptsetup_token_buffer_free */
64                 size_t *password_len,
65                 void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
66 
67         return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr);
68 }
69 
70 /*
71  * libcryptsetup callback for memory deallocation of 'password' parameter passed in
72  * any crypt_token_open_* plugin function
73  */
cryptsetup_token_buffer_free(void * buffer,size_t buffer_len)74 _public_ void cryptsetup_token_buffer_free(void *buffer, size_t buffer_len) {
75         erase_and_free(buffer);
76 }
77 
78 /*
79  * prints systemd-pkcs11 token content in crypt_dump().
80  * 'type' and 'keyslots' fields are printed by libcryptsetup
81  */
cryptsetup_token_dump(struct crypt_device * cd,const char * json)82 _public_ void cryptsetup_token_dump(
83                 struct crypt_device *cd /* is always LUKS2 context */,
84                 const char *json /* validated 'systemd-pkcs11' token if cryptsetup_token_validate is defined */) {
85 
86         int r;
87         size_t pkcs11_key_size;
88         _cleanup_free_ char *pkcs11_uri = NULL, *key_str = NULL;
89         _cleanup_free_ void *pkcs11_key = NULL;
90 
91         r = parse_luks2_pkcs11_data(cd, json, &pkcs11_uri, &pkcs11_key, &pkcs11_key_size);
92         if (r < 0)
93                 return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
94 
95         r = crypt_dump_buffer_to_hex_string(pkcs11_key, pkcs11_key_size, &key_str);
96         if (r < 0)
97                 return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
98 
99         crypt_log(cd, "\tpkcs11-uri: %s\n", pkcs11_uri);
100         crypt_log(cd, "\tpkcs11-key: %s\n", key_str);
101 }
102 
103 /*
104  * Note:
105  *   If plugin is available in library path, it's called in before following libcryptsetup calls:
106  *
107  *   crypt_token_json_set, crypt_dump, any crypt_activate_by_token_* flavour
108  */
cryptsetup_token_validate(struct crypt_device * cd,const char * json)109 _public_ int cryptsetup_token_validate(
110                 struct crypt_device *cd, /* is always LUKS2 context */
111                 const char *json /* contains valid 'type' and 'keyslots' fields. 'type' is 'systemd-pkcs11' */) {
112 
113         int r;
114         JsonVariant *w;
115         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
116 
117         r = json_parse(json, 0, &v, NULL, NULL);
118         if (r < 0)
119                 return crypt_log_debug_errno(cd, r, "Could not parse " TOKEN_NAME " json object: %m.");
120 
121         w = json_variant_by_key(v, "pkcs11-uri");
122         if (!w || !json_variant_is_string(w)) {
123                 crypt_log_debug(cd, "PKCS#11 token data lacks 'pkcs11-uri' field.");
124                 return 1;
125         }
126 
127         if (!pkcs11_uri_valid(json_variant_string(w))) {
128                 crypt_log_debug(cd, "PKCS#11 token data contains invalid PKCS#11 URI.");
129                 return 1;
130         }
131 
132         w = json_variant_by_key(v, "pkcs11-key");
133         if (!w || !json_variant_is_string(w)) {
134                 crypt_log_debug(cd, "PKCS#11 token data lacks 'pkcs11-key' field.");
135                 return 1;
136         }
137 
138         r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
139         if (r < 0)
140                 return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded key: %m.");
141 
142         return 0;
143 }
144