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