[gparted] Capture LUKS mapping master encryption key location (#59)



commit 099b85fe1893053c8518211a5ea93b3d605eddb1
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Fri Mar 26 10:46:56 2021 +0000

    Capture LUKS mapping master encryption key location (#59)
    
    ISSUE OVERVIEW
    
    When GParted tries to resize an open LUKS encryption mapping and the
    volume (master) key was stored in the kernel keyring service [1] it
    fails like this:
    
        Check and repair file system ([Encrypted] ext4) on /dev/...(ERROR)
        + calibrate /dev/sdd1                                      (SUCCESS)
        + check file system on /dev/mapper/sdd1_crypt for errors...(SUCCESS)
        + grow encryption volume to fill the partition             (ERROR)
          + cryptsetup -v resize 'sdd1_crypt'                      (ERROR)
              Command failed with code -1 (wrong or missing parameters).
              Nothing to read on input.
    
    This error occurs with cryptsetup >= 2.0, kernel >= 4.10 and LUKS2
    format because the crypt Device-Mapper target no longer has the volume
    key so cryptsetup resize prompts for a passphrase, but GParted doesn't
    provide it.
    
    THIS COMMIT
    
    Additionally capture the location of the volume (master) key location
    for active encryption mappings.  Do this the using the same method that
    cryptsetup uses [2][3].  Namely if the first character of the KEY is a
    ":" then the key *was* stored in the kernel keyring service, otherwise
    it *is* store in the Device-Mapper crypt target as previously.
    
        # echo -n badpassword | cryptsetup luksFormat --type luks1 /dev/sdb1 -
        # echo -n badpassword | cryptsetup luksOpen /dev/sdb1 sdb1_crypt
        # cryptsetup status sdb1_crypt | egrep 'type|key location'
          type:         LUKS1
          key location: dm-crypt
    
        # echo -n badpassword | cryptsetup luksFormat --type luks2 /dev/sdb2 -
        # echo -n badpassword | cryptsetup luksOpen /dev/sdb2 sdb2_crypt
        # cryptsetup status sdb2_crypt | egrep 'type|key location'
          type:         LUKS2
          key location: keyring
    
        # dmsetup table --target crypt
        sdb1_crypt: 0 520192 crypt aes-xts-plain64 
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
 0 8:17 4096
        sdb2_crypt: 0 491520 crypt aes-xts-plain64 
:64:logon:cryptsetup:3d040240-97ba-4559-af98-72c3be500498-d0 0 8:18 32768
                                                   ^
    First character of the KEY field --------------'
    
    [1] Integration with the kernel keyring service
        https://gitlab.com/cryptsetup/cryptsetup/blob/v2.0.0/docs/Keyring.txt
        "
        Starting with cryptsetup 2.0 we load [Volume Key] VK in kernel
        keyring by default for LUKSv2 devices ...
    
        In summary, the key description visible in dm-crypt table line is a
        reference to VK that usually no longer exists in kernel keyring
        service if you used cryptsetup to for device activation.
        "
    
    [2] cryptsetup/v2.3.5/lib/libdevmapper.c:_dm_target_query_crypt()
        https://gitlab.com/cryptsetup/cryptsetup/-/blob/v2.3.5/lib/libdevmapper.c#L2031
            if (key_[0] == ':')
                *act_flags |= CRYPT_ACTIVATE_KEYRING_KEY;
    
    [3] cryptsetup/v2.3.5/src/cryptsetup.c:action_status()
        https://gitlab.com/cryptsetup/cryptsetup/-/blob/v2.3.5/src/cryptsetup.c#L839
            log_std("  key location: %s\n", (cad.flags & CRYPT_ACTIVATE_KEYRING_KEY) ? "keyring" : 
"dm-crypt");
    
    Closes #59 - Resize of LUKS2 encrypted file system fails with "Nothing
                 to read on input"

 include/LUKS_Info.h |  7 +++++++
 src/LUKS_Info.cc    | 13 ++++++++++++-
 2 files changed, 19 insertions(+), 1 deletion(-)
---
diff --git a/include/LUKS_Info.h b/include/LUKS_Info.h
index 6ac6c9d0..0a9120f7 100644
--- a/include/LUKS_Info.h
+++ b/include/LUKS_Info.h
@@ -34,12 +34,19 @@
 namespace GParted
 {
 
+enum KeyLocation
+{
+       KEYLOC_DMCrypt = 0,  // Master encryption key is stored in DeviceMapper crypt target
+       KEYLOC_KeyRing       // Master encryption key was stored in kernel Key Ring
+};
+
 struct LUKS_Mapping
 {
        Glib::ustring name;       // Name of the dm-crypt mapping
        BlockSpecial  container;  // Underlying block device containing the LUKS mapping
        Byte_Value    offset;     // Offset to the start of the mapping in the underlying block device
        Byte_Value    length;     // Length of the mapping in the underlying block device
+       KeyLocation   key_loc;    // Location where the master encryption key is stored
 };
 
 class LUKS_Info
diff --git a/src/LUKS_Info.cc b/src/LUKS_Info.cc
index 45612bbb..598acf68 100644
--- a/src/LUKS_Info.cc
+++ b/src/LUKS_Info.cc
@@ -72,7 +72,7 @@ void LUKS_Info::load_cache()
        // _status() function:
        //     https://git.fedorahosted.org/cgit/lvm2.git/tree/tools/dmsetup.c?id=v2_02_118#n1715
        // Field 5 onwards are called parameters and documented in the kernel source:
-       //     
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/device-mapper/dm-crypt.txt?id=v4.0
+       //     
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/device-mapper/dm-crypt.txt?id=v5.0
 
        std::vector<Glib::ustring> lines;
        Utils::tokenize( output, lines, "\n" );
@@ -83,6 +83,7 @@ void LUKS_Info::load_cache()
                Utils::tokenize( lines[i], fields, " " );
                const unsigned DMCRYPT_FIELD_Name    = 0;
                const unsigned DMCRYPT_FIELD_length  = 2;
+               const unsigned DMCRYPT_FIELD_key     = 5;
                const unsigned DMCRYPT_FIELD_devpath = 7;
                const unsigned DMCRYPT_FIELD_offset  = 8;
 
@@ -126,6 +127,16 @@ void LUKS_Info::load_cache()
                else
                        continue;
 
+               // Extract LUKS mapping master key location.  Following the cryptsetup
+               // implementation method; first character of KEY field is ":" means the
+               // master key was stored in the kernel key ring, otherwise it is stored in
+               // the Device-Mapper crypt target itself.
+               // * cryptsetup/v2.3.5/lib/libdevmapper.c:_dm_target_query_crypt()
+               //   https://gitlab.com/cryptsetup/cryptsetup/-/blob/v2.3.5/lib/libdevmapper.c#L2031
+               // * cryptsetup/v2.3.5/src/cryptsetup.c:action_status()
+               //   https://gitlab.com/cryptsetup/cryptsetup/-/blob/v2.3.5/src/cryptsetup.c#L839
+               luks_map.key_loc = (fields[DMCRYPT_FIELD_key][0] == ':') ? KEYLOC_KeyRing : KEYLOC_DMCrypt;
+
                luks_mapping_cache.push_back( luks_map );
        }
 }


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