]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptenroll/cryptenroll-tpm2.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "cryptenroll-tpm2.h"
7 #include "memory-util.h"
10 static int search_policy_hash (
11 struct crypt_device
* cd
,
18 assert ( hash
|| hash_size
== 0 );
23 for ( int token
= 0 ; token
< sym_crypt_token_max ( CRYPT_LUKS2
); token
++) {
24 _cleanup_ ( json_variant_unrefp
) JsonVariant
* v
= NULL
;
25 _cleanup_free_
void * thash
= NULL
;
26 size_t thash_size
= 0 ;
30 r
= cryptsetup_get_token_as_json ( cd
, token
, "systemd-tpm2" , & v
);
31 if ( IN_SET ( r
, - ENOENT
, - EINVAL
, - EMEDIUMTYPE
))
34 return log_error_errno ( r
, "Failed to read JSON token data off disk: %m" );
36 keyslot
= cryptsetup_get_keyslot_from_token ( v
);
38 return log_error_errno ( keyslot
, "Failed to determine keyslot of JSON token: %m" );
40 w
= json_variant_by_key ( v
, "tpm2-policy-hash" );
41 if (! w
|| ! json_variant_is_string ( w
))
42 return log_error_errno ( SYNTHETIC_ERRNO ( EINVAL
),
43 "TPM2 token data lacks 'tpm2-policy-hash' field." );
45 r
= unhexmem ( json_variant_string ( w
), ( size_t ) - 1 , & thash
, & thash_size
);
47 return log_error_errno ( SYNTHETIC_ERRNO ( EINVAL
),
48 "Invalid base64 data in 'tpm2-policy-hash' field." );
50 if ( memcmp_nn ( hash
, hash_size
, thash
, thash_size
) == 0 )
51 return keyslot
; /* Found entry with same hash. */
54 return - ENOENT
; /* Not found */
57 int enroll_tpm2 ( struct crypt_device
* cd
,
58 const void * volume_key
,
59 size_t volume_key_size
,
63 _cleanup_ ( erase_and_freep
) void * secret
= NULL
, * secret2
= NULL
;
64 _cleanup_ ( json_variant_unrefp
) JsonVariant
* v
= NULL
;
65 _cleanup_ ( erase_and_freep
) char * base64_encoded
= NULL
;
66 size_t secret_size
, secret2_size
, blob_size
, hash_size
;
67 _cleanup_free_
void * blob
= NULL
, * hash
= NULL
;
73 assert ( volume_key_size
> 0 );
74 assert ( pcr_mask
< ( 1U << TPM2_PCRS_MAX
)); /* Support 24 PCR banks */
76 assert_se ( node
= crypt_get_device_name ( cd
));
78 r
= tpm2_seal ( device
, pcr_mask
, & secret
, & secret_size
, & blob
, & blob_size
, & hash
, & hash_size
);
82 /* Let's see if we already have this specific PCR policy hash enrolled, if so, exit early. */
83 r
= search_policy_hash ( cd
, hash
, hash_size
);
85 log_debug_errno ( r
, "PCR policy hash not yet enrolled, enrolling now." );
89 log_info ( "This PCR set is already enrolled, executing no operation." );
90 return r
; /* return existing keyslot, so that wiping won't kill it */
93 /* Quick verification that everything is in order, we are not in a hurry after all. */
94 log_debug ( "Unsealing for verification..." );
95 r
= tpm2_unseal ( device
, pcr_mask
, blob
, blob_size
, hash
, hash_size
, & secret2
, & secret2_size
);
99 if ( memcmp_nn ( secret
, secret_size
, secret2
, secret2_size
) != 0 )
100 return log_error_errno ( SYNTHETIC_ERRNO ( ENOTRECOVERABLE
), "TPM2 seal/unseal verification failed." );
102 /* let's base64 encode the key to use, for compat with homed (and it's easier to every type it in by keyboard, if that might end up being necessary. */
103 r
= base64mem ( secret
, secret_size
, & base64_encoded
);
105 return log_error_errno ( r
, "Failed to base64 encode secret key: %m" );
107 r
= cryptsetup_set_minimal_pbkdf ( cd
);
109 return log_error_errno ( r
, "Failed to set minimal PBKDF: %m" );
111 keyslot
= crypt_keyslot_add_by_volume_key (
117 strlen ( base64_encoded
));
119 return log_error_errno ( keyslot
, "Failed to add new TPM2 key to %s: %m" , node
);
121 r
= tpm2_make_luks2_json ( keyslot
, pcr_mask
, blob
, blob_size
, hash
, hash_size
, & v
);
123 return log_error_errno ( r
, "Failed to prepare TPM2 JSON token object: %m" );
125 r
= cryptsetup_add_token_json ( cd
, v
);
127 return log_error_errno ( r
, "Failed to add TPM2 JSON token to LUKS2 header: %m" );
129 log_info ( "New TPM2 token enrolled as key slot %i." , keyslot
);