SECURITY: Add SECURITY file
[grub.git] / grub-core / disk / geli.c
blob2f34a35e6b83e6a12f878ec18e615857d39cd96c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2003,2007,2010,2011 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 /* This file is loosely based on FreeBSD geli implementation
20 (but no code was directly copied). FreeBSD geli is distributed under
21 following terms: */
22 /*-
23 * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
24 * All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
48 #include <grub/cryptodisk.h>
49 #include <grub/types.h>
50 #include <grub/misc.h>
51 #include <grub/mm.h>
52 #include <grub/dl.h>
53 #include <grub/err.h>
54 #include <grub/disk.h>
55 #include <grub/crypto.h>
56 #include <grub/partition.h>
57 #include <grub/i18n.h>
59 GRUB_MOD_LICENSE ("GPLv3+");
61 /* Dirty trick to solve circular dependency. */
62 #ifdef GRUB_UTIL
64 #include <grub/util/misc.h>
66 #undef GRUB_MD_SHA256
67 #undef GRUB_MD_SHA512
69 static const gcry_md_spec_t *
70 grub_md_sha256_real (void)
72 const gcry_md_spec_t *ret;
73 ret = grub_crypto_lookup_md_by_name ("sha256");
74 if (!ret)
75 grub_util_error ("%s", _("Couldn't load sha256"));
76 return ret;
79 static const gcry_md_spec_t *
80 grub_md_sha512_real (void)
82 const gcry_md_spec_t *ret;
83 ret = grub_crypto_lookup_md_by_name ("sha512");
84 if (!ret)
85 grub_util_error ("%s", _("Couldn't load sha512"));
86 return ret;
89 #define GRUB_MD_SHA256 grub_md_sha256_real()
90 #define GRUB_MD_SHA512 grub_md_sha512_real()
91 #endif
93 struct grub_geli_key
95 grub_uint8_t iv_key[64];
96 grub_uint8_t cipher_key[64];
97 grub_uint8_t hmac[64];
98 } GRUB_PACKED;
100 struct grub_geli_phdr
102 grub_uint8_t magic[16];
103 #define GELI_MAGIC "GEOM::ELI"
104 grub_uint32_t version;
105 grub_uint32_t flags;
106 grub_uint16_t alg;
107 grub_uint16_t keylen;
108 grub_uint16_t unused3[5];
109 grub_uint32_t sector_size;
110 grub_uint8_t keys_used;
111 grub_uint32_t niter;
112 grub_uint8_t salt[64];
113 struct grub_geli_key keys[2];
114 } GRUB_PACKED;
116 enum
118 GRUB_GELI_FLAGS_ONETIME = 1,
119 GRUB_GELI_FLAGS_BOOT = 2,
122 /* FIXME: support version 0. */
123 /* FIXME: support big-endian pre-version-4 volumes. */
124 /* FIXME: support for keyfiles. */
125 /* FIXME: support for HMAC. */
126 const char *algorithms[] = {
127 [0x01] = "des",
128 [0x02] = "3des",
129 [0x03] = "blowfish",
130 [0x04] = "cast5",
131 /* FIXME: 0x05 is skipjack, but we don't have it. */
132 [0x0b] = "aes",
133 /* FIXME: 0x10 is null. */
134 [0x15] = "camellia128",
135 [0x16] = "aes"
138 #define MAX_PASSPHRASE 256
140 static gcry_err_code_t
141 geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno)
143 gcry_err_code_t gcry_err;
144 const struct {
145 char magic[4];
146 grub_uint64_t zone;
147 } GRUB_PACKED tohash
148 = { {'e', 'k', 'e', 'y'}, grub_cpu_to_le64 (zoneno) };
149 GRUB_PROPERLY_ALIGNED_ARRAY (key, GRUB_CRYPTO_MAX_MDLEN);
151 if (dev->hash->mdlen > GRUB_CRYPTO_MAX_MDLEN)
152 return GPG_ERR_INV_ARG;
154 grub_dprintf ("geli", "rekeying %" PRIuGRUB_UINT64_T " keysize=%d\n",
155 zoneno, dev->rekey_derived_size);
156 gcry_err = grub_crypto_hmac_buffer (dev->hash, dev->rekey_key, 64,
157 &tohash, sizeof (tohash), key);
158 if (gcry_err)
159 return gcry_err;
161 return grub_cryptodisk_setkey (dev, (grub_uint8_t *) key,
162 dev->rekey_derived_size);
165 static inline gcry_err_code_t
166 make_uuid (const struct grub_geli_phdr *header,
167 char *uuid)
169 grub_uint8_t uuidbin[GRUB_CRYPTODISK_MAX_UUID_LENGTH];
170 gcry_err_code_t err;
171 grub_uint8_t *iptr;
172 char *optr;
174 if (2 * GRUB_MD_SHA256->mdlen + 1 > GRUB_CRYPTODISK_MAX_UUID_LENGTH)
175 return GPG_ERR_TOO_LARGE;
176 err = grub_crypto_hmac_buffer (GRUB_MD_SHA256,
177 header->salt, sizeof (header->salt),
178 "uuid", sizeof ("uuid") - 1, uuidbin);
179 if (err)
180 return err;
182 optr = uuid;
183 for (iptr = uuidbin; iptr < &uuidbin[GRUB_MD_SHA256->mdlen]; iptr++)
185 grub_snprintf (optr, 3, "%02x", *iptr);
186 optr += 2;
188 *optr = 0;
189 return GPG_ERR_NO_ERROR;
192 #ifdef GRUB_UTIL
194 #include <grub/emu/hostdisk.h>
195 #include <grub/emu/misc.h>
197 char *
198 grub_util_get_geli_uuid (const char *dev)
200 grub_util_fd_t fd;
201 grub_uint64_t s;
202 unsigned log_secsize;
203 grub_uint8_t hdr[512];
204 struct grub_geli_phdr *header;
205 char *uuid;
206 gcry_err_code_t err;
208 fd = grub_util_fd_open (dev, GRUB_UTIL_FD_O_RDONLY);
210 if (!GRUB_UTIL_FD_IS_VALID (fd))
211 return NULL;
213 s = grub_util_get_fd_size (fd, dev, &log_secsize);
214 s >>= log_secsize;
215 if (grub_util_fd_seek (fd, (s << log_secsize) - 512) < 0)
216 grub_util_error ("%s", _("couldn't read ELI metadata"));
218 uuid = xmalloc (GRUB_MD_SHA256->mdlen * 2 + 1);
219 if (grub_util_fd_read (fd, (void *) &hdr, 512) < 0)
220 grub_util_error ("%s", _("couldn't read ELI metadata"));
222 grub_util_fd_close (fd);
224 COMPILE_TIME_ASSERT (sizeof (header) <= 512);
225 header = (void *) &hdr;
227 /* Look for GELI magic sequence. */
228 if (grub_memcmp (header->magic, GELI_MAGIC, sizeof (GELI_MAGIC))
229 || grub_le_to_cpu32 (header->version) > 7
230 || grub_le_to_cpu32 (header->version) < 1)
231 grub_util_error ("%s", _("wrong ELI magic or version"));
233 err = make_uuid ((void *) &hdr, uuid);
234 if (err)
236 grub_free (uuid);
237 return NULL;
240 return uuid;
242 #endif
244 static grub_cryptodisk_t
245 configure_ciphers (grub_disk_t disk, const char *check_uuid,
246 int boot_only)
248 grub_cryptodisk_t newdev;
249 struct grub_geli_phdr header;
250 grub_crypto_cipher_handle_t cipher = NULL, secondary_cipher = NULL;
251 const struct gcry_cipher_spec *ciph;
252 const char *ciphername = NULL;
253 gcry_err_code_t gcry_err;
254 char uuid[GRUB_CRYPTODISK_MAX_UUID_LENGTH];
255 grub_disk_addr_t sector;
256 grub_err_t err;
258 if (2 * GRUB_MD_SHA256->mdlen + 1 > GRUB_CRYPTODISK_MAX_UUID_LENGTH)
259 return NULL;
261 sector = grub_disk_native_sectors (disk);
262 if (sector == GRUB_DISK_SIZE_UNKNOWN || sector == 0)
263 return NULL;
265 /* Read the GELI header. */
266 err = grub_disk_read (disk, sector - 1, 0, sizeof (header), &header);
267 if (err)
268 return NULL;
270 /* Look for GELI magic sequence. */
271 if (grub_memcmp (header.magic, GELI_MAGIC, sizeof (GELI_MAGIC))
272 || grub_le_to_cpu32 (header.version) > 7
273 || grub_le_to_cpu32 (header.version) < 1)
275 grub_dprintf ("geli", "wrong magic %02x\n", header.magic[0]);
276 return NULL;
279 if ((grub_le_to_cpu32 (header.sector_size)
280 & (grub_le_to_cpu32 (header.sector_size) - 1))
281 || grub_le_to_cpu32 (header.sector_size) == 0)
283 grub_dprintf ("geli", "incorrect sector size %d\n",
284 grub_le_to_cpu32 (header.sector_size));
285 return NULL;
288 if (grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_ONETIME)
290 grub_dprintf ("geli", "skipping one-time volume\n");
291 return NULL;
294 if (boot_only && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT))
296 grub_dprintf ("geli", "not a boot volume\n");
297 return NULL;
300 gcry_err = make_uuid (&header, uuid);
301 if (gcry_err)
303 grub_crypto_gcry_error (gcry_err);
304 return NULL;
307 if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0)
309 grub_dprintf ("geli", "%s != %s\n", uuid, check_uuid);
310 return NULL;
313 if (grub_le_to_cpu16 (header.alg) >= ARRAY_SIZE (algorithms)
314 || algorithms[grub_le_to_cpu16 (header.alg)] == NULL)
316 grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher 0x%x unknown",
317 grub_le_to_cpu16 (header.alg));
318 return NULL;
321 ciphername = algorithms[grub_le_to_cpu16 (header.alg)];
322 ciph = grub_crypto_lookup_cipher_by_name (ciphername);
323 if (!ciph)
325 grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher %s isn't available",
326 ciphername);
327 return NULL;
330 /* Configure the cipher used for the bulk data. */
331 cipher = grub_crypto_cipher_open (ciph);
332 if (!cipher)
333 return NULL;
335 if (grub_le_to_cpu16 (header.alg) == 0x16)
337 secondary_cipher = grub_crypto_cipher_open (ciph);
338 if (!secondary_cipher)
340 grub_crypto_cipher_close (cipher);
341 return NULL;
346 if (grub_le_to_cpu16 (header.keylen) > 1024)
348 grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid keysize %d",
349 grub_le_to_cpu16 (header.keylen));
350 grub_crypto_cipher_close (cipher);
351 grub_crypto_cipher_close (secondary_cipher);
352 return NULL;
355 newdev = grub_zalloc (sizeof (struct grub_cryptodisk));
356 if (!newdev)
358 grub_crypto_cipher_close (cipher);
359 grub_crypto_cipher_close (secondary_cipher);
360 return NULL;
362 newdev->cipher = cipher;
363 newdev->secondary_cipher = secondary_cipher;
364 newdev->offset_sectors = 0;
365 newdev->source_disk = NULL;
366 newdev->benbi_log = 0;
367 if (grub_le_to_cpu16 (header.alg) == 0x16)
369 newdev->mode = GRUB_CRYPTODISK_MODE_XTS;
370 newdev->mode_iv = GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64;
372 else
374 newdev->mode = GRUB_CRYPTODISK_MODE_CBC;
375 newdev->mode_iv = GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH;
377 newdev->essiv_cipher = NULL;
378 newdev->essiv_hash = NULL;
379 newdev->hash = GRUB_MD_SHA512;
380 newdev->iv_hash = GRUB_MD_SHA256;
382 for (newdev->log_sector_size = 0;
383 (1U << newdev->log_sector_size) < grub_le_to_cpu32 (header.sector_size);
384 newdev->log_sector_size++);
386 if (grub_le_to_cpu32 (header.version) >= 5)
388 newdev->rekey = geli_rekey;
389 newdev->rekey_shift = 20;
392 newdev->modname = "geli";
394 newdev->total_sectors = grub_disk_native_sectors (disk) - 1;
395 grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid));
396 COMPILE_TIME_ASSERT (sizeof (newdev->uuid) >= 32 * 2 + 1);
397 return newdev;
400 static grub_err_t
401 recover_key (grub_disk_t source, grub_cryptodisk_t dev)
403 grub_size_t keysize;
404 grub_uint8_t digest[GRUB_CRYPTO_MAX_MDLEN];
405 grub_uint8_t geomkey[GRUB_CRYPTO_MAX_MDLEN];
406 grub_uint8_t verify_key[GRUB_CRYPTO_MAX_MDLEN];
407 grub_uint8_t zero[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE];
408 grub_uint8_t geli_cipher_key[64];
409 char passphrase[MAX_PASSPHRASE] = "";
410 unsigned i;
411 gcry_err_code_t gcry_err;
412 struct grub_geli_phdr header;
413 char *tmp;
414 grub_disk_addr_t sector;
415 grub_err_t err;
417 if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE)
418 return grub_error (GRUB_ERR_BUG, "cipher block is too long");
420 if (dev->hash->mdlen > GRUB_CRYPTO_MAX_MDLEN)
421 return grub_error (GRUB_ERR_BUG, "mdlen is too long");
423 sector = grub_disk_native_sectors (source);
424 if (sector == GRUB_DISK_SIZE_UNKNOWN || sector == 0)
425 return grub_error (GRUB_ERR_BUG, "not a geli");
427 /* Read the GELI header. */
428 err = grub_disk_read (source, sector - 1, 0, sizeof (header), &header);
429 if (err)
430 return err;
432 keysize = grub_le_to_cpu16 (header.keylen) / GRUB_CHAR_BIT;
433 grub_memset (zero, 0, sizeof (zero));
435 grub_puts_ (N_("Attempting to decrypt master key..."));
437 /* Get the passphrase from the user. */
438 tmp = NULL;
439 if (source->partition)
440 tmp = grub_partition_get_name (source->partition);
441 grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
442 source->partition ? "," : "", tmp ? : "",
443 dev->uuid);
444 grub_free (tmp);
445 if (!grub_password_get (passphrase, MAX_PASSPHRASE))
446 return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
448 /* Calculate the PBKDF2 of the user supplied passphrase. */
449 if (grub_le_to_cpu32 (header.niter) != 0)
451 grub_uint8_t pbkdf_key[64];
452 gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase,
453 grub_strlen (passphrase),
454 header.salt,
455 sizeof (header.salt),
456 grub_le_to_cpu32 (header.niter),
457 pbkdf_key, sizeof (pbkdf_key));
459 if (gcry_err)
460 return grub_crypto_gcry_error (gcry_err);
462 gcry_err = grub_crypto_hmac_buffer (dev->hash, NULL, 0, pbkdf_key,
463 sizeof (pbkdf_key), geomkey);
464 if (gcry_err)
465 return grub_crypto_gcry_error (gcry_err);
467 else
469 struct grub_crypto_hmac_handle *hnd;
471 hnd = grub_crypto_hmac_init (dev->hash, NULL, 0);
472 if (!hnd)
473 return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY);
475 grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt));
476 grub_crypto_hmac_write (hnd, passphrase, grub_strlen (passphrase));
478 gcry_err = grub_crypto_hmac_fini (hnd, geomkey);
479 if (gcry_err)
480 return grub_crypto_gcry_error (gcry_err);
483 gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey,
484 dev->hash->mdlen, "\1", 1, digest);
485 if (gcry_err)
486 return grub_crypto_gcry_error (gcry_err);
488 gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey,
489 dev->hash->mdlen, "\0", 1, verify_key);
490 if (gcry_err)
491 return grub_crypto_gcry_error (gcry_err);
493 grub_dprintf ("geli", "keylen = %" PRIuGRUB_SIZE "\n", keysize);
495 /* Try to recover master key from each active keyslot. */
496 for (i = 0; i < ARRAY_SIZE (header.keys); i++)
498 struct grub_geli_key candidate_key;
499 grub_uint8_t key_hmac[GRUB_CRYPTO_MAX_MDLEN];
501 /* Check if keyslot is enabled. */
502 if (! (header.keys_used & (1 << i)))
503 continue;
505 grub_dprintf ("geli", "Trying keyslot %d\n", i);
507 gcry_err = grub_crypto_cipher_set_key (dev->cipher,
508 digest, keysize);
509 if (gcry_err)
510 return grub_crypto_gcry_error (gcry_err);
512 gcry_err = grub_crypto_cbc_decrypt (dev->cipher, &candidate_key,
513 &header.keys[i],
514 sizeof (candidate_key),
515 zero);
516 if (gcry_err)
517 return grub_crypto_gcry_error (gcry_err);
519 gcry_err = grub_crypto_hmac_buffer (dev->hash, verify_key,
520 dev->hash->mdlen,
521 &candidate_key,
522 (sizeof (candidate_key)
523 - sizeof (candidate_key.hmac)),
524 key_hmac);
525 if (gcry_err)
526 return grub_crypto_gcry_error (gcry_err);
528 if (grub_memcmp (candidate_key.hmac, key_hmac, dev->hash->mdlen) != 0)
529 continue;
530 grub_printf_ (N_("Slot %d opened\n"), i);
532 if (grub_le_to_cpu32 (header.version) >= 7)
534 /* GELI >=7 uses the cipher_key */
535 grub_memcpy (geli_cipher_key, candidate_key.cipher_key,
536 sizeof (candidate_key.cipher_key));
538 else
540 /* GELI <=6 uses the iv_key */
541 grub_memcpy (geli_cipher_key, candidate_key.iv_key,
542 sizeof (candidate_key.iv_key));
545 /* Set the master key. */
546 if (!dev->rekey)
548 grub_size_t real_keysize = keysize;
549 if (grub_le_to_cpu16 (header.alg) == 0x16)
550 real_keysize *= 2;
551 gcry_err = grub_cryptodisk_setkey (dev, candidate_key.cipher_key,
552 real_keysize);
553 if (gcry_err)
554 return grub_crypto_gcry_error (gcry_err);
556 else
558 grub_size_t real_keysize = keysize;
559 if (grub_le_to_cpu16 (header.alg) == 0x16)
560 real_keysize *= 2;
562 grub_memcpy (dev->rekey_key, geli_cipher_key,
563 sizeof (geli_cipher_key));
564 dev->rekey_derived_size = real_keysize;
565 dev->last_rekey = -1;
566 COMPILE_TIME_ASSERT (sizeof (dev->rekey_key)
567 >= sizeof (geli_cipher_key));
570 dev->iv_prefix_len = sizeof (candidate_key.iv_key);
571 grub_memcpy (dev->iv_prefix, candidate_key.iv_key,
572 sizeof (candidate_key.iv_key));
574 COMPILE_TIME_ASSERT (sizeof (dev->iv_prefix) >= sizeof (candidate_key.iv_key));
576 return GRUB_ERR_NONE;
579 return GRUB_ACCESS_DENIED;
582 struct grub_cryptodisk_dev geli_crypto = {
583 .scan = configure_ciphers,
584 .recover_key = recover_key
587 GRUB_MOD_INIT (geli)
589 grub_cryptodisk_dev_register (&geli_crypto);
592 GRUB_MOD_FINI (geli)
594 grub_cryptodisk_dev_unregister (&geli_crypto);