grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v4 00/15] Cryptodisk fixes for v2.06 redux


From: Glenn Washburn
Subject: [PATCH v4 00/15] Cryptodisk fixes for v2.06 redux
Date: Fri, 6 Nov 2020 22:44:20 -0600

Here we go again. I have not added RB sigs to any patches since I've had to
modify them in moving them earlier in the patch set.  This would be the first
three rename patches. The first two patches of v3 have been reworked into 5
patches (05-09) which combine to be equivalent. Most of the changes since v3 are
added error handling around luks2 cryptodisk setup. Also, I addressed an IV
alignment issue in grub_cryptodisk_endecrypt for the
GRUB_CRYPTODISK_MODE_IV_PLAIN* case, found by Daniel. I'm not sure it works
(I can't reproduce the build error) or that its the desired way of doing it.

Glenn

Glenn Washburn (15):
  cryptodisk: Rename total_length field in grub_cryptodisk_t to
    total_sectors.
  cryptodisk: Rename offset in grub_cryptodisk_t to offset_sectors.
  luks2: Rename source disk variabled named 'disk' to 'source' as in
    luks.c.
  types: Define GRUB_CHAR_BIT based on compiler macro instead of using
    literal.
  luks2: Use correct index variable when looping in luks2_get_keyslot.
  luks2: Rename variable i to keyslot_idx in luks2_get_keyslot.
  luks2: Rename index variable j to i.
  luks2: Split idx into three variables: keyslot_key, digest_key,
    segment_key.
  luks2: Improve error messages in luks2_get_keyslot.
  luks2: Use more intuitive keyslot key instead of index when naming
    keyslot.
  cryptodisk: Replace some literals with constants in
    grub_cryptodisk_endecrypt.
  luks2: grub_cryptodisk_t->total_length is the max number of device
    native sectors
  cryptodisk: Properly handle non-512 byte sized sectors.
  luks2: Better error handling when setting up the cryptodisk.
  luks2: Error check segment.sector_size.

 grub-core/disk/cryptodisk.c |  76 ++++++++++-------
 grub-core/disk/geli.c       |   4 +-
 grub-core/disk/luks.c       |   9 +-
 grub-core/disk/luks2.c      | 165 +++++++++++++++++++++++++++---------
 include/grub/cryptodisk.h   |  18 +++-
 include/grub/misc.h         |   2 +
 include/grub/types.h        |  15 +++-
 7 files changed, 205 insertions(+), 84 deletions(-)

Range-diff against v3:
 5:  e8e069cae =  1:  90fedb50c cryptodisk: Fix cipher IV mode 'plain64' always 
being set as 'plain'.
 8:  28e0cac66 !  2:  d72632f3f cryptodisk: Rename total_length field in 
grub_cryptodisk_t to total_sectors.
    @@ grub-core/disk/luks.c
     @@ grub-core/disk/luks.c: configure_ciphers (grub_disk_t disk, const char 
*check_uuid,
        newdev->offset = grub_be_to_cpu32 (header.payloadOffset);
        newdev->source_disk = NULL;
    -   newdev->log_sector_size = LUKS1_LOG_SECTOR_SIZE;
    +   newdev->log_sector_size = 9;
     -  newdev->total_length = grub_disk_get_size (disk) - newdev->offset;
     +  newdev->total_sectors = grub_disk_get_size (disk) - newdev->offset;
        grub_memcpy (newdev->uuid, uuid, sizeof (uuid));
    @@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
            crypt->log_sector_size = sizeof (unsigned int) * 8
                - __builtin_clz ((unsigned int) segment.sector_size) - 1;
            if (grub_strcmp (segment.size, "dynamic") == 0)
    --  crypt->total_length = (grub_disk_get_size (disk) >> 
(crypt->log_sector_size - disk->log_sector_size))
    -+  crypt->total_sectors = (grub_disk_get_size (disk) >> 
(crypt->log_sector_size - disk->log_sector_size))
    -                          - crypt->offset;
    +-  crypt->total_length = grub_disk_get_size (disk) - crypt->offset;
    ++  crypt->total_sectors = grub_disk_get_size (disk) - crypt->offset;
            else
    --  crypt->total_length = grub_strtoull (segment.size, NULL, 10) >> 
crypt->log_sector_size;
    -+  crypt->total_sectors = grub_strtoull (segment.size, NULL, 10) >> 
crypt->log_sector_size;
    +-  crypt->total_length = grub_strtoull (segment.size, NULL, 10);
    ++  crypt->total_sectors = grub_strtoull (segment.size, NULL, 10);
      
            ret = luks2_decrypt_key (candidate_key, disk, crypt, &keyslot,
                               (const grub_uint8_t *) passphrase, grub_strlen 
(passphrase));
 9:  74c6232c9 !  3:  d79204f6c cryptodisk: Rename offset in grub_cryptodisk_t 
to offset_sectors.
    @@ grub-core/disk/luks.c: configure_ciphers (grub_disk_t disk, const char 
*check_uu
     -  newdev->offset = grub_be_to_cpu32 (header.payloadOffset);
     +  newdev->offset_sectors = grub_be_to_cpu32 (header.payloadOffset);
        newdev->source_disk = NULL;
    -   newdev->log_sector_size = LUKS1_LOG_SECTOR_SIZE;
    +   newdev->log_sector_size = 9;
     -  newdev->total_sectors = grub_disk_get_size (disk) - newdev->offset;
     +  newdev->total_sectors = grub_disk_get_size (disk) - 
newdev->offset_sectors;
        grub_memcpy (newdev->uuid, uuid, sizeof (uuid));
    @@ grub-core/disk/luks.c: configure_ciphers (grub_disk_t disk, const char 
*check_uu
     
      ## grub-core/disk/luks2.c ##
     @@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
    -       grub_dprintf ("luks2", "Trying keyslot %"PRIuGRUB_UINT64_T"\n", 
keyslot.slot_key);
    +       grub_dprintf ("luks2", "Trying keyslot %"PRIuGRUB_SIZE"\n", i);
      
            /* Set up disk according to keyslot's segment. */
     -      crypt->offset = grub_divmod64 (segment.offset, segment.sector_size, 
NULL);
    @@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
            crypt->log_sector_size = sizeof (unsigned int) * 8
                - __builtin_clz ((unsigned int) segment.sector_size) - 1;
            if (grub_strcmp (segment.size, "dynamic") == 0)
    -   crypt->total_sectors = (grub_disk_get_size (disk) >> 
(crypt->log_sector_size - disk->log_sector_size))
    --                         - crypt->offset;
    -+                         - crypt->offset_sectors;
    +-  crypt->total_sectors = grub_disk_get_size (disk) - crypt->offset;
    ++  crypt->total_sectors = grub_disk_get_size (disk) - 
crypt->offset_sectors;
            else
    -   crypt->total_sectors = grub_strtoull (segment.size, NULL, 10) >> 
crypt->log_sector_size;
    +   crypt->total_sectors = grub_strtoull (segment.size, NULL, 10);
      
     
      ## include/grub/cryptodisk.h ##
10:  738fe0139 !  4:  cceded198 luks2: Rename source disk variabled named 
'disk' to 'source' as in luks.c.
    @@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
            crypt->log_sector_size = sizeof (unsigned int) * 8
                - __builtin_clz ((unsigned int) segment.sector_size) - 1;
            if (grub_strcmp (segment.size, "dynamic") == 0)
    --  crypt->total_sectors = (grub_disk_get_size (disk) >> 
(crypt->log_sector_size - disk->log_sector_size))
    -+  crypt->total_sectors = (grub_disk_get_size (source) >> 
(crypt->log_sector_size - source->log_sector_size))
    -                          - crypt->offset_sectors;
    +-  crypt->total_sectors = grub_disk_get_size (disk) - 
crypt->offset_sectors;
    ++  crypt->total_sectors = grub_disk_get_size (source) - 
crypt->offset_sectors;
            else
    -   crypt->total_sectors = grub_strtoull (segment.size, NULL, 10) >> 
crypt->log_sector_size;
    +   crypt->total_sectors = grub_strtoull (segment.size, NULL, 10);
      
     -      ret = luks2_decrypt_key (candidate_key, disk, crypt, &keyslot,
     +      ret = luks2_decrypt_key (candidate_key, source, crypt, &keyslot,
 -:  --------- >  5:  badbd93f8 types: Define GRUB_CHAR_BIT based on compiler 
macro instead of using literal.
 1:  80dd653c9 !  6:  4839ead9b luks2: Fix use of incorrect index and some 
grub_error() messages.
    @@ Metadata
     Author: Glenn Washburn <development@efficientek.com>
     
      ## Commit message ##
    -    luks2: Fix use of incorrect index and some grub_error() messages.
    +    luks2: Use correct index variable when looping in luks2_get_keyslot.
     
    -    When looping over the digests and segments, the loop variable is j, 
but the
    -    variable i is used to index in the the digests and segments json 
array. The
    -    variable i is the keyslot index. Similarly, there are several 
grub_error()
    -    statements using the wrong index in constructing the error string.
    +    The loop variable j should be used to index the digests and segments 
json
    +    array, instead of the variable i, which is the keyslot index.
     
      ## grub-core/disk/luks2.c ##
     @@ grub-core/disk/luks2.c: luks2_get_keyslot (grub_luks2_keyslot_t *k, 
grub_luks2_digest_t *d, grub_luks2_s
    @@ grub-core/disk/luks2.c: luks2_get_keyslot (grub_luks2_keyslot_t *k, 
grub_luks2_d
      
            if ((d->keyslots & (1 << idx)))
        break;
    -     }
    -   if (j == size)
    --      return grub_error (GRUB_ERR_FILE_NOT_FOUND, "No digest for keyslot 
%"PRIuGRUB_SIZE);
    -+      return grub_error (GRUB_ERR_FILE_NOT_FOUND, "No digest for keyslot 
%"PRIuGRUB_SIZE, i);
    - 
    -   /* Get segment that matches the digest. */
    -   if (grub_json_getvalue (&segments, root, "segments") ||
    -       grub_json_getsize (&size, &segments))
    +@@ grub-core/disk/luks2.c: luks2_get_keyslot (grub_luks2_keyslot_t *k, 
grub_luks2_digest_t *d, grub_luks2_s
          return grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not get segments");
    --  for (j = 0; j < size; j++)
    -+  for (i = j, j = 0; j < size; j++)
    +   for (j = 0; j < size; j++)
          {
     -      if (grub_json_getchild (&segment, &segments, i) ||
     +      if (grub_json_getchild (&segment, &segments, j) ||
    @@ grub-core/disk/luks2.c: luks2_get_keyslot (grub_luks2_keyslot_t *k, 
grub_luks2_d
      
            if ((d->segments & (1 << idx)))
        break;
    -     }
    -   if (j == size)
    --    return grub_error (GRUB_ERR_FILE_NOT_FOUND, "No segment for digest 
%"PRIuGRUB_SIZE);
    -+    return grub_error (GRUB_ERR_FILE_NOT_FOUND, "No segment for digest 
%"PRIuGRUB_SIZE, i);
    - 
    -   return GRUB_ERR_NONE;
    - }
 2:  e4cf8ab40 <  -:  --------- luks2: Improve readability in luks2_get_keyslot.
 -:  --------- >  7:  21b745c11 luks2: Rename variable i to keyslot_idx in 
luks2_get_keyslot.
 -:  --------- >  8:  21a3962b9 luks2: Rename index variable j to i.
 -:  --------- >  9:  b3b361c49 luks2: Split idx into three variables: 
keyslot_key, digest_key, segment_key.
 -:  --------- > 10:  8ac7af919 luks2: Improve error messages in 
luks2_get_keyslot.
 3:  1f65a04e0 ! 11:  31b9f0b83 luks2: Use more intuitive keyslot key instead 
of index when naming keyslot.
    @@ Commit message
         example, say you have a LUKS2 device with a key in slot 1 and slot 4. 
When
         using the password for slot 4 to unlock the device, the messages using 
the
         index of the keyslot will mention keyslot 1 (its a zero-based index).
    -    Furthermore,with this change the keyslot number will align with the 
number
    +    Furthermore, with this change the keyslot number will align with the 
number
         used to reference the keyslot when using the --key-slot argument to
         cryptsetup.
     
    @@ grub-core/disk/luks2.c: typedef struct grub_luks2_header 
grub_luks2_header_t;
        grub_int64_t key_size;
        grub_int64_t priority;
        struct
    +@@ grub-core/disk/luks2.c: typedef struct grub_luks2_keyslot 
grub_luks2_keyslot_t;
    + 
    + struct grub_luks2_segment
    + {
    ++  grub_uint64_t slot_key;
    +   grub_uint64_t offset;
    +   const char      *size;
    +   const char      *encryption;
    +@@ grub-core/disk/luks2.c: typedef struct grub_luks2_segment 
grub_luks2_segment_t;
    + 
    + struct grub_luks2_digest
    + {
    ++  grub_uint64_t slot_key;
    +   /* Both keyslots and segments are interpreted as bitfields here */
    +   grub_uint64_t   keyslots;
    +   grub_uint64_t   segments;
     @@ grub-core/disk/luks2.c: luks2_get_keyslot (grub_luks2_keyslot_t *k, 
grub_luks2_digest_t *d, grub_luks2_s
      {
        grub_json_t keyslots, keyslot, digests, digest, segments, segment;
    @@ grub-core/disk/luks2.c: luks2_get_keyslot (grub_luks2_keyslot_t *k, 
grub_luks2_d
        return grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not parse digest index 
%"PRIuGRUB_SIZE, i);
      
     -      if ((d->keyslots & (1 << keyslot_key)))
    ++      d->slot_key = digest_key;
     +      if ((d->keyslots & (1 << k->slot_key)))
        break;
          }
    @@ grub-core/disk/luks2.c: luks2_get_keyslot (grub_luks2_keyslot_t *k, 
grub_luks2_d
      
        /* Get segment that matches the digest. */
        if (grub_json_getvalue (&segments, root, "segments") ||
    -@@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
    +@@ grub-core/disk/luks2.c: luks2_get_keyslot (grub_luks2_keyslot_t *k, 
grub_luks2_digest_t *d, grub_luks2_s
    +           luks2_parse_segment (s, &segment))
    +   return grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not parse segment 
index %"PRIuGRUB_SIZE, i);
    + 
    ++      s->slot_key = segment_key;
    +       if ((d->segments & (1 << segment_key)))
    +   break;
    +     }
    +@@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t source,
      
            if (keyslot.priority == 0)
        {
    @@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
     +      grub_dprintf ("luks2", "Trying keyslot %"PRIuGRUB_UINT64_T"\n", 
keyslot.slot_key);
      
            /* Set up disk according to keyslot's segment. */
    -       crypt->offset = grub_divmod64 (segment.offset, segment.sector_size, 
NULL);
    -@@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
    +       crypt->offset_sectors = grub_divmod64 (segment.offset, 
segment.sector_size, NULL);
    +@@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t source,
                               (const grub_uint8_t *) passphrase, grub_strlen 
(passphrase));
            if (ret)
        {
    @@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
          continue;
        }
      
    -@@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
    +@@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t source,
             * TRANSLATORS: It's a cryptographic key slot: one element of an 
array
             * where each element is either empty or holds a key.
             */
 -:  --------- > 12:  87bafa5d9 cryptodisk: Replace some literals with 
constants in grub_cryptodisk_endecrypt.
 4:  fcb72f70d ! 13:  1bc8c867c luks2: grub_cryptodisk_t->total_length is the 
max number of device native sectors
    @@ grub-core/disk/luks2.c: luks2_decrypt_key (grub_uint8_t *out_key,
        const gcry_md_spec_t *hash;
        gcry_err_code_t gcry_ret;
        grub_err_t ret;
    -@@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t disk,
    +@@ grub-core/disk/luks2.c: luks2_recover_key (grub_disk_t source,
            crypt->log_sector_size = sizeof (unsigned int) * 8
                - __builtin_clz ((unsigned int) segment.sector_size) - 1;
            if (grub_strcmp (segment.size, "dynamic") == 0)
    --  crypt->total_length = grub_disk_get_size (disk) - crypt->offset;
    -+  crypt->total_length = (grub_disk_get_size (disk) >> 
(crypt->log_sector_size - disk->log_sector_size))
    -+                         - crypt->offset;
    +-  crypt->total_sectors = grub_disk_get_size (source) - 
crypt->offset_sectors;
    ++  crypt->total_sectors = (grub_disk_get_size (source) >> 
(crypt->log_sector_size - source->log_sector_size))
    ++                         - crypt->offset_sectors;
            else
    --  crypt->total_length = grub_strtoull (segment.size, NULL, 10);
    -+  crypt->total_length = grub_strtoull (segment.size, NULL, 10) >> 
crypt->log_sector_size;
    +-  crypt->total_sectors = grub_strtoull (segment.size, NULL, 10);
    ++  crypt->total_sectors = grub_strtoull (segment.size, NULL, 10) >> 
crypt->log_sector_size;
      
    -       ret = luks2_decrypt_key (candidate_key, disk, crypt, &keyslot,
    +       ret = luks2_decrypt_key (candidate_key, source, crypt, &keyslot,
                               (const grub_uint8_t *) passphrase, grub_strlen 
(passphrase));
 6:  6fe26ba56 ! 14:  c3b6adaeb cryptodisk: Properly handle non-512 byte sized 
sectors.
    @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_endecrypt (struct 
grub_cryptodisk *
          {
            grub_size_t sz = ((dev->cipher->cipher->blocksize
                         + sizeof (grub_uint32_t) - 1)
    +                   / sizeof (grub_uint32_t));
    +-      grub_uint32_t iv[(GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE + 3) / 4];
    ++      grub_uint32_t iv[(GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE + 3) / 4] 
__attribute__((aligned (sizeof (grub_uint64_t))));
    + 
    +       if (dev->rekey)
    +   {
     @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_endecrypt (struct 
grub_cryptodisk *dev,
            if (!ctx)
              return GPG_ERR_OUT_OF_MEMORY;
    @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_endecrypt (struct 
grub_cryptodisk *
     -    iv[1] = grub_cpu_to_le32 (sector >> 32);
     -    /* FALLTHROUGH */
        case GRUB_CRYPTODISK_MODE_IV_PLAIN:
    --    iv[0] = grub_cpu_to_le32 (sector & 0xFFFFFFFF);
    +-    iv[0] = grub_cpu_to_le32 (sector & GRUB_TYPE_U_MAX (iv[0]));
     +    /*
     +     * The IV is a 32 or 64 bit value of the dm-crypt native sector
     +     * number. If using 32 bit IV mode, zero out the most significant
     +     * 32 bits.
     +     */
     +    {
    -+      grub_uint64_t *iv64 = (grub_uint64_t *)iv;
    ++      grub_uint64_t *iv64 = (grub_uint64_t *) iv;
     +      *iv64 = grub_cpu_to_le64 (sector << (log_sector_size
     +                                           - 
GRUB_CRYPTODISK_IV_LOG_SIZE));
     +      if (dev->mode_iv == GRUB_CRYPTODISK_MODE_IV_PLAIN)
    @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_endecrypt (struct 
grub_cryptodisk *
     +    }
          break;
        case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64:
    --    iv[1] = grub_cpu_to_le32 (sector >> (32 - dev->log_sector_size));
    ++    /* The IV is the 64 bit byte offset of the sector. */
    +     iv[1] = grub_cpu_to_le32 (sector >> (GRUB_TYPE_BITS (iv[1])
    +-                                         - dev->log_sector_size));
     -    iv[0] = grub_cpu_to_le32 ((sector << dev->log_sector_size)
    -+    iv[1] = grub_cpu_to_le32 (sector >> (32 - log_sector_size));
    ++                                         - log_sector_size));
     +    iv[0] = grub_cpu_to_le32 ((sector << log_sector_size)
    -                               & 0xFFFFFFFF);
    +                               & GRUB_TYPE_U_MAX (iv[0]));
          break;
        case GRUB_CRYPTODISK_MODE_IV_BENBI:
     @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_endecrypt (struct 
grub_cryptodisk *dev,
    @@ grub-core/disk/cryptodisk.c: grub_cryptodisk_write (grub_disk_t disk, 
grub_disk_
      ## grub-core/disk/luks.c ##
     @@ grub-core/disk/luks.c: configure_ciphers (grub_disk_t disk, const char 
*check_uuid,
            return NULL;
    -   newdev->offset = grub_be_to_cpu32 (header.payloadOffset);
    +   newdev->offset_sectors = grub_be_to_cpu32 (header.payloadOffset);
        newdev->source_disk = NULL;
     -  newdev->log_sector_size = 9;
    -+  newdev->log_sector_size = LUKS1_LOG_SECTOR_SIZE;
    -   newdev->total_length = grub_disk_get_size (disk) - newdev->offset;
    ++  newdev->log_sector_size = GRUB_LUKS1_LOG_SECTOR_SIZE;
    +   newdev->total_sectors = grub_disk_get_size (disk) - 
newdev->offset_sectors;
        grub_memcpy (newdev->uuid, uuid, sizeof (uuid));
        newdev->modname = "luks";
     @@ grub-core/disk/luks.c: luks_recover_key (grub_disk_t source,
    @@ grub-core/disk/luks.c: luks_recover_key (grub_disk_t source,
      
     -      gcry_err = grub_cryptodisk_decrypt (dev, split_key, length, 0);
     +      gcry_err = grub_cryptodisk_decrypt (dev, split_key, length, 0,
    -+                                    LUKS1_LOG_SECTOR_SIZE);
    ++                                    GRUB_LUKS1_LOG_SECTOR_SIZE);
            if (gcry_err)
        {
          grub_free (split_key);
    @@ grub-core/disk/luks2.c: luks2_decrypt_key (grub_uint8_t *out_key,
     +   * regardless of encrypted data sector size.
     +   */
     +  gcry_ret = grub_cryptodisk_decrypt (crypt, split_key, k->area.size, 0,
    -+                                LUKS1_LOG_SECTOR_SIZE);
    ++                                GRUB_LUKS1_LOG_SECTOR_SIZE);
        if (gcry_ret)
          {
            ret = grub_crypto_gcry_error (gcry_ret);
    @@ include/grub/cryptodisk.h: typedef enum
      #define GRUB_CRYPTODISK_MAX_UUID_LENGTH 71
      
     +/* LUKS1 specification defines the block size to always be 512 bytes. */
    -+#define LUKS1_LOG_SECTOR_SIZE 9
    ++#define GRUB_LUKS1_LOG_SECTOR_SIZE 9
     +
     +/* By default dm-crypt increments the IV every 512 bytes. */
     +#define GRUB_CRYPTODISK_IV_LOG_SIZE 9
 7:  3918a9013 <  -:  --------- cryptodisk: Replace some literals with 
constants in grub_cryptodisk_endecrypt.
 -:  --------- > 15:  f0758a06f luks2: Better error handling when setting up 
the cryptodisk.
 -:  --------- > 16:  6ef5c9965 luks2: Error check segment.sector_size.
-- 
2.27.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]