TCRYPT: add dump command
[platform/upstream/cryptsetup.git] / lib / setup.c
index a6d66b5..156e270 100644 (file)
@@ -30,6 +30,7 @@
 #include "luks.h"
 #include "loopaes.h"
 #include "verity.h"
+#include "tcrypt.h"
 #include "internal.h"
 
 struct crypt_device {
@@ -45,6 +46,10 @@ struct crypt_device {
        int password_verify;
        int rng_type;
 
+       // FIXME: switch to union
+       // FIXME: privatre binary headers and access it properly
+       // through sub-library (LUKS1, TCRYPT)
+
        /* used in CRYPT_LUKS1 */
        struct luks_phdr hdr;
        uint64_t PBKDF2_per_sec;
@@ -69,6 +74,10 @@ struct crypt_device {
        unsigned int verity_root_hash_size;
        char *verity_uuid;
 
+       /* used in CRYPT_TCRYPT */
+       struct crypt_params_tcrypt tcrypt_params;
+       struct tcrypt_phdr tcrypt_hdr;
+
        /* callbacks definitions */
        void (*log)(int level, const char *msg, void *usrptr);
        void *log_usrptr;
@@ -168,7 +177,7 @@ struct device *crypt_data_device(struct crypt_device *cd)
        return cd->device;
 }
 
-static int init_crypto(struct crypt_device *ctx)
+int init_crypto(struct crypt_device *ctx)
 {
        int r;
 
@@ -243,6 +252,11 @@ static int isVERITY(const char *type)
        return (type && !strcmp(CRYPT_VERITY, type));
 }
 
+static int isTCRYPT(const char *type)
+{
+       return (type && !strcmp(CRYPT_TCRYPT, type));
+}
+
 /* keyslot helpers */
 static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot)
 {
@@ -530,10 +544,7 @@ int crypt_init(struct crypt_device **cd, const char *device)
        if (r < 0)
                goto bad;
 
-       if (dm_init(h, 1) < 0) {
-               r = -ENOSYS;
-               goto bad;
-       }
+       dm_backend_init();
 
        h->iteration_time = 1000;
        h->password_verify = 0;
@@ -619,6 +630,32 @@ static int _crypt_load_luks1(struct crypt_device *cd, int require_header, int re
        return r;
 }
 
+static int _crypt_load_tcrypt(struct crypt_device *cd, struct crypt_params_tcrypt *params)
+{
+       int r;
+
+       r = init_crypto(cd);
+       if (r < 0)
+               return r;
+
+       memcpy(&cd->tcrypt_params, params, sizeof(*params));
+
+       r = TCRYPT_read_phdr(cd, &cd->tcrypt_hdr, &cd->tcrypt_params);
+
+       cd->tcrypt_params.passphrase = NULL;
+       cd->tcrypt_params.passphrase_size = 0;
+       cd->tcrypt_params.keyfiles = NULL;
+       cd->tcrypt_params.keyfiles_count = 0;
+
+       if (r < 0)
+               return r;
+
+       if (!cd->type && !(cd->type = strdup(CRYPT_TCRYPT)))
+               return -ENOMEM;
+
+       return r;
+}
+
 static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verity *params)
 {
        int r;
@@ -628,7 +665,7 @@ static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verit
        if (r < 0)
                return r;
 
-       if (params->flags & CRYPT_VERITY_NO_HEADER)
+       if (params && params->flags & CRYPT_VERITY_NO_HEADER)
                return -EINVAL;
 
        if (params)
@@ -717,6 +754,9 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
                                goto out;
                        }
                }
+       } else if (isTCRYPT(cd->type)) {
+               r = TCRYPT_init_by_name(cd, name, &dmd, &cd->device,
+                                       &cd->tcrypt_params, &cd->tcrypt_hdr);
        }
 out:
        crypt_free_volume_key(dmd.u.crypt.vk);
@@ -822,6 +862,8 @@ int crypt_init_by_name_and_header(struct crypt_device **cd,
                        (*cd)->type = strdup(CRYPT_LUKS1);
                else if (!strncmp(CRYPT_VERITY, dmd.uuid, sizeof(CRYPT_VERITY)-1))
                        (*cd)->type = strdup(CRYPT_VERITY);
+               else if (!strncmp(CRYPT_TCRYPT, dmd.uuid, sizeof(CRYPT_TCRYPT)-1))
+                       (*cd)->type = strdup(CRYPT_TCRYPT);
                else
                        log_dbg("Unknown UUID set, some parameters are not set.");
        } else
@@ -940,6 +982,11 @@ static int _crypt_format_luks1(struct crypt_device *cd,
                                       &required_alignment,
                                       &alignment_offset, DEFAULT_DISK_ALIGNMENT);
 
