TCRYPT: support keyfiles
[platform/upstream/cryptsetup.git] / lib / setup.c
index d0b25ac..38ec6d5 100644 (file)
@@ -30,6 +30,7 @@
 #include "luks.h"
 #include "loopaes.h"
 #include "verity.h"
+#include "tcrypt.h"
 #include "internal.h"
 
 struct crypt_device {
@@ -69,6 +70,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 +173,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 +248,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)
 {
@@ -616,6 +626,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;
@@ -625,7 +661,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)
@@ -1068,7 +1104,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;
@@ -1076,7 +1113,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);
@@ -1184,6 +1223,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;
 
@@ -1372,7 +1417,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;
@@ -1384,8 +1429,7 @@ int crypt_suspend(struct crypt_device *cd,
                return -EINVAL;
        }
 
-       if (!cd)
-               dm_backend_init();
+       dm_backend_init();
 
        r = dm_status_suspended(cd, name);
        if (r < 0)
@@ -1403,8 +1447,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_backend_exit();
+       dm_backend_exit();
        return r;
 }
 
@@ -2004,6 +2047,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 -EINVAL;
+               r = TCRYPT_activate(cd, name, &cd->tcrypt_hdr,
+                                   &cd->tcrypt_params, flags);
        } else
                log_err(cd, _("Device type is not properly initialised.\n"));
 
@@ -2358,6 +2406,12 @@ uint64_t crypt_get_data_offset(struct crypt_device *cd)
        if (isLOOPAES(cd->type))
                return cd->loopaes_hdr.offset;
 
+       if (isTCRYPT(cd->type)) { // FIXME: system vol.
+               if (!cd->tcrypt_hdr.d.mk_offset)
+                       return 1;
+               return (cd->tcrypt_hdr.d.mk_offset / cd->tcrypt_hdr.d.sector_size);
+       }
+
        return 0;
 }
 
@@ -2372,6 +2426,12 @@ uint64_t crypt_get_iv_offset(struct crypt_device *cd)
        if (isLOOPAES(cd->type))
                return cd->loopaes_hdr.skip;
 
+       if (isTCRYPT(cd->type)) {
+               if (!cd->tcrypt_hdr.d.mk_offset)
+                       return 0;
+               return (cd->tcrypt_hdr.d.mk_offset / cd->tcrypt_hdr.d.sector_size);
+       }
+
        return 0;
 }