"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/lib/luks2/luks2_keyslot_reenc.c" (13 Jan 2022, 10854 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "luks2_keyslot_reenc.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.2_vs_2.4.3.

    1 /*
    2  * LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
    3  *
    4  * Copyright (C) 2016-2021, Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2016-2021, Ondrej Kozina
    6  *
    7  * This program is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU General Public License
    9  * as published by the Free Software Foundation; either version 2
   10  * of the License, or (at your option) any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   20  */
   21 
   22 #include "luks2_internal.h"
   23 
   24 static int reenc_keyslot_open(struct crypt_device *cd __attribute__((unused)),
   25     int keyslot __attribute__((unused)),
   26     const char *password __attribute__((unused)),
   27     size_t password_len __attribute__((unused)),
   28     char *volume_key __attribute__((unused)),
   29     size_t volume_key_len __attribute__((unused)))
   30 {
   31     return -ENOENT;
   32 }
   33 
   34 int reenc_keyslot_alloc(struct crypt_device *cd,
   35     struct luks2_hdr *hdr,
   36     int keyslot,
   37     const struct crypt_params_reencrypt *params)
   38 {
   39     int r;
   40     json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
   41     uint64_t area_offset, area_length;
   42 
   43     log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot);
   44 
   45     if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
   46         return -ENOMEM;
   47 
   48     if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
   49         return -EINVAL;
   50 
   51     /* encryption doesn't require area (we shift data and backup will be available) */
   52     if (!params->data_shift) {
   53         r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length);
   54         if (r < 0)
   55             return r;
   56     } else { /* we can't have keyslot w/o area...bug? */
   57         r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
   58         if (r < 0)
   59             return r;
   60     }
   61 
   62     jobj_keyslot = json_object_new_object();
   63     if (!jobj_keyslot)
   64         return -ENOMEM;
   65 
   66     jobj_area = json_object_new_object();
   67 
   68     if (params->data_shift) {
   69         json_object_object_add(jobj_area, "type", json_object_new_string("datashift"));
   70         json_object_object_add(jobj_area, "shift_size", crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
   71     } else
   72         /* except data shift protection, initial setting is irrelevant. Type can be changed during reencryption */
   73         json_object_object_add(jobj_area, "type", json_object_new_string("none"));
   74 
   75     json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
   76     json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
   77 
   78     json_object_object_add(jobj_keyslot, "type", json_object_new_string("reencrypt"));
   79     json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(1)); /* useless but mandatory */
   80     json_object_object_add(jobj_keyslot, "mode", json_object_new_string(crypt_reencrypt_mode_to_str(params->mode)));
   81     if (params->direction == CRYPT_REENCRYPT_FORWARD)
   82         json_object_object_add(jobj_keyslot, "direction", json_object_new_string("forward"));
   83     else if (params->direction == CRYPT_REENCRYPT_BACKWARD)
   84         json_object_object_add(jobj_keyslot, "direction", json_object_new_string("backward"));
   85     else
   86         return -EINVAL;
   87 
   88     json_object_object_add(jobj_keyslot, "area", jobj_area);
   89 
   90     json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
   91     if (LUKS2_check_json_size(cd, hdr)) {
   92         log_dbg(cd, "New keyslot too large to fit in free metadata space.");
   93         json_object_object_del_by_uint(jobj_keyslots, keyslot);
   94         return -ENOSPC;
   95     }
   96 
   97     JSON_DBG(cd, hdr->jobj, "JSON:");
   98 
   99     return 0;
  100 }
  101 
  102 static int reenc_keyslot_store_data(struct crypt_device *cd,
  103     json_object *jobj_keyslot,
  104     const void *buffer, size_t buffer_len)
  105 {
  106     int devfd, r;
  107     json_object *jobj_area, *jobj_offset, *jobj_length;
  108     uint64_t area_offset, area_length;
  109     struct device *device = crypt_metadata_device(cd);
  110 
  111     if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
  112         !json_object_object_get_ex(jobj_area, "offset", &jobj_offset) ||
  113         !json_object_object_get_ex(jobj_area, "size", &jobj_length))
  114         return -EINVAL;
  115 
  116     area_offset = crypt_jobj_get_uint64(jobj_offset);
  117     area_length = crypt_jobj_get_uint64(jobj_length);
  118 
  119     if (!area_offset || !area_length || ((uint64_t)buffer_len > area_length))
  120         return -EINVAL;
  121 
  122     devfd = device_open_locked(cd, device, O_RDWR);
  123     if (devfd >= 0) {
  124         if (write_lseek_blockwise(devfd, device_block_size(cd, device),
  125                       device_alignment(device), CONST_CAST(void *)buffer,
  126                       buffer_len, area_offset) < 0)
  127             r = -EIO;
  128         else
  129             r = 0;
  130     } else
  131         r = -EINVAL;
  132 
  133     if (r)
  134         log_err(cd, _("IO error while encrypting keyslot."));
  135 
  136     return r;
  137 }
  138 
  139 static int reenc_keyslot_store(struct crypt_device *cd,
  140     int keyslot,
  141     const char *password __attribute__((unused)),
  142     size_t password_len __attribute__((unused)),
  143     const char *buffer,
  144     size_t buffer_len)
  145 {
  146     struct luks2_hdr *hdr;
  147     json_object *jobj_keyslot;
  148     int r = 0;
  149 
  150     if (!cd || !buffer || !buffer_len)
  151         return -EINVAL;
  152 
  153     if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
  154         return -EINVAL;
  155 
  156     log_dbg(cd, "Reencrypt keyslot %d store.", keyslot);
  157 
  158     jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
  159     if (!jobj_keyslot)
  160         return -EINVAL;
  161 
  162     r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
  163     if (r)
  164         return r;
  165 
  166     r = reenc_keyslot_store_data(cd, jobj_keyslot, buffer, buffer_len);
  167     if (r < 0) {
  168         device_write_unlock(cd, crypt_metadata_device(cd));
  169         return r;
  170     }
  171 
  172     r = LUKS2_hdr_write(cd, hdr);
  173 
  174     device_write_unlock(cd, crypt_metadata_device(cd));
  175 
  176     return r < 0 ? r : keyslot;
  177 }
  178 
  179 static int reenc_keyslot_wipe(struct crypt_device *cd,
  180     int keyslot)
  181 {
  182     struct luks2_hdr *hdr;
  183 
  184     if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
  185         return -EINVAL;
  186 
  187     /* remove reencryption verification data */
  188     LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0);
  189 
  190     return 0;
  191 }
  192 
  193 static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
  194 {
  195     json_object *jobj_keyslot, *jobj_area, *jobj_direction, *jobj_mode, *jobj_resilience,
  196             *jobj1;
  197 
  198     jobj_keyslot = LUKS2_get_keyslot_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), keyslot);
  199     if (!jobj_keyslot)
  200         return -EINVAL;
  201 
  202     if (!json_object_object_get_ex(jobj_keyslot, "direction", &jobj_direction) ||
  203         !json_object_object_get_ex(jobj_keyslot, "mode", &jobj_mode) ||
  204         !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
  205         !json_object_object_get_ex(jobj_area, "type", &jobj_resilience))
  206         return -EINVAL;
  207 
  208     log_std(cd, "\t%-12s%s\n", "Mode:", json_object_get_string(jobj_mode));
  209     log_std(cd, "\t%-12s%s\n", "Direction:", json_object_get_string(jobj_direction));
  210     log_std(cd, "\t%-12s%s\n", "Resilience:", json_object_get_string(jobj_resilience));
  211 
  212     if (!strcmp(json_object_get_string(jobj_resilience), "checksum")) {
  213         json_object_object_get_ex(jobj_area, "hash", &jobj1);
  214         log_std(cd, "\t%-12s%s\n", "Hash:", json_object_get_string(jobj1));
  215         json_object_object_get_ex(jobj_area, "sector_size", &jobj1);
  216         log_std(cd, "\t%-12s%d [bytes]\n", "Hash data:", json_object_get_int(jobj1));
  217     } else if (!strcmp(json_object_get_string(jobj_resilience), "datashift")) {
  218         json_object_object_get_ex(jobj_area, "shift_size", &jobj1);
  219         log_std(cd, "\t%-12s%" PRIu64 "[bytes]\n", "Shift size:", crypt_jobj_get_uint64(jobj1));
  220     }
  221 
  222     json_object_object_get_ex(jobj_area, "offset", &jobj1);
  223     log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
  224 
  225     json_object_object_get_ex(jobj_area, "size", &jobj1);
  226     log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
  227 
  228     return 0;
  229 }
  230 
  231 static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
  232 {
  233     json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction, *jobj_key_size;
  234     const char *mode, *type, *direction;
  235     uint32_t sector_size;
  236     uint64_t shift_size;
  237 
  238     /* mode (string: encrypt,reencrypt,decrypt)
  239      * direction (string:)
  240      * area {
  241      *   type: (string: datashift, journal, checksum, none)
  242      *      hash: (string: checksum only)
  243      *      sector_size (uint32: checksum only)
  244      *      shift_size (uint64: datashift only)
  245      * }
  246      */
  247 
  248     /* area and area type are validated in general validation code */
  249     if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
  250         !json_object_object_get_ex(jobj_area, "type", &jobj_type))
  251         return -EINVAL;
  252 
  253     jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
  254     jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
  255     jobj_direction = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string);
  256 
  257     if (!jobj_mode || !jobj_direction || !jobj_key_size)
  258         return -EINVAL;
  259 
  260     if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) {
  261         log_dbg(cd, "Illegal reencrypt key size.");
  262         return -EINVAL;
  263     }
  264 
  265     mode = json_object_get_string(jobj_mode);
  266     type = json_object_get_string(jobj_type);
  267     direction = json_object_get_string(jobj_direction);
  268 
  269     if (strcmp(mode, "reencrypt") && strcmp(mode, "encrypt") &&
  270         strcmp(mode, "decrypt")) {
  271         log_dbg(cd, "Illegal reencrypt mode %s.", mode);
  272         return -EINVAL;
  273     }
  274 
  275     if (strcmp(direction, "forward") && strcmp(direction, "backward")) {
  276         log_dbg(cd, "Illegal reencrypt direction %s.", direction);
  277         return -EINVAL;
  278     }
  279 
  280     if (!strcmp(type, "checksum")) {
  281         jobj_hash = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "hash", json_type_string);
  282         jobj_sector_size = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "sector_size", json_type_int);
  283         if (!jobj_hash || !jobj_sector_size)
  284             return -EINVAL;
  285         if (!validate_json_uint32(jobj_sector_size))
  286             return -EINVAL;
  287         sector_size = crypt_jobj_get_uint32(jobj_sector_size);
  288         if (sector_size < SECTOR_SIZE || NOTPOW2(sector_size)) {
  289             log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.", sector_size);
  290             return -EINVAL;
  291         }
  292     } else if (!strcmp(type, "datashift")) {
  293         if (!(jobj_shift_size = json_contains(cd, jobj_area, "type:datashift", "Keyslot area", "shift_size", json_type_string)))
  294             return -EINVAL;
  295 
  296         shift_size = crypt_jobj_get_uint64(jobj_shift_size);
  297         if (!shift_size)
  298             return -EINVAL;
  299 
  300         if (MISALIGNED_512(shift_size)) {
  301             log_dbg(cd, "Shift size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
  302             return -EINVAL;
  303         }
  304     }
  305 
  306     return 0;
  307 }
  308 
  309 const keyslot_handler reenc_keyslot = {
  310     .name  = "reencrypt",
  311     .open  = reenc_keyslot_open,
  312     .store = reenc_keyslot_store, /* initialization only or also per every chunk write */
  313     .wipe  = reenc_keyslot_wipe,
  314     .dump  = reenc_keyslot_dump,
  315     .validate  = reenc_keyslot_validate
  316 };