+       /* Check early if we cannot allocate block device for key slot access */
+       r = device_block_adjust(cd, cd->device, DEV_OK, 0, NULL, NULL);
+       if(r < 0)
+               return r;
+
        r = LUKS_generate_phdr(&cd->hdr, cd->volume_key, cipher, cipher_mode,
                               (params && params->hash) ? params->hash : "sha1",
                               uuid, LUKS_STRIPES,
@@ -1066,7 +1113,8 @@ static int _crypt_format_verity(struct crypt_device *cd,
                return -ENOMEM;
 
        cd->verity_hdr.flags = params->flags;
-       cd->verity_hdr.hash_name = strdup(params->hash_name);
+       if (!(cd->verity_hdr.hash_name = strdup(params->hash_name)))
+               return -ENOMEM;
        cd->verity_hdr.data_device = NULL;
        cd->verity_hdr.data_block_size = params->data_block_size;
        cd->verity_hdr.hash_block_size = params->hash_block_size;
@@ -1074,7 +1122,9 @@ static int _crypt_format_verity(struct crypt_device *cd,
        cd->verity_hdr.hash_type = params->hash_type;
        cd->verity_hdr.flags = params->flags;
        cd->verity_hdr.salt_size = params->salt_size;
-       cd->verity_hdr.salt = malloc(params->salt_size);
+       if (!(cd->verity_hdr.salt = malloc(params->salt_size)))
+               return -ENOMEM;
+
        if (params->salt)
                memcpy(CONST_CAST(char*)cd->verity_hdr.salt, params->salt,
                       params->salt_size);
@@ -1182,6 +1232,12 @@ int crypt_load(struct crypt_device *cd,
                        return -EINVAL;
                }
                r = _crypt_load_verity(cd, params);
+       } else if (isTCRYPT(requested_type)) {
+               if (cd->type && !isTCRYPT(cd->type)) {
+                       log_dbg("Context is already initialised to type %s", cd->type);
+                       return -EINVAL;
+               }
+               r = _crypt_load_tcrypt(cd, params);
        } else
                return -EINVAL;
 
@@ -1254,7 +1310,10 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
                r = 0;
        } else {
                dmd.size = new_size;
-               r = dm_create_device(cd, name, cd->type, &dmd, 1);
+               if (isTCRYPT(cd->type))
+                       r = -ENOTSUP;
+               else
+                       r = dm_create_device(cd, name, cd->type, &dmd, 1);
        }
 out:
        if (dmd.target == DM_CRYPT) {
@@ -1334,7 +1393,7 @@ void crypt_free(struct crypt_device *cd)
        if (cd) {
                log_dbg("Releasing crypt device %s context.", mdata_device_path(cd));
 
-               dm_exit();
+               dm_backend_exit();
                crypt_free_volume_key(cd->volume_key);
 
                device_free(cd->device);
@@ -1370,7 +1429,7 @@ int crypt_suspend(struct crypt_device *cd,
 
        log_dbg("Suspending volume %s.", name);
 
-       if (!isLUKS(cd->type)) {
+       if (!cd || !isLUKS(cd->type)) {
                log_err(cd, _("This operation is supported only for LUKS device.\n"));
                r = -EINVAL;
                goto out;
@@ -1382,8 +1441,7 @@ int crypt_suspend(struct crypt_device *cd,
                return -EINVAL;
        }
 
-       if (!cd && dm_init(NULL, 1) < 0)
-               return -ENOSYS;
+       dm_backend_init();
 
        r = dm_status_suspended(cd, name);
        if (r < 0)
@@ -1401,8 +1459,7 @@ int crypt_suspend(struct crypt_device *cd,
        else if (r)
                log_err(cd, "Error during suspending device %s.\n", name);
 out:
-       if (!cd)
-               dm_exit();
+       dm_backend_exit();
        return r;
 }
 
@@ -2002,6 +2059,11 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
                        if (cd->verity_root_hash)
                                memcpy(cd->verity_root_hash, volume_key, volume_key_size);
                }
+       } else if (isTCRYPT(cd->type)) {
+               if (!name)
+                       return 0;
+               r = TCRYPT_activate(cd, name, &cd->tcrypt_hdr,
+                                   &cd->tcrypt_params, flags);
        } else
                log_err(cd, _("Device type is not properly initialised.\n"));
 
@@ -2019,13 +2081,16 @@ int crypt_deactivate(struct crypt_device *cd, const char *name)
 
        log_dbg("Deactivating volume %s.", name);
 
-       if (!cd && dm_init(NULL, 1) < 0)
-               return -ENOSYS;
+       if (!cd)
+               dm_backend_init();
 
        switch (crypt_status(cd, name)) {
                case CRYPT_ACTIVE:
                case CRYPT_BUSY:
-                       r = dm_remove_device(cd, name, 0, 0);
+                       if (isTCRYPT(cd->type))
+                               r = TCRYPT_deactivate(cd, name);
+                       else
+                               r = dm_remove_device(cd, name, 0, 0);
                        break;
                case CRYPT_INACTIVE:
                        log_err(cd, _("Device %s is not active.\n"), name);
@@ -2037,7 +2102,7 @@ int crypt_deactivate(struct crypt_device *cd, const char *name)
        }
 
        if (!cd)
-               dm_exit();
+               dm_backend_exit();
 
        return r;
 }
@@ -2072,7 +2137,8 @@ int crypt_volume_key_get(struct crypt_device *cd,
        } else if (isLUKS(cd->type)) {
                r = LUKS_open_key_with_hdr(keyslot, passphrase,
                                        passphrase_size, &cd->hdr, &vk, cd);
-
+       } else if (isTCRYPT(cd->type)) {
+               r = TCRYPT_get_volume_key(cd, &cd->tcrypt_hdr, &cd->tcrypt_params, &vk);
        } else
                log_err(cd, _("This operation is not supported for %s crypt device.\n"), cd->type ?: "(none)");
 
@@ -2167,13 +2233,13 @@ crypt_status_info crypt_status(struct crypt_device *cd, const char *name)
 {
        int r;
 
-       if (!cd && dm_init(NULL, 1) < 0)
-               return CRYPT_INVALID;
+       if (!cd)
+               dm_backend_init();
 
        r = dm_status_device(cd, name);
 
        if (!cd)
-               dm_exit();
+               dm_backend_exit();
 
        if (r < 0 && r != -ENODEV)
                return CRYPT_INVALID;
@@ -2268,6 +2334,8 @@ int crypt_dump(struct crypt_device *cd)
                return _luks_dump(cd);
        else if (isVERITY(cd->type))
                return _verity_dump(cd);
+       else if (isTCRYPT(cd->type))
+               return TCRYPT_dump(cd, &cd->tcrypt_hdr, &cd->tcrypt_params);
 
        log_err(cd, _("Dump operation is not supported for this device type.\n"));
        return -EINVAL;
@@ -2284,6 +2352,9 @@ const char *crypt_get_cipher(struct crypt_device *cd)
        if (isLOOPAES(cd->type))
                return cd->loopaes_cipher;
 
+       if (isTCRYPT(cd->type))
+               return cd->tcrypt_params.cipher;
+
        return NULL;
 }
 
@@ -2298,6 +2369,9 @@ const char *crypt_get_cipher_mode(struct crypt_device *cd)
        if (isLOOPAES(cd->type))
                return cd->loopaes_cipher_mode;
 
+       if (isTCRYPT(cd->type))
+               return cd->tcrypt_params.mode;
+
        return NULL;
 }
 
@@ -2342,6 +2416,9 @@ int crypt_get_volume_key_size(struct crypt_device *cd)
        if (isVERITY(cd->type))
                return cd->verity_root_hash_size;
 
+       if (isTCRYPT(cd->type))
+               return cd->tcrypt_params.key_size;
+
        return 0;
 }
 
@@ -2356,6 +2433,9 @@ uint64_t crypt_get_data_offset(struct crypt_device *cd)
        if (isLOOPAES(cd->type))
                return cd->loopaes_hdr.offset;
 
+       if (isTCRYPT(cd->type))
+               return TCRYPT_get_data_offset(&cd->tcrypt_hdr);
+
        return 0;
 }
 
