86305ce4fd482a5f9d8405747d8e2f424011328c
[platform/upstream/cryptsetup.git] / lib / integrity / integrity.c
1 /*
2  * Integrity volume handling
3  *
4  * Copyright (C) 2016-2020 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 static int INTEGRITY_read_superblock(struct crypt_device *cd,
31                                      struct device *device,
32                                      uint64_t offset, struct superblock *sb)
33 {
34         int devfd, r;
35
36         devfd = device_open(cd, device, O_RDONLY);
37         if(devfd < 0)
38                 return -EINVAL;
39
40         if (read_lseek_blockwise(devfd, device_block_size(cd, device),
41                 device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
42             memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
43             sb->version < SB_VERSION_1 || sb->version > SB_VERSION_4) {
44                 log_std(cd, "No integrity superblock detected on %s.\n",
45                         device_path(device));
46                 r = -EINVAL;
47         } else {
48                 sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
49                 sb->journal_sections = le32toh(sb->journal_sections);
50                 sb->provided_data_sectors = le64toh(sb->provided_data_sectors);
51                 sb->recalc_sector = le64toh(sb->recalc_sector);
52                 sb->flags = le32toh(sb->flags);
53                 r = 0;
54         }
55
56         return r;
57 }
58
59 int INTEGRITY_read_sb(struct crypt_device *cd,
60                       struct crypt_params_integrity *params,
61                       uint32_t *flags)
62 {
63         struct superblock sb;
64         int r;
65
66         r = INTEGRITY_read_superblock(cd, crypt_metadata_device(cd), 0, &sb);
67         if (r)
68                 return r;
69
70         params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
71         params->tag_size = sb.integrity_tag_size;
72
73         if (flags)
74                 *flags = sb.flags;
75
76         return 0;
77 }
78
79 int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offset)
80 {
81         struct superblock sb;
82         int r;
83
84         r = INTEGRITY_read_superblock(cd, device, offset, &sb);
85         if (r)
86                 return r;
87
88         log_std(cd, "Info for integrity device %s.\n", device_path(device));
89         log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
90         log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
91         log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
92         log_std(cd, "journal_sections %u\n", sb.journal_sections);
93         log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
94         log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
95         if (sb.version == SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
96                 log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
97         log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
98         log_std(cd, "flags %s%s%s%s\n",
99                 sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
100                 sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
101                 sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
102                 sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "");
103
104         return 0;
105 }
106
107 int INTEGRITY_data_sectors(struct crypt_device *cd,
108                            struct device *device, uint64_t offset,
109                            uint64_t *data_sectors)
110 {
111         struct superblock sb;
112         int r;
113
114         r = INTEGRITY_read_superblock(cd, device, offset, &sb);
115         if (r)
116                 return r;
117
118         *data_sectors = sb.provided_data_sectors;
119         return 0;
120 }
121
122 int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity)
123 {
124         if (!integrity)
125                 return 0;
126
127         //FIXME: use crypto backend hash size
128         if (!strcmp(integrity, "aead"))
129                 return 0;
130         else if (!strcmp(integrity, "hmac(sha1)"))
131                 return 20;
132         else if (!strcmp(integrity, "hmac(sha256)"))
133                 return 32;
134         else if (!strcmp(integrity, "hmac(sha512)"))
135                 return 64;
136         else if (!strcmp(integrity, "poly1305"))
137                 return 0;
138         else if (!strcmp(integrity, "none"))
139                 return 0;
140
141         return -EINVAL;
142 }
143
144 /* Return hash or hmac(hash) size, if known */
145 int INTEGRITY_hash_tag_size(const char *integrity)
146 {
147         char hash[MAX_CIPHER_LEN];
148         int r;
149
150         if (!integrity)
151                 return 0;
152
153         if (!strcmp(integrity, "crc32") || !strcmp(integrity, "crc32c"))
154                 return 4;
155
156         r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
157         if (r == 1)
158                 r = crypt_hash_size(hash);
159         else
160                 r = crypt_hash_size(integrity);
161
162         return r < 0 ? 0 : r;
163 }
164
165 int INTEGRITY_tag_size(struct crypt_device *cd,
166                        const char *integrity,
167                        const char *cipher,
168                        const char *cipher_mode)
169 {
170         int iv_tag_size = 0, auth_tag_size = 0;
171
172         if (!cipher_mode)
173                 iv_tag_size = 0;
174         else if (!strcmp(cipher_mode, "xts-random"))
175                 iv_tag_size = 16;
176         else if (!strcmp(cipher_mode, "gcm-random"))
177                 iv_tag_size = 12;
178         else if (!strcmp(cipher_mode, "ccm-random"))
179                 iv_tag_size = 8;
180         else if (!strcmp(cipher_mode, "ctr-random"))
181                 iv_tag_size = 16;
182         else if (!strcmp(cipher, "aegis256") && !strcmp(cipher_mode, "random"))
183                 iv_tag_size = 32;
184         else if (!strcmp(cipher_mode, "random"))
185                 iv_tag_size = 16;
186
187         //FIXME: use crypto backend hash size
188         if (!integrity || !strcmp(integrity, "none"))
189                 auth_tag_size = 0;
190         else if (!strcmp(integrity, "aead"))
191                 auth_tag_size = 16; //FIXME gcm- mode only
192         else if (!strcmp(integrity, "cmac(aes)"))
193                 auth_tag_size = 16;
194         else if (!strcmp(integrity, "hmac(sha1)"))
195                 auth_tag_size = 20;
196         else if (!strcmp(integrity, "hmac(sha256)"))
197                 auth_tag_size = 32;
198         else if (!strcmp(integrity, "hmac(sha512)"))
199                 auth_tag_size = 64;
200         else if (!strcmp(integrity, "poly1305")) {
201                 if (iv_tag_size)
202                         iv_tag_size = 12;
203                 auth_tag_size = 16;
204         }
205
206         return iv_tag_size + auth_tag_size;
207 }
208
209 int INTEGRITY_create_dmd_device(struct crypt_device *cd,
210                        const struct crypt_params_integrity *params,
211                        struct volume_key *vk,
212                        struct volume_key *journal_crypt_key,
213                        struct volume_key *journal_mac_key,
214                        struct crypt_dm_active_device *dmd,
215                        uint32_t flags, uint32_t sb_flags)
216 {
217         int r;
218
219         if (!dmd)
220                 return -EINVAL;
221
222         *dmd = (struct crypt_dm_active_device) {
223                 .flags = flags,
224         };
225
226         /* Workaround for kernel dm-integrity table bug */
227         if (sb_flags & SB_FLAG_RECALCULATING)
228                 dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
229
230         r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
231                                    crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
232         if (r < 0)
233                 return r;
234
235         return dm_integrity_target_set(cd, &dmd->segment, 0, dmd->size,
236                         crypt_metadata_device(cd), crypt_data_device(cd),
237                         crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
238                         crypt_get_sector_size(cd), vk, journal_crypt_key,
239                         journal_mac_key, params);
240 }
241
242 int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
243                        const char *name,
244                        const char *type,
245                        struct crypt_dm_active_device *dmd,
246                        uint32_t sb_flags)
247 {
248         int r;
249         uint32_t dmi_flags;
250         struct dm_target *tgt = &dmd->segment;
251
252         if (!single_segment(dmd) || tgt->type != DM_INTEGRITY)
253                 return -EINVAL;
254
255         log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
256                 device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size);
257
258         r = device_block_adjust(cd, tgt->data_device, DEV_EXCL,
259                                 tgt->u.integrity.offset, NULL, &dmd->flags);
260         if (r)
261                 return r;
262
263         if (tgt->u.integrity.meta_device) {
264                 r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
265                 if (r)
266                         return r;
267         }
268
269         r = dm_create_device(cd, name, type, dmd);
270         if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
271                 log_err(cd, _("Kernel does not support dm-integrity mapping."));
272                 return -ENOTSUP;
273         }
274
275         if (r < 0 && (sb_flags & SB_FLAG_FIXED_PADDING) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
276             !(dmi_flags & DM_INTEGRITY_FIX_PADDING_SUPPORTED)) {
277                 log_err(cd, _("Kernel does not support dm-integrity fixed metadata alignment."));
278                 return -ENOTSUP;
279         }
280
281         return r;
282 }
283
284 int INTEGRITY_activate(struct crypt_device *cd,
285                        const char *name,
286                        const struct crypt_params_integrity *params,
287                        struct volume_key *vk,
288                        struct volume_key *journal_crypt_key,
289                        struct volume_key *journal_mac_key,
290                        uint32_t flags, uint32_t sb_flags)
291 {
292         struct crypt_dm_active_device dmd = {};
293         int r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key,
294                                             journal_mac_key, &dmd, flags, sb_flags);
295
296         if (r < 0)
297                 return r;
298
299         r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
300         dm_targets_free(cd, &dmd);
301         return r;
302 }
303
304 int INTEGRITY_format(struct crypt_device *cd,
305                      const struct crypt_params_integrity *params,
306                      struct volume_key *journal_crypt_key,
307                      struct volume_key *journal_mac_key)
308 {
309         uint32_t dmi_flags;
310         char tmp_name[64], tmp_uuid[40];
311         struct crypt_dm_active_device dmdi = {
312                 .size = 8,
313                 .flags = CRYPT_ACTIVATE_PRIVATE, /* We always create journal but it can be unused later */
314         };
315         struct dm_target *tgt = &dmdi.segment;
316         int r;
317         uuid_t tmp_uuid_bin;
318         struct volume_key *vk = NULL;
319
320         uuid_generate(tmp_uuid_bin);
321         uuid_unparse(tmp_uuid_bin, tmp_uuid);
322
323         snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid);
324
325         /* There is no data area, we can actually use fake zeroed key */
326         if (params && params->integrity_key_size)
327                 vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
328
329         r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, crypt_metadata_device(cd),
330                         crypt_data_device(cd), crypt_get_integrity_tag_size(cd),
331                         crypt_get_data_offset(cd), crypt_get_sector_size(cd), vk,
332                         journal_crypt_key, journal_mac_key, params);
333         if (r < 0) {
334                 crypt_free_volume_key(vk);
335                 return r;
336         }
337
338         log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
339                 device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size);
340
341         r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL);
342         if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
343                 log_err(cd, _("Kernel does not support dm-integrity mapping."));
344                 r = -ENOTSUP;
345         }
346         if (r) {
347                 dm_targets_free(cd, &dmdi);
348                 return r;
349         }
350
351         if (tgt->u.integrity.meta_device) {
352                 r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
353                 if (r) {
354                         dm_targets_free(cd, &dmdi);
355                         return r;
356                 }
357         }
358
359         r = dm_create_device(cd, tmp_name, CRYPT_INTEGRITY, &dmdi);
360         crypt_free_volume_key(vk);
361         dm_targets_free(cd, &dmdi);
362         if (r)
363                 return r;
364
365         return dm_remove_device(cd, tmp_name, CRYPT_DEACTIVATE_FORCE);
366 }