"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/lib/luks2/luks2_digest.c" (13 Jan 2022, 11735 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_digest.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.3.6_vs_2.4.0.

    1 /*
    2  * LUKS - Linux Unified Key Setup v2, digest handling
    3  *
    4  * Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2015-2021 Milan Broz
    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 extern const digest_handler PBKDF2_digest;
   25 
   26 static const digest_handler *digest_handlers[LUKS2_DIGEST_MAX] = {
   27     &PBKDF2_digest,
   28     NULL
   29 };
   30 
   31 static const digest_handler *LUKS2_digest_handler_type(const char *type)
   32 {
   33     int i;
   34 
   35     for (i = 0; i < LUKS2_DIGEST_MAX && digest_handlers[i]; i++) {
   36         if (!strcmp(digest_handlers[i]->name, type))
   37             return digest_handlers[i];
   38     }
   39 
   40     return NULL;
   41 }
   42 
   43 static const digest_handler *LUKS2_digest_handler(struct crypt_device *cd, int digest)
   44 {
   45     struct luks2_hdr *hdr;
   46     json_object *jobj1, *jobj2;
   47 
   48     if (digest < 0)
   49         return NULL;
   50 
   51     if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
   52         return NULL;
   53 
   54     if (!(jobj1 = LUKS2_get_digest_jobj(hdr, digest)))
   55         return NULL;
   56 
   57     if (!json_object_object_get_ex(jobj1, "type", &jobj2))
   58         return NULL;
   59 
   60     return LUKS2_digest_handler_type(json_object_get_string(jobj2));
   61 }
   62 
   63 static int LUKS2_digest_find_free(struct luks2_hdr *hdr)
   64 {
   65     int digest = 0;
   66 
   67     while (LUKS2_get_digest_jobj(hdr, digest) && digest < LUKS2_DIGEST_MAX)
   68         digest++;
   69 
   70     return digest < LUKS2_DIGEST_MAX ? digest : -1;
   71 }
   72 
   73 int LUKS2_digest_create(struct crypt_device *cd,
   74     const char *type,
   75     struct luks2_hdr *hdr,
   76     const struct volume_key *vk)
   77 {
   78     int digest;
   79     const digest_handler *dh;
   80 
   81     dh = LUKS2_digest_handler_type(type);
   82     if (!dh)
   83         return -EINVAL;
   84 
   85     digest = LUKS2_digest_find_free(hdr);
   86     if (digest < 0)
   87         return -EINVAL;
   88 
   89     log_dbg(cd, "Creating new digest %d (%s).", digest, type);
   90 
   91     return dh->store(cd, digest, vk->key, vk->keylength) ?: digest;
   92 }
   93 
   94 int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
   95 {
   96     char keyslot_name[16];
   97     json_object *jobj_digests, *jobj_digest_keyslots;
   98 
   99     if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
  100         return -ENOMEM;
  101 
  102     json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
  103 
  104     json_object_object_foreach(jobj_digests, key, val) {
  105         json_object_object_get_ex(val, "keyslots", &jobj_digest_keyslots);
  106         if (LUKS2_array_jobj(jobj_digest_keyslots, keyslot_name))
  107             return atoi(key);
  108     }
  109 
  110     return -ENOENT;
  111 }
  112 
  113 int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
  114     struct luks2_hdr *hdr __attribute__((unused)),
  115     int digest,
  116     const struct volume_key *vk)
  117 {
  118     const digest_handler *h;
  119     int r;
  120 
  121     h = LUKS2_digest_handler(cd, digest);
  122     if (!h)
  123         return -EINVAL;
  124 
  125     r = h->verify(cd, digest, vk->key, vk->keylength);
  126     if (r < 0) {
  127         log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
  128         return r;
  129     }
  130 
  131     return digest;
  132 }
  133 
  134 int LUKS2_digest_verify(struct crypt_device *cd,
  135     struct luks2_hdr *hdr,
  136     const struct volume_key *vk,
  137     int keyslot)
  138 {
  139     int digest;
  140 
  141     digest = LUKS2_digest_by_keyslot(hdr, keyslot);
  142     if (digest < 0)
  143         return digest;
  144 
  145     log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
  146 
  147     return LUKS2_digest_verify_by_digest(cd, hdr, digest, vk);
  148 }
  149 
  150 int LUKS2_digest_dump(struct crypt_device *cd, int digest)
  151 {
  152     const digest_handler *h;
  153 
  154     if (!(h = LUKS2_digest_handler(cd, digest)))
  155         return -EINVAL;
  156 
  157     return h->dump(cd, digest);
  158 }
  159 
  160 int LUKS2_digest_any_matching(struct crypt_device *cd,
  161         struct luks2_hdr *hdr,
  162         const struct volume_key *vk)
  163 {
  164     int digest;
  165 
  166     for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++)
  167         if (LUKS2_digest_verify_by_digest(cd, hdr, digest, vk) == digest)
  168             return digest;
  169 
  170     return -ENOENT;
  171 }
  172 
  173 int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
  174     struct luks2_hdr *hdr,
  175     int segment,
  176     const struct volume_key *vk)
  177 {
  178     return LUKS2_digest_verify_by_digest(cd, hdr, LUKS2_digest_by_segment(hdr, segment), vk);
  179 }
  180 
  181 /* FIXME: segment can have more digests */
  182 int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment)
  183 {
  184     char segment_name[16];
  185     json_object *jobj_digests, *jobj_digest_segments;
  186 
  187     if (segment == CRYPT_DEFAULT_SEGMENT)
  188         segment = LUKS2_get_default_segment(hdr);
  189 
  190     json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
  191 
  192     if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
  193         return -EINVAL;
  194 
  195     json_object_object_foreach(jobj_digests, key, val) {
  196         json_object_object_get_ex(val, "segments", &jobj_digest_segments);
  197         if (!LUKS2_array_jobj(jobj_digest_segments, segment_name))
  198             continue;
  199 
  200         return atoi(key);
  201     }
  202 
  203     return -ENOENT;
  204 }
  205 
  206 static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
  207                  int keyslot, int digest, int assign)
  208 {
  209     json_object *jobj1, *jobj_digest, *jobj_digest_keyslots;
  210     char num[16];
  211 
  212     log_dbg(cd, "Keyslot %i %s digest %i.", keyslot, assign ? "assigned to" : "unassigned from", digest);
  213 
  214     jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
  215     if (!jobj_digest)
  216         return -EINVAL;
  217 
  218     json_object_object_get_ex(jobj_digest, "keyslots", &jobj_digest_keyslots);
  219     if (!jobj_digest_keyslots)
  220         return -EINVAL;
  221 
  222     if (snprintf(num, sizeof(num), "%d", keyslot) < 0)
  223         return -EINVAL;
  224 
  225     if (assign) {
  226         jobj1 = LUKS2_array_jobj(jobj_digest_keyslots, num);
  227         if (!jobj1)
  228             json_object_array_add(jobj_digest_keyslots, json_object_new_string(num));
  229     } else {
  230         jobj1 = LUKS2_array_remove(jobj_digest_keyslots, num);
  231         if (jobj1)
  232             json_object_object_add(jobj_digest, "keyslots", jobj1);
  233     }
  234 
  235     return 0;
  236 }
  237 
  238 int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
  239             int keyslot, int digest, int assign, int commit)
  240 {
  241     json_object *jobj_digests;
  242     int r = 0;
  243 
  244     if (digest == CRYPT_ANY_DIGEST) {
  245         json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
  246 
  247         json_object_object_foreach(jobj_digests, key, val) {
  248             UNUSED(val);
  249             r = assign_one_digest(cd, hdr, keyslot, atoi(key), assign);
  250             if (r < 0)
  251                 break;
  252         }
  253     } else
  254         r = assign_one_digest(cd, hdr, keyslot, digest, assign);
  255 
  256     if (r < 0)
  257         return r;
  258 
  259     return commit ? LUKS2_hdr_write(cd, hdr) : 0;
  260 }
  261 
  262 static int assign_all_segments(struct crypt_device *cd __attribute__((unused)),
  263                    struct luks2_hdr *hdr, int digest, int assign)
  264 {
  265     json_object *jobj1, *jobj_digest, *jobj_digest_segments;
  266 
  267     jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
  268     if (!jobj_digest)
  269         return -EINVAL;
  270 
  271     json_object_object_get_ex(jobj_digest, "segments", &jobj_digest_segments);
  272     if (!jobj_digest_segments)
  273         return -EINVAL;
  274 
  275     if (assign) {
  276         json_object_object_foreach(LUKS2_get_segments_jobj(hdr), key, value) {
  277             UNUSED(value);
  278             jobj1 = LUKS2_array_jobj(jobj_digest_segments, key);
  279             if (!jobj1)
  280                 json_object_array_add(jobj_digest_segments, json_object_new_string(key));
  281         }
  282     } else {
  283         jobj1 = json_object_new_array();
  284         if (!jobj1)
  285             return -ENOMEM;
  286         json_object_object_add(jobj_digest, "segments", jobj1);
  287     }
  288 
  289     return 0;
  290 }
  291 
  292 static int assign_one_segment(struct crypt_device *cd, struct luks2_hdr *hdr,
  293                  int segment, int digest, int assign)
  294 {
  295     json_object *jobj1, *jobj_digest, *jobj_digest_segments;
  296     char num[16];
  297 
  298     log_dbg(cd, "Segment %i %s digest %i.", segment, assign ? "assigned to" : "unassigned from", digest);
  299 
  300     jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
  301     if (!jobj_digest)
  302         return -EINVAL;
  303 
  304     json_object_object_get_ex(jobj_digest, "segments", &jobj_digest_segments);
  305     if (!jobj_digest_segments)
  306         return -EINVAL;
  307 
  308     if (snprintf(num, sizeof(num), "%d", segment) < 0)
  309         return -EINVAL;
  310 
  311     if (assign) {
  312         jobj1 = LUKS2_array_jobj(jobj_digest_segments, num);
  313         if (!jobj1)
  314             json_object_array_add(jobj_digest_segments, json_object_new_string(num));
  315     } else {
  316         jobj1 = LUKS2_array_remove(jobj_digest_segments, num);
  317         if (jobj1)
  318             json_object_object_add(jobj_digest, "segments", jobj1);
  319     }
  320 
  321     return 0;
  322 }
  323 
  324 int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
  325             int segment, int digest, int assign, int commit)
  326 {
  327     json_object *jobj_digests;
  328     int r = 0;
  329 
  330     if (segment == CRYPT_DEFAULT_SEGMENT)
  331         segment = LUKS2_get_default_segment(hdr);
  332 
  333     if (digest == CRYPT_ANY_DIGEST) {
  334         json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
  335 
  336         json_object_object_foreach(jobj_digests, key, val) {
  337             UNUSED(val);
  338             if (segment == CRYPT_ANY_SEGMENT)
  339                 r = assign_all_segments(cd, hdr, atoi(key), assign);
  340             else
  341                 r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
  342             if (r < 0)
  343                 break;
  344         }
  345     } else {
  346         if (segment == CRYPT_ANY_SEGMENT)
  347             r = assign_all_segments(cd, hdr, digest, assign);
  348         else
  349             r = assign_one_segment(cd, hdr, segment, digest, assign);
  350     }
  351 
  352     if (r < 0)
  353         return r;
  354 
  355     return commit ? LUKS2_hdr_write(cd, hdr) : 0;
  356 }
  357 
  358 static int digest_unused(json_object *jobj_digest)
  359 {
  360     json_object *jobj;
  361 
  362     json_object_object_get_ex(jobj_digest, "segments", &jobj);
  363     if (!jobj || !json_object_is_type(jobj, json_type_array) || json_object_array_length(jobj) > 0)
  364         return 0;
  365 
  366     json_object_object_get_ex(jobj_digest, "keyslots", &jobj);
  367     if (!jobj || !json_object_is_type(jobj, json_type_array))
  368         return 0;
  369 
  370     return json_object_array_length(jobj) > 0 ? 0 : 1;
  371 }
  372 
  373 void LUKS2_digests_erase_unused(struct crypt_device *cd,
  374     struct luks2_hdr *hdr)
  375 {
  376     json_object *jobj_digests;
  377 
  378     json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
  379     if (!jobj_digests || !json_object_is_type(jobj_digests, json_type_object))
  380         return;
  381 
  382     json_object_object_foreach(jobj_digests, key, val) {
  383         if (digest_unused(val)) {
  384             log_dbg(cd, "Erasing unused digest %d.", atoi(key));
  385             json_object_object_del(jobj_digests, key);
  386         }
  387     }
  388 }
  389 
  390 /* Key description helpers */
  391 static char *get_key_description_by_digest(struct crypt_device *cd, int digest)
  392 {
  393     char *desc, digest_str[3];
  394     int r;
  395     size_t len;
  396 
  397     if (!crypt_get_uuid(cd))
  398         return NULL;
  399 
  400     r = snprintf(digest_str, sizeof(digest_str), "d%u", digest);
  401     if (r < 0 || (size_t)r >= sizeof(digest_str))
  402         return NULL;
  403 
  404     /* "cryptsetup:<uuid>-<digest_str>" + \0 */
  405     len = strlen(crypt_get_uuid(cd)) + strlen(digest_str) + 13;
  406 
  407     desc = malloc(len);
  408     if (!desc)
  409            return NULL;
  410 
  411     r = snprintf(desc, len, "%s:%s-%s", "cryptsetup", crypt_get_uuid(cd), digest_str);
  412     if (r < 0 || (size_t)r >= len) {
  413            free(desc);
  414            return NULL;
  415     }
  416 
  417     return desc;
  418 }
  419 
  420 int LUKS2_key_description_by_segment(struct crypt_device *cd,
  421         struct luks2_hdr *hdr, struct volume_key *vk, int segment)
  422 {
  423     char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(hdr, segment));
  424     int r;
  425 
  426     r = crypt_volume_key_set_description(vk, desc);
  427     free(desc);
  428     return r;
  429 }
  430 
  431 int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
  432         struct luks2_hdr *hdr, struct volume_key *vk, int keyslot)
  433 {
  434     char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_keyslot(hdr, keyslot));
  435     int r;
  436 
  437     r = crypt_volume_key_set_description(vk, desc);
  438     if (!r)
  439         r = crypt_volume_key_load_in_keyring(cd, vk);
  440 
  441     free(desc);
  442     return r;
  443 }
  444 
  445 int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
  446         struct luks2_hdr *hdr __attribute__((unused)), struct volume_key *vk, int digest)
  447 {
  448     char *desc = get_key_description_by_digest(cd, digest);
  449     int r;
  450 
  451     r = crypt_volume_key_set_description(vk, desc);
  452     if (!r)
  453         r = crypt_volume_key_load_in_keyring(cd, vk);
  454 
  455     free(desc);
  456     return r;
  457 }