@@ -2370,6 +2450,9 @@ uint64_t crypt_get_iv_offset(struct crypt_device *cd)
        if (isLOOPAES(cd->type))
                return cd->loopaes_hdr.skip;
 
+       if (isTCRYPT(cd->type))
+               return TCRYPT_get_iv_offset(&cd->tcrypt_hdr);
+
        return 0;
 }
 
@@ -2391,6 +2474,17 @@ int crypt_keyslot_max(const char *type)
        return -EINVAL;
 }
 
+int crypt_keyslot_area(struct crypt_device *cd,
+       int keyslot,
+       uint64_t *offset,
+       uint64_t *length)
+{
+       if (!isLUKS(cd->type))
+               return -EINVAL;
+
+       return LUKS_keyslot_area(&cd->hdr, keyslot, offset, length);
+}
+
 const char *crypt_get_type(struct crypt_device *cd)
 {
        return cd->type;
@@ -2416,8 +2510,7 @@ int crypt_get_verity_info(struct crypt_device *cd,
        return 0;
 }
 
-int crypt_get_active_device(struct crypt_device *cd __attribute__((unused)),
-                           const char *name,
+int crypt_get_active_device(struct crypt_device *cd, const char *name,
                            struct crypt_active_device *cad)
 {
        struct crypt_dm_active_device dmd;
@@ -2430,8 +2523,13 @@ int crypt_get_active_device(struct crypt_device *cd __attribute__((unused)),
        if (dmd.target != DM_CRYPT && dmd.target != DM_VERITY)
                return -ENOTSUP;
 
-       cad->offset     = dmd.u.crypt.offset;
-       cad->iv_offset  = dmd.u.crypt.iv_offset;
+       if (cd && isTCRYPT(cd->type)) {
+               cad->offset     = TCRYPT_get_data_offset(&cd->tcrypt_hdr);
+               cad->iv_offset  = TCRYPT_get_iv_offset(&cd->tcrypt_hdr);
+       } else {
+               cad->offset     = dmd.u.crypt.offset;
+               cad->iv_offset  = dmd.u.crypt.iv_offset;
+       }
        cad->size       = dmd.size;
        cad->flags      = dmd.flags;