1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "ask-password-api.h"
6 #include "cryptenroll-fido2.h"
7 #include "cryptenroll-list.h"
8 #include "cryptenroll-password.h"
9 #include "cryptenroll-pkcs11.h"
10 #include "cryptenroll-recovery.h"
11 #include "cryptenroll-tpm2.h"
12 #include "cryptenroll-wipe.h"
13 #include "cryptenroll.h"
14 #include "cryptsetup-util.h"
16 #include "libfido2-util.h"
17 #include "main-func.h"
18 #include "memory-util.h"
19 #include "parse-argument.h"
20 #include "parse-util.h"
21 #include "path-util.h"
22 #include "pkcs11-util.h"
23 #include "pretty-print.h"
24 #include "string-table.h"
26 #include "terminal-util.h"
27 #include "tpm2-util.h"
29 static EnrollType arg_enroll_type
= _ENROLL_TYPE_INVALID
;
30 static char *arg_pkcs11_token_uri
= NULL
;
31 static char *arg_fido2_device
= NULL
;
32 static char *arg_tpm2_device
= NULL
;
33 static uint32_t arg_tpm2_pcr_mask
= UINT32_MAX
;
34 static char *arg_node
= NULL
;
35 static int *arg_wipe_slots
= NULL
;
36 static size_t arg_n_wipe_slots
= 0;
37 static WipeScope arg_wipe_slots_scope
= WIPE_EXPLICIT
;
38 static unsigned arg_wipe_slots_mask
= 0; /* Bitmask of (1U << EnrollType), for wiping all slots of specific types */
40 assert_cc(sizeof(arg_wipe_slots_mask
) * 8 >= _ENROLL_TYPE_MAX
);
42 STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri
, freep
);
43 STATIC_DESTRUCTOR_REGISTER(arg_fido2_device
, freep
);
44 STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device
, freep
);
45 STATIC_DESTRUCTOR_REGISTER(arg_node
, freep
);
47 static bool wipe_requested(void) {
48 return arg_n_wipe_slots
> 0 ||
49 arg_wipe_slots_scope
!= WIPE_EXPLICIT
||
50 arg_wipe_slots_mask
!= 0;
53 static const char* const enroll_type_table
[_ENROLL_TYPE_MAX
] = {
54 [ENROLL_PASSWORD
] = "password",
55 [ENROLL_RECOVERY
] = "recovery",
56 [ENROLL_PKCS11
] = "pkcs11",
57 [ENROLL_FIDO2
] = "fido2",
58 [ENROLL_TPM2
] = "tpm2",
61 DEFINE_STRING_TABLE_LOOKUP(enroll_type
, EnrollType
);
63 static const char *const luks2_token_type_table
[_ENROLL_TYPE_MAX
] = {
64 /* ENROLL_PASSWORD has no entry here, as slots of this type do not have a token in the LUKS2 header */
65 [ENROLL_RECOVERY
] = "systemd-recovery",
66 [ENROLL_PKCS11
] = "systemd-pkcs11",
67 [ENROLL_FIDO2
] = "systemd-fido2",
68 [ENROLL_TPM2
] = "systemd-tpm2",
71 DEFINE_STRING_TABLE_LOOKUP(luks2_token_type
, EnrollType
);
73 static int help(void) {
74 _cleanup_free_
char *link
= NULL
;
77 r
= terminal_urlify_man("systemd-cryptenroll", "1", &link
);
81 printf("%s [OPTIONS...] BLOCK-DEVICE\n"
82 "\n%sEnroll a security token or authentication credential to a LUKS volume.%s\n\n"
83 " -h --help Show this help\n"
84 " --version Show package version\n"
85 " --password Enroll a user-supplied password\n"
86 " --recovery-key Enroll a recovery key\n"
87 " --pkcs11-token-uri=URI\n"
88 " Specify PKCS#11 security token URI\n"
89 " --fido2-device=PATH\n"
90 " Enroll a FIDO2-HMAC security token\n"
91 " --tpm2-device=PATH\n"
92 " Enroll a TPM2 device\n"
93 " --tpm2-pcrs=PCR1,PCR2,PCR3,…\n"
94 " Specify TPM2 PCRs to seal against\n"
95 " --wipe-slot=SLOT1,SLOT2,…\n"
96 " Wipe specified slots\n"
97 "\nSee the %s for details.\n",
98 program_invocation_short_name
,
106 static int parse_argv(int argc
, char *argv
[]) {
112 ARG_PKCS11_TOKEN_URI
,
119 static const struct option options
[] = {
120 { "help", no_argument
, NULL
, 'h' },
121 { "version", no_argument
, NULL
, ARG_VERSION
},
122 { "password", no_argument
, NULL
, ARG_PASSWORD
},
123 { "recovery-key", no_argument
, NULL
, ARG_RECOVERY_KEY
},
124 { "pkcs11-token-uri", required_argument
, NULL
, ARG_PKCS11_TOKEN_URI
},
125 { "fido2-device", required_argument
, NULL
, ARG_FIDO2_DEVICE
},
126 { "tpm2-device", required_argument
, NULL
, ARG_TPM2_DEVICE
},
127 { "tpm2-pcrs", required_argument
, NULL
, ARG_TPM2_PCRS
},
128 { "wipe-slot", required_argument
, NULL
, ARG_WIPE_SLOT
},
137 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0) {
148 if (arg_enroll_type
>= 0)
149 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
150 "Multiple operations specified at once, refusing.");
152 arg_enroll_type
= ENROLL_PASSWORD
;
155 case ARG_RECOVERY_KEY
:
156 if (arg_enroll_type
>= 0)
157 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
158 "Multiple operations specified at once, refusing.");
160 arg_enroll_type
= ENROLL_RECOVERY
;
163 case ARG_PKCS11_TOKEN_URI
: {
164 _cleanup_free_
char *uri
= NULL
;
166 if (streq(optarg
, "list"))
167 return pkcs11_list_tokens();
169 if (arg_enroll_type
>= 0 || arg_pkcs11_token_uri
)
170 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
171 "Multiple operations specified at once, refusing.");
173 if (streq(optarg
, "auto")) {
174 r
= pkcs11_find_token_auto(&uri
);
178 if (!pkcs11_uri_valid(optarg
))
179 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Not a valid PKCS#11 URI: %s", optarg
);
181 uri
= strdup(optarg
);
186 arg_enroll_type
= ENROLL_PKCS11
;
187 arg_pkcs11_token_uri
= TAKE_PTR(uri
);
191 case ARG_FIDO2_DEVICE
: {
192 _cleanup_free_
char *device
= NULL
;
194 if (streq(optarg
, "list"))
195 return fido2_list_devices();
197 if (arg_enroll_type
>= 0 || arg_fido2_device
)
198 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
199 "Multiple operations specified at once, refusing.");
201 if (streq(optarg
, "auto")) {
202 r
= fido2_find_device_auto(&device
);
206 device
= strdup(optarg
);
211 arg_enroll_type
= ENROLL_FIDO2
;
212 arg_fido2_device
= TAKE_PTR(device
);
216 case ARG_TPM2_DEVICE
: {
217 _cleanup_free_
char *device
= NULL
;
219 if (streq(optarg
, "list"))
220 return tpm2_list_devices();
222 if (arg_enroll_type
>= 0 || arg_tpm2_device
)
223 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
224 "Multiple operations specified at once, refusing.");
226 if (!streq(optarg
, "auto")) {
227 device
= strdup(optarg
);
232 arg_enroll_type
= ENROLL_TPM2
;
233 arg_tpm2_device
= TAKE_PTR(device
);
237 case ARG_TPM2_PCRS
: {
240 if (isempty(optarg
)) {
241 arg_tpm2_pcr_mask
= 0;
245 r
= tpm2_parse_pcrs(optarg
, &mask
);
249 if (arg_tpm2_pcr_mask
== UINT32_MAX
)
250 arg_tpm2_pcr_mask
= mask
;
252 arg_tpm2_pcr_mask
|= mask
;
257 case ARG_WIPE_SLOT
: {
258 const char *p
= optarg
;
260 if (isempty(optarg
)) {
261 arg_wipe_slots_mask
= 0;
262 arg_wipe_slots_scope
= WIPE_EXPLICIT
;
267 _cleanup_free_
char *slot
= NULL
;
270 r
= extract_first_word(&p
, &slot
, ",", EXTRACT_DONT_COALESCE_SEPARATORS
);
274 return log_error_errno(r
, "Failed to parse slot list: %s", optarg
);
276 if (streq(slot
, "all"))
277 arg_wipe_slots_scope
= WIPE_ALL
;
278 else if (streq(slot
, "empty")) {
279 if (arg_wipe_slots_scope
!= WIPE_ALL
) /* if "all" was specified before, that wins */
280 arg_wipe_slots_scope
= WIPE_EMPTY_PASSPHRASE
;
281 } else if (streq(slot
, "password"))
282 arg_wipe_slots_mask
= 1U << ENROLL_PASSWORD
;
283 else if (streq(slot
, "recovery"))
284 arg_wipe_slots_mask
= 1U << ENROLL_RECOVERY
;
285 else if (streq(slot
, "pkcs11"))
286 arg_wipe_slots_mask
= 1U << ENROLL_PKCS11
;
287 else if (streq(slot
, "fido2"))
288 arg_wipe_slots_mask
= 1U << ENROLL_FIDO2
;
289 else if (streq(slot
, "tpm2"))
290 arg_wipe_slots_mask
= 1U << ENROLL_TPM2
;
294 r
= safe_atou(slot
, &n
);
296 return log_error_errno(r
, "Failed to parse slot index: %s", slot
);
298 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
), "Slot index out of range: %u", n
);
300 a
= reallocarray(arg_wipe_slots
, sizeof(int), arg_n_wipe_slots
+ 1);
305 arg_wipe_slots
[arg_n_wipe_slots
++] = (int) n
;
315 assert_not_reached("Unhandled option");
320 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
321 "No block device node specified, refusing.");
324 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
325 "Too many arguments, refusing.");
327 r
= parse_path_argument(argv
[optind
], false, &arg_node
);
331 if (arg_tpm2_pcr_mask
== UINT32_MAX
)
332 arg_tpm2_pcr_mask
= TPM2_PCR_MASK_DEFAULT
;
337 static int prepare_luks(
338 struct crypt_device
**ret_cd
,
339 void **ret_volume_key
,
340 size_t *ret_volume_key_size
) {
342 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
343 _cleanup_(erase_and_freep
) void *vk
= NULL
;
349 assert(!ret_volume_key
== !ret_volume_key_size
);
351 r
= crypt_init(&cd
, arg_node
);
353 return log_error_errno(r
, "Failed to allocate libcryptsetup context: %m");
355 cryptsetup_enable_logging(cd
);
357 r
= crypt_load(cd
, CRYPT_LUKS2
, NULL
);
359 return log_error_errno(r
, "Failed to load LUKS2 superblock: %m");
361 if (!ret_volume_key
) {
362 *ret_cd
= TAKE_PTR(cd
);
366 r
= crypt_get_volume_key_size(cd
);
368 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to determine LUKS volume key size");
375 e
= getenv("PASSWORD");
377 _cleanup_(erase_and_freep
) char *password
= NULL
;
379 password
= strdup(e
);
384 assert_se(unsetenv("PASSWORD") >= 0);
386 r
= crypt_volume_key_get(
394 return log_error_errno(r
, "Password from environment variable $PASSWORD did not work.");
396 AskPasswordFlags ask_password_flags
= ASK_PASSWORD_PUSH_CACHE
|ASK_PASSWORD_ACCEPT_CACHED
;
397 _cleanup_free_
char *question
= NULL
, *disk_path
= NULL
;
401 question
= strjoin("Please enter current passphrase for disk ", arg_node
, ":");
405 disk_path
= cescape(arg_node
);
409 id
= strjoina("cryptsetup:", disk_path
);
412 _cleanup_strv_free_erase_
char **passwords
= NULL
;
416 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY
),
417 "Too many attempts, giving up:");
419 r
= ask_password_auto(
420 question
, "drive-harddisk", id
, "cryptenroll", "cryptenroll.passphrase", USEC_INFINITY
,
424 return log_error_errno(r
, "Failed to query password: %m");
427 STRV_FOREACH(p
, passwords
) {
428 r
= crypt_volume_key_get(
441 log_error_errno(r
, "Password not correct, please try again.");
442 ask_password_flags
&= ~ASK_PASSWORD_ACCEPT_CACHED
;
446 *ret_cd
= TAKE_PTR(cd
);
447 *ret_volume_key
= TAKE_PTR(vk
);
448 *ret_volume_key_size
= vks
;
453 static int run(int argc
, char *argv
[]) {
454 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
455 _cleanup_(erase_and_freep
) void *vk
= NULL
;
459 log_show_color(true);
460 log_parse_environment();
463 r
= parse_argv(argc
, argv
);
467 if (arg_enroll_type
< 0)
468 r
= prepare_luks(&cd
, NULL
, NULL
); /* No need to unlock device if we don't need the volume key because we don't need to enroll anything */
470 r
= prepare_luks(&cd
, &vk
, &vks
);
474 switch (arg_enroll_type
) {
476 case ENROLL_PASSWORD
:
477 slot
= enroll_password(cd
, vk
, vks
);
480 case ENROLL_RECOVERY
:
481 slot
= enroll_recovery(cd
, vk
, vks
);
485 slot
= enroll_pkcs11(cd
, vk
, vks
, arg_pkcs11_token_uri
);
489 slot
= enroll_fido2(cd
, vk
, vks
, arg_fido2_device
);
493 slot
= enroll_tpm2(cd
, vk
, vks
, arg_tpm2_device
, arg_tpm2_pcr_mask
);
496 case _ENROLL_TYPE_INVALID
:
497 /* List enrolled slots if we are called without anything to enroll or wipe */
498 if (!wipe_requested())
499 return list_enrolled(cd
);
501 /* Only slot wiping selected */
502 return wipe_slots(cd
, arg_wipe_slots
, arg_n_wipe_slots
, arg_wipe_slots_scope
, arg_wipe_slots_mask
, -1);
505 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Operation not implemented yet.");
510 /* After we completed enrolling, remove user selected slots */
511 r
= wipe_slots(cd
, arg_wipe_slots
, arg_n_wipe_slots
, arg_wipe_slots_scope
, arg_wipe_slots_mask
, slot
);
518 DEFINE_MAIN_FUNCTION(run
);