Imported Upstream version 2.6.1
[platform/upstream/cryptsetup.git] / lib / integrity / integrity.c
1 /*
2  * Integrity volume handling
3  *
4  * Copyright (C) 2016-2023 Milan Broz
5  *
6  * This file is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This file is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <uuid/uuid.h>
26
27 #include "integrity.h"
28 #include "internal.h"
29
30 /* For LUKS2, integrity metadata are on DATA device even for detached header! */
31 static struct device *INTEGRITY_metadata_device(struct crypt_device *cd)
32 {
33         const char *type = crypt_get_type(cd);
34
35         if (type && !strcmp(type, CRYPT_LUKS2))
36                 return crypt_data_device(cd);
37
38         return crypt_metadata_device(cd);
39 }
40
41 static int INTEGRITY_read_superblock(struct crypt_device *cd,
42                                      struct device *device,
43                                      uint64_t offset, struct superblock *sb)
44 {
45         int devfd, r;
46
47         devfd = device_open(cd, device, O_RDONLY);
48         if(devfd < 0)
49                 return -EINVAL;
50
51         if (read_lseek_blockwise(devfd, device_block_size(cd, device),
52             device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
53             memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic))) {
54                 log_dbg(cd, "No kernel dm-integrity metadata detected on %s.", device_path(device));
55                 r = -EINVAL;
56         } else if (sb->version < SB_VERSION_1 || sb->version > SB_VERSION_5) {
57                 log_err(cd, _("Incompatible kernel dm-integrity metadata (version %u) detected on %s."),
58                         sb->version, device_path(device));
59                 r = -EINVAL;
60         } else {
61                 sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
62                 sb->journal_sections = le32toh(sb->journal_sections);
63                 sb->provided_data_sectors = le64toh(sb->provided_data_sectors);
64                 sb->recalc_sector = le64toh(sb->recalc_sector);
65                 sb->flags = le32toh(sb->flags);
66                 r = 0;
67         }
68
69         return r;
70 }
71
72 int INTEGRITY_read_sb(struct crypt_device *cd,
73                       struct crypt_params_integrity *params,
74                       uint32_t *flags)
75 {
76         struct superblock sb;
77         int r;
78
79         r = INTEGRITY_read_superblock(cd, INTEGRITY_metadata_device(cd), 0, &sb);
80         if (r)
81                 return r;
82
83         params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
84         params->tag_size = sb.integrity_tag_size;
85
86         if (flags)
87                 *flags = sb.flags;
88
89         return 0;
90 }
91
92 int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offset)
93 {
94         struct superblock sb;
95         int r;
96
97         r = INTEGRITY_read_superblock(cd, device, offset, &sb);
98         if (r)
99                 return r;
100
101         log_std(cd, "Info for integrity device %s.\n", device_path(device));
102         log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
103         log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
104         log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
105         log_std(cd, "journal_sections %u\n", sb.journal_sections);
106         log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
107         log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
108         if (sb.version >= SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
109                 log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
110         log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
111         log_std(cd, "flags %s%s%s%s%s\n",
112                 sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
113                 sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
114                 sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
115                 sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "",
116                 sb.flags & SB_FLAG_FIXED_HMAC ? "fix_hmac " : "");
117
118         return 0;
119 }
120
121 int INTEGRITY_data_sectors(struct crypt_device *cd,
122                            struct device *device, uint64_t offset,
123                            uint64_t *data_sectors)
124 {
125         struct superblock sb;
126         int r;
127
128         r = INTEGRITY_read_superblock(cd, device, offset, &sb);
129         if (r)
130                 return r;
131
132         *data_sectors = sb.provided_data_sectors;
133         return 0;
134 }
135
136 int INTEGRITY_key_size(const char *integrity)
137 {
138         if (!integrity)
139                 return 0;
140
141         //FIXME: use crypto backend hash size
142         if (!strcmp(integrity, "aead"))
143                 return 0;
144         else if (!strcmp(integrity, "hmac(sha1)"))
145                 return 20;
146         else if (!strcmp(integrity, "hmac(sha256)"))
147                 return 32;
148         else if (!strcmp(integrity, "hmac(sha512)"))
149                 return 64;
150         else if (!strcmp(integrity, "poly1305"))
151                 return 0;
152         else if (!strcmp(integrity, "none"))
153                 return 0;
154
155         return -EINVAL;
156 }
157
158 /* Return hash or hmac(hash) size, if known */
159 int INTEGRITY_hash_tag_size(const char *integrity)
160 {
161         char hash[MAX_CIPHER_LEN];
162         int r;
163
164         if (!integrity)
165                 return 0;
166
167         if (!strcmp(integrity, "crc32") || !strcmp(integrity, "crc32c"))
168                 return 4;
169
170         if (!strcmp(integrity, "xxhash64"))
171                 return 8;
172
173         r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
174         if (r == 1)
175                 r = crypt_hash_size(hash);
176         else
177                 r = crypt_hash_size(integrity);
178
179         return r < 0 ? 0 : r;
180 }
181
182 int INTEGRITY_tag_size(const char *integrity,
183                        const char *cipher,
184                        const char *cipher_mode)
185 {
186         int iv_tag_size = 0, auth_tag_size = 0;
187
188         if (!cipher_mode)
189                 iv_tag_size = 0;
190         else if (!strcmp(cipher_mode, "xts-random"))
191                 iv_tag_size = 16;
192         else if (!strcmp(cipher_mode, "gcm-random"))
193                 iv_tag_size = 12;
194         else if (!strcmp(cipher_mode, "ccm-random"))
195                 iv_tag_size = 8;
196         else if (!strcmp(cipher_mode, "ctr-random"))
197                 iv_tag_size = 16;
198         else if (!strcmp(cipher, "aegis256") && !strcmp(cipher_mode, "random"))
199                 iv_tag_size = 32;
200         else if (!strcmp(cipher_mode, "random"))
201                 iv_tag_size = 16;
202
203         //FIXME: use crypto backend hash size
204         if (!integrity || !strcmp(integrity, "none"))
205                 auth_tag_size = 0;
206         else if (!strcmp(integrity, "aead"))
207                 auth_tag_size = 16; /* gcm- mode only */
208         else if (!strcmp(integrity, "cmac(aes)"))
209                 auth_tag_size = 16;
210         else if (!strcmp(integrity, "hmac(sha1)"))
211                 auth_tag_size = 20;
212         else if (!strcmp(integrity, "hmac(sha256)"))
213                 auth_tag_size = 32;
214         else if (!strcmp(integrity, "hmac(sha512)"))
215                 auth_tag_size = 64;
216         else if (!strcmp(integrity, "poly1305")) {
217                 if (iv_tag_size)
218                         iv_tag_size = 12;
219                 auth_tag_size = 16;
220         }
221
222         return iv_tag_size + auth_tag_size;
223 }
224
225 int INTEGRITY_create_dmd_device(struct crypt_device *cd,
226                        const struct crypt_params_integrity *params,
227                        struct volume_key *vk,
228                        struct volume_key *journal_crypt_key,
229                        struct volume_key *journal_mac_key,
230                        struct crypt_dm_active_device *dmd,
231                        uint32_t flags, uint32_t sb_flags)
232 {
233         int r;
234
235         if (!dmd)
236                 return -EINVAL;
237
238         *dmd = (struct crypt_dm_active_device) {
239                 .flags = flags,
240         };
241
242         /* Workaround for kernel dm-integrity table bug */
243         if (sb_flags & SB_FLAG_RECALCULATING)
244                 dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
245
246         r = INTEGRITY_data_sectors(cd, INTEGRITY_metadata_device(cd),
247                                    crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
248         if (r < 0)
249                 return r;
250
251         return dm_integrity_target_set(cd, &dmd->segment, 0, dmd->size,
252                         INTEGRITY_metadata_device(cd), crypt_data_device(cd),
253                         crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
254                         crypt_get_sector_size(cd), vk, journal_crypt_key,
255                         journal_mac_key, params);
256 }
257
258 int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
259                        const char *name,
260                        const char *type,
261                        struct crypt_dm_active_device *dmd,
262                        uint32_t sb_flags)
263 {
264         int r;
265         uint32_t dmi_flags;
266         struct dm_target *tgt = &dmd->segment;
267
268         if (!single_segment(dmd) || tgt->type != DM_INTEGRITY)
269                 return -EINVAL;
270
271         log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
272                 device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size);
273
274         r = create_or_reload_device(cd, name, type, dmd);
275
276         if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
277                 log_err(cd, _("Kernel does not support dm-integrity mapping."));
278                 return -ENOTSUP;
279         }
280
281         if (r < 0 && (sb_flags & SB_FLAG_FIXED_PADDING) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
282             !(dmi_flags & DM_INTEGRITY_FIX_PADDING_SUPPORTED)) {
283                 log_err(cd, _("Kernel does not support dm-integrity fixed metadata alignment."));
284                 return -ENOTSUP;
285         }
286
287         if (r < 0 && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
288             !(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC) &&
289             ((sb_flags & SB_FLAG_FIXED_HMAC) ?
290             (tgt->u.integrity.vk && !tgt->u.integrity.journal_integrity_key) :
291             (tgt->u.integrity.vk || tgt->u.integrity.journal_integrity_key))) {
292                 log_err(cd, _("Kernel refuses to activate insecure recalculate option (see legacy activation options to override)."));
293                 return -ENOTSUP;
294         }
295
296         return r;
297 }
298
299 int INTEGRITY_activate(struct crypt_device *cd,
300                        const char *name,
301                        const struct crypt_params_integrity *params,
302                        struct volume_key *vk,
303                        struct volume_key *journal_crypt_key,
304                        struct volume_key *journal_mac_key,
305                        uint32_t flags, uint32_t sb_flags)
306 {
307         struct crypt_dm_active_device dmdq = {}, dmd = {};
308         int r;
309
310         if (flags & CRYPT_ACTIVATE_REFRESH) {
311                 r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE |
312                                               DM_ACTIVE_CRYPT_KEY |
313                                               DM_ACTIVE_INTEGRITY_PARAMS |
314                                               DM_ACTIVE_JOURNAL_CRYPT_KEY |
315                                               DM_ACTIVE_JOURNAL_MAC_KEY, &dmdq);
316                 if (r < 0)
317                         return r;
318
319                 r = INTEGRITY_create_dmd_device(cd, params, vk ?: dmdq.segment.u.integrity.vk,
320                                                 journal_crypt_key ?: dmdq.segment.u.integrity.journal_crypt_key,
321                                                 journal_mac_key ?: dmdq.segment.u.integrity.journal_integrity_key,
322                                                 &dmd, flags, sb_flags);
323
324                 if (!r)
325                         dmd.size = dmdq.size;
326         } else
327                 r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key,
328                                                 journal_mac_key, &dmd, flags, sb_flags);
329
330         if (!r)
331                 r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
332
333         dm_targets_free(cd, &dmdq);
334         dm_targets_free(cd, &dmd);
335         return r;
336 }
337
338 int INTEGRITY_format(struct crypt_device *cd,
339                      const struct crypt_params_integrity *params,
340                      struct volume_key *journal_crypt_key,
341                      struct volume_key *journal_mac_key)
342 {
343         uint32_t dmi_flags;
344         char tmp_name[64], tmp_uuid[40];
345         struct crypt_dm_active_device dmdi = {
346                 .size = 8,
347                 .flags = CRYPT_ACTIVATE_PRIVATE, /* We always create journal but it can be unused later */
348         };
349         struct dm_target *tgt = &dmdi.segment;
350         int r;
351         uuid_t tmp_uuid_bin;
352         struct volume_key *vk = NULL;
353
354         uuid_generate(tmp_uuid_bin);
355         uuid_unparse(tmp_uuid_bin, tmp_uuid);
356
357         r = snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid);
358         if (r < 0 || (size_t)r >= sizeof(tmp_name))
359                 return -EINVAL;
360
361         /* There is no data area, we can actually use fake zeroed key */
362         if (params && params->integrity_key_size)
363                 vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
364
365         r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, INTEGRITY_metadata_device(cd),
366                         crypt_data_device(cd), crypt_get_integrity_tag_size(cd),
367                         crypt_get_data_offset(cd), crypt_get_sector_size(cd), vk,
368                         journal_crypt_key, journal_mac_key, params);
369         if (r < 0) {
370                 crypt_free_volume_key(vk);
371                 return r;
372         }
373
374         log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
375                 device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size);
376
377         r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL);
378         if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
379                 log_err(cd, _("Kernel does not support dm-integrity mapping."));
380                 r = -ENOTSUP;
381         }
382         if (r) {
383                 dm_targets_free(cd, &dmdi);
384                 return r;
385         }
386
387         if (tgt->u.integrity.meta_device) {
388                 r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
389                 if (r) {
390                         dm_targets_free(cd, &dmdi);
391                         return r;
392                 }
393         }
394
395         r = dm_create_device(cd, tmp_name, CRYPT_INTEGRITY, &dmdi);
396         crypt_free_volume_key(vk);
397         dm_targets_free(cd, &dmdi);
398         if (r)
399                 return r;
400
401         return dm_remove_device(cd, tmp_name, CRYPT_DEACTIVATE_FORCE);
402 }