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"
17 #include "libfido2-util.h"
18 #include "main-func.h"
19 #include "memory-util.h"
20 #include "parse-argument.h"
21 #include "parse-util.h"
22 #include "path-util.h"
23 #include "pkcs11-util.h"
24 #include "pretty-print.h"
25 #include "string-table.h"
27 #include "terminal-util.h"
28 #include "tpm2-util.h"
30 static EnrollType arg_enroll_type
= _ENROLL_TYPE_INVALID
;
31 static char *arg_pkcs11_token_uri
= NULL
;
32 static char *arg_fido2_device
= NULL
;
33 static char *arg_tpm2_device
= NULL
;
34 static uint32_t arg_tpm2_pcr_mask
= UINT32_MAX
;
35 static bool arg_tpm2_pin
= false;
36 static char *arg_node
= NULL
;
37 static int *arg_wipe_slots
= NULL
;
38 static size_t arg_n_wipe_slots
= 0;
39 static WipeScope arg_wipe_slots_scope
= WIPE_EXPLICIT
;
40 static unsigned arg_wipe_slots_mask
= 0; /* Bitmask of (1U << EnrollType), for wiping all slots of specific types */
41 static Fido2EnrollFlags arg_fido2_lock_with
= FIDO2ENROLL_PIN
| FIDO2ENROLL_UP
;
43 assert_cc(sizeof(arg_wipe_slots_mask
) * 8 >= _ENROLL_TYPE_MAX
);
45 STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri
, freep
);
46 STATIC_DESTRUCTOR_REGISTER(arg_fido2_device
, freep
);
47 STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device
, freep
);
48 STATIC_DESTRUCTOR_REGISTER(arg_node
, freep
);
50 static bool wipe_requested(void) {
51 return arg_n_wipe_slots
> 0 ||
52 arg_wipe_slots_scope
!= WIPE_EXPLICIT
||
53 arg_wipe_slots_mask
!= 0;
56 static const char* const enroll_type_table
[_ENROLL_TYPE_MAX
] = {
57 [ENROLL_PASSWORD
] = "password",
58 [ENROLL_RECOVERY
] = "recovery",
59 [ENROLL_PKCS11
] = "pkcs11",
60 [ENROLL_FIDO2
] = "fido2",
61 [ENROLL_TPM2
] = "tpm2",
64 DEFINE_STRING_TABLE_LOOKUP(enroll_type
, EnrollType
);
66 static const char *const luks2_token_type_table
[_ENROLL_TYPE_MAX
] = {
67 /* ENROLL_PASSWORD has no entry here, as slots of this type do not have a token in the LUKS2 header */
68 [ENROLL_RECOVERY
] = "systemd-recovery",
69 [ENROLL_PKCS11
] = "systemd-pkcs11",
70 [ENROLL_FIDO2
] = "systemd-fido2",
71 [ENROLL_TPM2
] = "systemd-tpm2",
74 DEFINE_STRING_TABLE_LOOKUP(luks2_token_type
, EnrollType
);
76 static int help(void) {
77 _cleanup_free_
char *link
= NULL
;
80 r
= terminal_urlify_man("systemd-cryptenroll", "1", &link
);
84 printf("%s [OPTIONS...] BLOCK-DEVICE\n"
85 "\n%sEnroll a security token or authentication credential to a LUKS volume.%s\n\n"
86 " -h --help Show this help\n"
87 " --version Show package version\n"
88 " --password Enroll a user-supplied password\n"
89 " --recovery-key Enroll a recovery key\n"
90 " --pkcs11-token-uri=URI\n"
91 " Specify PKCS#11 security token URI\n"
92 " --fido2-device=PATH\n"
93 " Enroll a FIDO2-HMAC security token\n"
94 " --fido2-with-client-pin=BOOL\n"
95 " Whether to require entering a PIN to unlock the volume\n"
96 " --fido2-with-user-presence=BOOL\n"
97 " Whether to require user presence to unlock the volume\n"
98 " --fido2-with-user-verification=BOOL\n"
99 " Whether to require user verification to unlock the volume\n"
100 " --tpm2-device=PATH\n"
101 " Enroll a TPM2 device\n"
102 " --tpm2-pcrs=PCR1+PCR2+PCR3+…\n"
103 " Specify TPM2 PCRs to seal against\n"
104 " --tpm2-with-pin=BOOL\n"
105 " Whether to require entering a PIN to unlock the volume\n"
106 " --wipe-slot=SLOT1,SLOT2,…\n"
107 " Wipe specified slots\n"
108 "\nSee the %s for details.\n",
109 program_invocation_short_name
,
117 static int parse_argv(int argc
, char *argv
[]) {
123 ARG_PKCS11_TOKEN_URI
,
134 static const struct option options
[] = {
135 { "help", no_argument
, NULL
, 'h' },
136 { "version", no_argument
, NULL
, ARG_VERSION
},
137 { "password", no_argument
, NULL
, ARG_PASSWORD
},
138 { "recovery-key", no_argument
, NULL
, ARG_RECOVERY_KEY
},
139 { "pkcs11-token-uri", required_argument
, NULL
, ARG_PKCS11_TOKEN_URI
},
140 { "fido2-device", required_argument
, NULL
, ARG_FIDO2_DEVICE
},
141 { "fido2-with-client-pin", required_argument
, NULL
, ARG_FIDO2_WITH_PIN
},
142 { "fido2-with-user-presence", required_argument
, NULL
, ARG_FIDO2_WITH_UP
},
143 { "fido2-with-user-verification", required_argument
, NULL
, ARG_FIDO2_WITH_UV
},
144 { "tpm2-device", required_argument
, NULL
, ARG_TPM2_DEVICE
},
145 { "tpm2-pcrs", required_argument
, NULL
, ARG_TPM2_PCRS
},
146 { "tpm2-with-pin", required_argument
, NULL
, ARG_TPM2_PIN
},
147 { "wipe-slot", required_argument
, NULL
, ARG_WIPE_SLOT
},
156 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0) {
166 case ARG_FIDO2_WITH_PIN
: {
169 r
= parse_boolean_argument("--fido2-with-client-pin=", optarg
, &lock_with_pin
);
173 SET_FLAG(arg_fido2_lock_with
, FIDO2ENROLL_PIN
, lock_with_pin
);
177 case ARG_FIDO2_WITH_UP
: {
180 r
= parse_boolean_argument("--fido2-with-user-presence=", optarg
, &lock_with_up
);
184 SET_FLAG(arg_fido2_lock_with
, FIDO2ENROLL_UP
, lock_with_up
);
188 case ARG_FIDO2_WITH_UV
: {
191 r
= parse_boolean_argument("--fido2-with-user-verification=", optarg
, &lock_with_uv
);
195 SET_FLAG(arg_fido2_lock_with
, FIDO2ENROLL_UV
, lock_with_uv
);
200 if (arg_enroll_type
>= 0)
201 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
202 "Multiple operations specified at once, refusing.");
204 arg_enroll_type
= ENROLL_PASSWORD
;
207 case ARG_RECOVERY_KEY
:
208 if (arg_enroll_type
>= 0)
209 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
210 "Multiple operations specified at once, refusing.");
212 arg_enroll_type
= ENROLL_RECOVERY
;
215 case ARG_PKCS11_TOKEN_URI
: {
216 _cleanup_free_
char *uri
= NULL
;
218 if (streq(optarg
, "list"))
219 return pkcs11_list_tokens();
221 if (arg_enroll_type
>= 0 || arg_pkcs11_token_uri
)
222 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
223 "Multiple operations specified at once, refusing.");
225 if (streq(optarg
, "auto")) {
226 r
= pkcs11_find_token_auto(&uri
);
230 if (!pkcs11_uri_valid(optarg
))
231 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Not a valid PKCS#11 URI: %s", optarg
);
233 uri
= strdup(optarg
);
238 arg_enroll_type
= ENROLL_PKCS11
;
239 arg_pkcs11_token_uri
= TAKE_PTR(uri
);
243 case ARG_FIDO2_DEVICE
: {
244 _cleanup_free_
char *device
= NULL
;
246 if (streq(optarg
, "list"))
247 return fido2_list_devices();
249 if (arg_enroll_type
>= 0 || arg_fido2_device
)
250 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
251 "Multiple operations specified at once, refusing.");
253 if (streq(optarg
, "auto")) {
254 r
= fido2_find_device_auto(&device
);
258 device
= strdup(optarg
);
263 arg_enroll_type
= ENROLL_FIDO2
;
264 arg_fido2_device
= TAKE_PTR(device
);
268 case ARG_TPM2_DEVICE
: {
269 _cleanup_free_
char *device
= NULL
;
271 if (streq(optarg
, "list"))
272 return tpm2_list_devices();
274 if (arg_enroll_type
>= 0 || arg_tpm2_device
)
275 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
276 "Multiple operations specified at once, refusing.");
278 if (!streq(optarg
, "auto")) {
279 device
= strdup(optarg
);
284 arg_enroll_type
= ENROLL_TPM2
;
285 arg_tpm2_device
= TAKE_PTR(device
);
289 case ARG_TPM2_PCRS
: {
292 if (isempty(optarg
)) {
293 arg_tpm2_pcr_mask
= 0;
297 r
= tpm2_parse_pcrs(optarg
, &mask
);
301 if (arg_tpm2_pcr_mask
== UINT32_MAX
)
302 arg_tpm2_pcr_mask
= mask
;
304 arg_tpm2_pcr_mask
|= mask
;
310 r
= parse_boolean_argument("--tpm2-with-pin=", optarg
, &arg_tpm2_pin
);
317 case ARG_WIPE_SLOT
: {
318 const char *p
= optarg
;
320 if (isempty(optarg
)) {
321 arg_wipe_slots_mask
= 0;
322 arg_wipe_slots_scope
= WIPE_EXPLICIT
;
327 _cleanup_free_
char *slot
= NULL
;
330 r
= extract_first_word(&p
, &slot
, ",", EXTRACT_DONT_COALESCE_SEPARATORS
);
334 return log_error_errno(r
, "Failed to parse slot list: %s", optarg
);
336 if (streq(slot
, "all"))
337 arg_wipe_slots_scope
= WIPE_ALL
;
338 else if (streq(slot
, "empty")) {
339 if (arg_wipe_slots_scope
!= WIPE_ALL
) /* if "all" was specified before, that wins */
340 arg_wipe_slots_scope
= WIPE_EMPTY_PASSPHRASE
;
341 } else if (streq(slot
, "password"))
342 arg_wipe_slots_mask
= 1U << ENROLL_PASSWORD
;
343 else if (streq(slot
, "recovery"))
344 arg_wipe_slots_mask
= 1U << ENROLL_RECOVERY
;
345 else if (streq(slot
, "pkcs11"))
346 arg_wipe_slots_mask
= 1U << ENROLL_PKCS11
;
347 else if (streq(slot
, "fido2"))
348 arg_wipe_slots_mask
= 1U << ENROLL_FIDO2
;
349 else if (streq(slot
, "tpm2"))
350 arg_wipe_slots_mask
= 1U << ENROLL_TPM2
;
354 r
= safe_atou(slot
, &n
);
356 return log_error_errno(r
, "Failed to parse slot index: %s", slot
);
358 return log_error_errno(SYNTHETIC_ERRNO(ERANGE
), "Slot index out of range: %u", n
);
360 a
= reallocarray(arg_wipe_slots
, sizeof(int), arg_n_wipe_slots
+ 1);
365 arg_wipe_slots
[arg_n_wipe_slots
++] = (int) n
;
375 assert_not_reached();
380 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
381 "No block device node specified, refusing.");
384 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
385 "Too many arguments, refusing.");
387 r
= parse_path_argument(argv
[optind
], false, &arg_node
);
391 if (arg_tpm2_pcr_mask
== UINT32_MAX
)
392 arg_tpm2_pcr_mask
= TPM2_PCR_MASK_DEFAULT
;
397 static int check_for_homed(struct crypt_device
*cd
) {
402 /* Politely refuse operating on homed volumes. The enrolled tokens for the user record and the LUKS2
403 * volume should not get out of sync. */
405 for (int token
= 0; token
< crypt_token_max(CRYPT_LUKS2
); token
++) {
406 r
= cryptsetup_get_token_as_json(cd
, token
, "systemd-homed", NULL
);
407 if (IN_SET(r
, -ENOENT
, -EINVAL
, -EMEDIUMTYPE
))
410 return log_error_errno(r
, "Failed to read JSON token data off disk: %m");
412 return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN
),
413 "LUKS2 volume is managed by systemd-homed, please use homectl to enroll tokens.");
419 static int prepare_luks(
420 struct crypt_device
**ret_cd
,
421 void **ret_volume_key
,
422 size_t *ret_volume_key_size
) {
424 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
425 _cleanup_(erase_and_freep
) char *envpw
= NULL
;
426 _cleanup_(erase_and_freep
) void *vk
= NULL
;
431 assert(!ret_volume_key
== !ret_volume_key_size
);
433 r
= crypt_init(&cd
, arg_node
);
435 return log_error_errno(r
, "Failed to allocate libcryptsetup context: %m");
437 cryptsetup_enable_logging(cd
);
439 r
= crypt_load(cd
, CRYPT_LUKS2
, NULL
);
441 return log_error_errno(r
, "Failed to load LUKS2 superblock: %m");
443 r
= check_for_homed(cd
);
447 if (!ret_volume_key
) {
448 *ret_cd
= TAKE_PTR(cd
);
452 r
= crypt_get_volume_key_size(cd
);
454 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Failed to determine LUKS volume key size");
461 r
= getenv_steal_erase("PASSWORD", &envpw
);
463 return log_error_errno(r
, "Failed to acquire password from environment: %m");
465 r
= crypt_volume_key_get(
473 return log_error_errno(r
, "Password from environment variable $PASSWORD did not work.");
475 AskPasswordFlags ask_password_flags
= ASK_PASSWORD_PUSH_CACHE
|ASK_PASSWORD_ACCEPT_CACHED
;
476 _cleanup_free_
char *question
= NULL
, *disk_path
= NULL
;
480 question
= strjoin("Please enter current passphrase for disk ", arg_node
, ":");
484 disk_path
= cescape(arg_node
);
488 id
= strjoina("cryptsetup:", disk_path
);
491 _cleanup_strv_free_erase_
char **passwords
= NULL
;
494 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY
),
495 "Too many attempts, giving up:");
497 r
= ask_password_auto(
498 question
, "drive-harddisk", id
, "cryptenroll", "cryptenroll.passphrase", USEC_INFINITY
,
502 return log_error_errno(r
, "Failed to query password: %m");
505 STRV_FOREACH(p
, passwords
) {
506 r
= crypt_volume_key_get(
519 log_error_errno(r
, "Password not correct, please try again.");
520 ask_password_flags
&= ~ASK_PASSWORD_ACCEPT_CACHED
;
524 *ret_cd
= TAKE_PTR(cd
);
525 *ret_volume_key
= TAKE_PTR(vk
);
526 *ret_volume_key_size
= vks
;
531 static int run(int argc
, char *argv
[]) {
532 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
533 _cleanup_(erase_and_freep
) void *vk
= NULL
;
537 log_show_color(true);
538 log_parse_environment();
541 r
= parse_argv(argc
, argv
);
545 cryptsetup_enable_logging(NULL
);
547 if (arg_enroll_type
< 0)
548 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 */
550 r
= prepare_luks(&cd
, &vk
, &vks
);
554 switch (arg_enroll_type
) {
556 case ENROLL_PASSWORD
:
557 slot
= enroll_password(cd
, vk
, vks
);
560 case ENROLL_RECOVERY
:
561 slot
= enroll_recovery(cd
, vk
, vks
);
565 slot
= enroll_pkcs11(cd
, vk
, vks
, arg_pkcs11_token_uri
);
569 slot
= enroll_fido2(cd
, vk
, vks
, arg_fido2_device
, arg_fido2_lock_with
);
573 slot
= enroll_tpm2(cd
, vk
, vks
, arg_tpm2_device
, arg_tpm2_pcr_mask
, arg_tpm2_pin
);
576 case _ENROLL_TYPE_INVALID
:
577 /* List enrolled slots if we are called without anything to enroll or wipe */
578 if (!wipe_requested())
579 return list_enrolled(cd
);
581 /* Only slot wiping selected */
582 return wipe_slots(cd
, arg_wipe_slots
, arg_n_wipe_slots
, arg_wipe_slots_scope
, arg_wipe_slots_mask
, -1);
585 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Operation not implemented yet.");
590 /* After we completed enrolling, remove user selected slots */
591 r
= wipe_slots(cd
, arg_wipe_slots
, arg_n_wipe_slots
, arg_wipe_slots_scope
, arg_wipe_slots_mask
, slot
);
598 DEFINE_MAIN_FUNCTION(run
);