1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "alloc-util.h"
4 #include "ask-password-api.h"
5 #include "env-util.h"
6 #include "hexdecoct.h"
7 #include "json.h"
8 #include "log.h"
9 #include "luks2-tpm2.h"
10 #include "parse-util.h"
11 #include "random-util.h"
12 #include "strv.h"
13 #include "tpm2-util.h"
14 
acquire_luks2_key(uint32_t pcr_mask,uint16_t pcr_bank,uint16_t primary_alg,const char * device,const void * key_data,size_t key_data_size,const void * policy_hash,size_t policy_hash_size,TPM2Flags flags,void ** ret_decrypted_key,size_t * ret_decrypted_key_size)15 int acquire_luks2_key(
16                 uint32_t pcr_mask,
17                 uint16_t pcr_bank,
18                 uint16_t primary_alg,
19                 const char *device,
20                 const void *key_data,
21                 size_t key_data_size,
22                 const void *policy_hash,
23                 size_t policy_hash_size,
24                 TPM2Flags flags,
25                 void **ret_decrypted_key,
26                 size_t *ret_decrypted_key_size) {
27 
28         _cleanup_free_ char *auto_device = NULL;
29         _cleanup_(erase_and_freep) char *pin_str = NULL;
30         int r;
31 
32         assert(ret_decrypted_key);
33         assert(ret_decrypted_key_size);
34 
35         if (!device) {
36                 r = tpm2_find_device_auto(LOG_DEBUG, &auto_device);
37                 if (r == -ENODEV)
38                         return -EAGAIN; /* Tell the caller to wait for a TPM2 device to show up */
39                 if (r < 0)
40                         return r;
41 
42                 device = auto_device;
43         }
44 
45         r = getenv_steal_erase("PIN", &pin_str);
46         if (r < 0)
47                 return log_error_errno(r, "Failed to acquire PIN from environment: %m");
48         if (!r) {
49                 /* PIN entry is not supported by plugin, let it fallback, possibly to sd-cryptsetup's
50                  * internal handling. */
51                 if (flags & TPM2_FLAGS_USE_PIN)
52                         return -EOPNOTSUPP;
53         }
54 
55         return tpm2_unseal(
56                         device,
57                         pcr_mask, pcr_bank,
58                         primary_alg,
59                         key_data, key_data_size,
60                         policy_hash, policy_hash_size, pin_str,
61                         ret_decrypted_key, ret_decrypted_key_size);
62 }
63 
64 /* this function expects valid "systemd-tpm2" in json */
parse_luks2_tpm2_data(const char * json,uint32_t search_pcr_mask,uint32_t * ret_pcr_mask,uint16_t * ret_pcr_bank,uint16_t * ret_primary_alg,char ** ret_base64_blob,char ** ret_hex_policy_hash,TPM2Flags * ret_flags)65 int parse_luks2_tpm2_data(
66                 const char *json,
67                 uint32_t search_pcr_mask,
68                 uint32_t *ret_pcr_mask,
69                 uint16_t *ret_pcr_bank,
70                 uint16_t *ret_primary_alg,
71                 char **ret_base64_blob,
72                 char **ret_hex_policy_hash,
73                 TPM2Flags *ret_flags) {
74 
75         int r;
76         JsonVariant *w, *e;
77         uint32_t pcr_mask = 0;
78         uint16_t pcr_bank = UINT16_MAX, primary_alg = TPM2_ALG_ECC;
79         _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL;
80         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
81         TPM2Flags flags = 0;
82 
83         assert(json);
84         assert(ret_pcr_mask);
85         assert(ret_pcr_bank);
86         assert(ret_primary_alg);
87         assert(ret_base64_blob);
88         assert(ret_hex_policy_hash);
89 
90         r = json_parse(json, 0, &v, NULL, NULL);
91         if (r < 0)
92                 return -EINVAL;
93 
94         w = json_variant_by_key(v, "tpm2-pcrs");
95         if (!w || !json_variant_is_array(w))
96                 return -EINVAL;
97 
98         JSON_VARIANT_ARRAY_FOREACH(e, w) {
99                 uint64_t u;
100 
101                 if (!json_variant_is_number(e))
102                         return -EINVAL;
103 
104                 u = json_variant_unsigned(e);
105                 if (u >= TPM2_PCRS_MAX)
106                         return -EINVAL;
107 
108                 pcr_mask |= UINT32_C(1) << u;
109         }
110 
111         if (search_pcr_mask != UINT32_MAX &&
112             search_pcr_mask != pcr_mask)
113                 return -ENXIO;
114 
115         w = json_variant_by_key(v, "tpm2-pcr-bank");
116         if (w) {
117                 /* The PCR bank field is optional */
118 
119                 if (!json_variant_is_string(w))
120                         return -EINVAL;
121 
122                 r = tpm2_pcr_bank_from_string(json_variant_string(w));
123                 if (r < 0)
124                         return r;
125 
126                 pcr_bank = r;
127         }
128 
129         w = json_variant_by_key(v, "tpm2-primary-alg");
130         if (w) {
131                 /* The primary key algorithm is optional */
132 
133                 if (!json_variant_is_string(w))
134                         return -EINVAL;
135 
136                 r = tpm2_primary_alg_from_string(json_variant_string(w));
137                 if (r < 0)
138                         return r;
139 
140                 primary_alg = r;
141         }
142 
143         w = json_variant_by_key(v, "tpm2-blob");
144         if (!w || !json_variant_is_string(w))
145                 return -EINVAL;
146 
147         base64_blob = strdup(json_variant_string(w));
148         if (!base64_blob)
149                 return -ENOMEM;
150 
151         w = json_variant_by_key(v, "tpm2-policy-hash");
152         if (!w || !json_variant_is_string(w))
153                 return -EINVAL;
154 
155         hex_policy_hash = strdup(json_variant_string(w));
156         if (!hex_policy_hash)
157                 return -ENOMEM;
158 
159         w = json_variant_by_key(v, "tpm2-pin");
160         if (w) {
161                 if (!json_variant_is_boolean(w))
162                         return -EINVAL;
163 
164                 if (json_variant_boolean(w))
165                         flags |= TPM2_FLAGS_USE_PIN;
166         }
167 
168         *ret_pcr_mask = pcr_mask;
169         *ret_pcr_bank = pcr_bank;
170         *ret_primary_alg = primary_alg;
171         *ret_base64_blob = TAKE_PTR(base64_blob);
172         *ret_hex_policy_hash = TAKE_PTR(hex_policy_hash);
173         *ret_flags = flags;
174 
175         return 0;
176 }
177