Merge branch 'upstream' into tizen
[platform/upstream/cryptsetup.git] / lib / luks2 / luks2_keyslot.c
index d93f2dd..5cf4b83 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * LUKS - Linux Unified Key Setup v2, keyslot handling
  *
- * Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2015-2021 Milan Broz
+ * Copyright (C) 2015-2023 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2015-2023 Milan Broz
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -34,7 +34,7 @@ static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
 };
 
 static const keyslot_handler
-*LUKS2_keyslot_handler_type(struct crypt_device *cd, const char *type)
+*LUKS2_keyslot_handler_type(const char *type)
 {
        int i;
 
@@ -64,18 +64,25 @@ static const keyslot_handler
        if (!json_object_object_get_ex(jobj1, "type", &jobj2))
                return NULL;
 
-       return LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj2));
+       return LUKS2_keyslot_handler_type(json_object_get_string(jobj2));
 }
 
-int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr)
+int LUKS2_keyslot_find_empty(struct crypt_device *cd, struct luks2_hdr *hdr, size_t keylength)
 {
        int i;
 
        for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++)
                if (!LUKS2_get_keyslot_jobj(hdr, i))
-                       return i;
+                       break;
+
+       if (i == LUKS2_KEYSLOTS_MAX)
+               return -EINVAL;
 
-       return -EINVAL;
+       /* Check also there is a space for the key in keyslots area */
+       if (keylength && LUKS2_find_area_gap(cd, hdr, keylength, NULL, NULL) < 0)
+               return -ENOSPC;
+
+       return i;
 }
 
 /* Check if a keyslot is assigned to specific segment */
@@ -554,7 +561,7 @@ out:
 
                if (r == -ENOMEM)
                        log_err(cd, _("Not enough available memory to open a keyslot."));
-               else if (r != -EPERM)
+               else if (r != -EPERM && r != -ENOENT)
                        log_err(cd, _("Keyslot open failed."));
        }
        return r;
@@ -591,46 +598,13 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
        if (r < 0) {
                if (r == -ENOMEM)
                        log_err(cd, _("Not enough available memory to open a keyslot."));
-               else if (r != -EPERM)
+               else if (r != -EPERM && r != -ENOENT)
                        log_err(cd, _("Keyslot open failed."));
        }
 
        return r;
 }
 
-int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
-       struct luks2_hdr *hdr,
-       int keyslot,
-       const struct crypt_params_reencrypt *params)
-{
-       const keyslot_handler *h;
-       int r;
-
-       if (keyslot == CRYPT_ANY_SLOT)
-               return -EINVAL;
-
-       /* FIXME: find keyslot by type */
-       h = LUKS2_keyslot_handler_type(cd, "reencrypt");
-       if (!h)
-               return -EINVAL;
-
-       r = reenc_keyslot_alloc(cd, hdr, keyslot, params);
-       if (r < 0)
-               return r;
-
-       r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
-       if (r < 0)
-               return r;
-
-       r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
-       if (r) {
-               log_dbg(cd, "Keyslot validation failed.");
-               return r;
-       }
-
-       return 0;
-}
-
 int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
        struct luks2_hdr *hdr,
        int keyslot,
@@ -669,7 +643,7 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
 
        if (!LUKS2_get_keyslot_jobj(hdr, keyslot)) {
                /* Try to allocate default and empty keyslot type */
-               h = LUKS2_keyslot_handler_type(cd, "luks2");
+               h = LUKS2_keyslot_handler_type("luks2");
                if (!h)
                        return -EINVAL;
 
@@ -775,8 +749,7 @@ int LUKS2_keyslot_dump(struct crypt_device *cd, int keyslot)
        return h->dump(cd, keyslot);
 }
 
-crypt_keyslot_priority LUKS2_keyslot_priority_get(struct crypt_device *cd,
-         struct luks2_hdr *hdr, int keyslot)
+crypt_keyslot_priority LUKS2_keyslot_priority_get(struct luks2_hdr *hdr, int keyslot)
 {
        json_object *jobj_keyslot, *jobj_priority;
 
@@ -810,8 +783,7 @@ int LUKS2_keyslot_priority_set(struct crypt_device *cd, struct luks2_hdr *hdr,
 int placeholder_keyslot_alloc(struct crypt_device *cd,
        int keyslot,
        uint64_t area_offset,
-       uint64_t area_length,
-       size_t volume_key_len)
+       uint64_t area_length)
 {
        struct luks2_hdr *hdr;
        json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
@@ -892,7 +864,7 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
        json_object_object_foreach(jobj_keyslots, slot, val) {
                keyslot = atoi(slot);
                json_object_object_get_ex(val, "type", &jobj_type);
-               h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
+               h = LUKS2_keyslot_handler_type(json_object_get_string(jobj_type));
                if (!h)
                        continue;
                if (h->validate && h->validate(cd, val)) {
@@ -914,7 +886,7 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj)
                return -EINVAL;
        }
 
-       if (!(reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count) {
+       if (reencrypt_count && !LUKS2_reencrypt_requirement_candidate(&dummy)) {
                log_dbg(cd, "Missing reencryption requirement flag.");
                return -EINVAL;
        }
@@ -939,9 +911,9 @@ void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_keyslots)
                    !json_object_is_type(jobj_type, json_type_string))
                        continue;
 
-               h = LUKS2_keyslot_handler_type(cd, json_object_get_string(jobj_type));
+               h = LUKS2_keyslot_handler_type(json_object_get_string(jobj_type));
                if (h && h->repair)
-                       h->repair(cd, val);
+                       h->repair(val);
        }
 }
 
@@ -966,3 +938,40 @@ int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type)
 
        return -ENOENT;
 }
+
+/* assumes valid header, it does not move references in tokens/digests etc! */
+int LUKS2_keyslot_swap(struct crypt_device *cd, struct luks2_hdr *hdr,
+       int keyslot, int keyslot2)
+{
+       json_object *jobj_keyslots, *jobj_keyslot, *jobj_keyslot2;
+       int r;
+
+       if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
+               return -EINVAL;
+
+       jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
+       if (!jobj_keyslot)
+               return -EINVAL;
+
+       jobj_keyslot2 = LUKS2_get_keyslot_jobj(hdr, keyslot2);
+       if (!jobj_keyslot2)
+               return -EINVAL;
+
+       /* This transfer owner of object, no need for json_object_put */
+       json_object_get(jobj_keyslot);
+       json_object_get(jobj_keyslot2);
+
+       json_object_object_del_by_uint(jobj_keyslots, keyslot);
+       r = json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot2);
+       if (r < 0) {
+               log_dbg(cd, "Failed to swap keyslot %d.", keyslot);
+               return r;
+       }
+
+       json_object_object_del_by_uint(jobj_keyslots, keyslot2);
+       r = json_object_object_add_by_uint(jobj_keyslots, keyslot2, jobj_keyslot);
+       if (r < 0)
+               log_dbg(cd, "Failed to swap keyslot2 %d.", keyslot2);
+
+       return r;
+}