450745180fcb71c466e3216d8e785846b7342b03
[platform/upstream/cryptsetup.git] / lib / volumekey.c
1 /*
2  * cryptsetup volume key implementation
3  *
4  * Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org>
5  * Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
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 <string.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <errno.h>
26
27 #include "internal.h"
28
29 struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key)
30 {
31         struct volume_key *vk;
32
33         if (keylength > (SIZE_MAX - sizeof(*vk)))
34                 return NULL;
35
36         vk = malloc(sizeof(*vk) + keylength);
37         if (!vk)
38                 return NULL;
39
40         vk->key_description = NULL;
41         vk->keylength = keylength;
42         vk->id = -1;
43         vk->next = NULL;
44
45         /* keylength 0 is valid => no key */
46         if (vk->keylength) {
47                 if (key)
48                         memcpy(&vk->key, key, keylength);
49                 else
50                         crypt_safe_memzero(&vk->key, keylength);
51         }
52
53         return vk;
54 }
55
56 int crypt_volume_key_set_description(struct volume_key *vk, const char *key_description)
57 {
58         if (!vk)
59                 return -EINVAL;
60
61         free(CONST_CAST(void*)vk->key_description);
62         vk->key_description = NULL;
63         if (key_description && !(vk->key_description = strdup(key_description)))
64                 return -ENOMEM;
65
66         return 0;
67 }
68
69 void crypt_volume_key_set_id(struct volume_key *vk, int id)
70 {
71         if (vk && id >= 0)
72                 vk->id = id;
73 }
74
75 int crypt_volume_key_get_id(const struct volume_key *vk)
76 {
77         return vk ? vk->id : -1;
78 }
79
80 struct volume_key *crypt_volume_key_by_id(struct volume_key *vks, int id)
81 {
82         struct volume_key *vk = vks;
83
84         if (id < 0)
85                 return NULL;
86
87         while (vk && vk->id != id)
88                 vk = vk->next;
89
90         return vk;
91 }
92
93 void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk)
94 {
95         struct volume_key *tmp;
96
97         if (!vks)
98                 return;
99
100         if (!*vks) {
101                 *vks = vk;
102                 return;
103         }
104
105         tmp = *vks;
106
107         while (tmp->next)
108                 tmp = tmp->next;
109
110         tmp->next = vk;
111 }
112
113 struct volume_key *crypt_volume_key_next(struct volume_key *vk)
114 {
115         return vk ? vk->next : NULL;
116 }
117
118 void crypt_free_volume_key(struct volume_key *vk)
119 {
120         struct volume_key *vk_next;
121
122         while (vk) {
123                 crypt_safe_memzero(vk->key, vk->keylength);
124                 vk->keylength = 0;
125                 free(CONST_CAST(void*)vk->key_description);
126                 vk_next = vk->next;
127                 free(vk);
128                 vk = vk_next;
129         }
130 }
131
132 struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength)
133 {
134         int r;
135         struct volume_key *vk;
136
137         vk = crypt_alloc_volume_key(keylength, NULL);
138         if (!vk)
139                 return NULL;
140
141         r = crypt_random_get(cd, vk->key, keylength, CRYPT_RND_KEY);
142         if(r < 0) {
143                 crypt_free_volume_key(vk);
144                 return NULL;
145         }
146         return vk;
147 }