Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/libsa/geli/geliboot.c
34860 views
1
/*-
2
* Copyright (c) 2015 Allan Jude <[email protected]>
3
* Copyright (c) 2005-2011 Pawel Jakub Dawidek <[email protected]>
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <stand.h>
29
#include <stdarg.h>
30
#include "geliboot.h"
31
#include "geliboot_internal.h"
32
33
struct known_dev {
34
char name[GELIDEV_NAMELEN];
35
struct geli_dev *gdev;
36
SLIST_ENTRY(known_dev) entries;
37
};
38
39
SLIST_HEAD(known_dev_list, known_dev) known_devs_head =
40
SLIST_HEAD_INITIALIZER(known_devs_head);
41
42
static geli_ukey saved_keys[GELI_MAX_KEYS];
43
static unsigned int nsaved_keys = 0;
44
45
/*
46
* Copy keys from local storage to the keybuf struct.
47
* Destroy the local storage when finished.
48
*/
49
void
50
geli_export_key_buffer(struct keybuf *fkeybuf)
51
{
52
unsigned int i;
53
54
for (i = 0; i < nsaved_keys; i++) {
55
fkeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_GELI;
56
memcpy(fkeybuf->kb_ents[i].ke_data, saved_keys[i],
57
G_ELI_USERKEYLEN);
58
}
59
fkeybuf->kb_nents = nsaved_keys;
60
explicit_bzero(saved_keys, sizeof(saved_keys));
61
}
62
63
/*
64
* Copy keys from a keybuf struct into local storage.
65
* Zero out the keybuf.
66
*/
67
void
68
geli_import_key_buffer(struct keybuf *skeybuf)
69
{
70
unsigned int i;
71
72
for (i = 0; i < skeybuf->kb_nents && i < GELI_MAX_KEYS; i++) {
73
memcpy(saved_keys[i], skeybuf->kb_ents[i].ke_data,
74
G_ELI_USERKEYLEN);
75
explicit_bzero(skeybuf->kb_ents[i].ke_data,
76
G_ELI_USERKEYLEN);
77
skeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_NONE;
78
}
79
nsaved_keys = skeybuf->kb_nents;
80
skeybuf->kb_nents = 0;
81
}
82
83
void
84
geli_add_key(geli_ukey key)
85
{
86
87
/*
88
* If we run out of key space, the worst that will happen is
89
* it will ask the user for the password again.
90
*/
91
if (nsaved_keys < GELI_MAX_KEYS) {
92
memcpy(saved_keys[nsaved_keys], key, G_ELI_USERKEYLEN);
93
nsaved_keys++;
94
}
95
}
96
97
static int
98
geli_findkey(struct geli_dev *gdev, u_char *mkey)
99
{
100
u_int keynum;
101
int i;
102
103
if (gdev->keybuf_slot >= 0) {
104
if (g_eli_mkey_decrypt_any(&gdev->md, saved_keys[gdev->keybuf_slot],
105
mkey, &keynum) == 0) {
106
return (0);
107
}
108
}
109
110
for (i = 0; i < nsaved_keys; i++) {
111
if (g_eli_mkey_decrypt_any(&gdev->md, saved_keys[i], mkey,
112
&keynum) == 0) {
113
gdev->keybuf_slot = i;
114
return (0);
115
}
116
}
117
118
return (1);
119
}
120
121
/*
122
* Read the last sector of a drive or partition and see if it is GELI encrypted.
123
*/
124
struct geli_dev *
125
geli_taste(geli_readfunc readfunc, void *readpriv, daddr_t lastsector,
126
const char *namefmt, ...)
127
{
128
va_list args;
129
struct g_eli_metadata md;
130
struct known_dev *kdev;
131
struct geli_dev *gdev;
132
u_char *buf;
133
char devname[GELIDEV_NAMELEN];
134
int error;
135
off_t alignsector;
136
137
/*
138
* Format the name into a temp buffer and use that to search for an
139
* existing known_dev instance. If not found, this has the side effect
140
* of initializing kdev to NULL.
141
*/
142
va_start(args, namefmt);
143
vsnprintf(devname, sizeof(devname), namefmt, args);
144
va_end(args);
145
SLIST_FOREACH(kdev, &known_devs_head, entries) {
146
if (strcmp(kdev->name, devname) == 0)
147
return (kdev->gdev);
148
}
149
150
/* Determine whether the new device is geli-encrypted... */
151
if ((buf = malloc(DEV_GELIBOOT_BSIZE)) == NULL)
152
goto out;
153
alignsector = rounddown2(lastsector * DEV_BSIZE, DEV_GELIBOOT_BSIZE);
154
if (alignsector + DEV_GELIBOOT_BSIZE > ((lastsector + 1) * DEV_BSIZE)) {
155
/* Don't read past the end of the disk */
156
alignsector = (lastsector * DEV_BSIZE) + DEV_BSIZE -
157
DEV_GELIBOOT_BSIZE;
158
}
159
error = readfunc(NULL, readpriv, alignsector, buf, DEV_GELIBOOT_BSIZE);
160
if (error != 0) {
161
goto out;
162
}
163
164
/*
165
* We have a new known_device. Whether it's geli-encrypted or not,
166
* record its existence so we can avoid doing IO to probe it next time.
167
*/
168
if ((kdev = malloc(sizeof(*kdev))) == NULL)
169
goto out;
170
strlcpy(kdev->name, devname, sizeof(kdev->name));
171
kdev->gdev = NULL;
172
SLIST_INSERT_HEAD(&known_devs_head, kdev, entries);
173
174
/* Extract the last 4k sector of the disk. */
175
error = eli_metadata_decode(buf, &md);
176
if (error != 0) {
177
/* Try the last 512 byte sector instead. */
178
error = eli_metadata_decode(buf +
179
(DEV_GELIBOOT_BSIZE - DEV_BSIZE), &md);
180
if (error != 0) {
181
goto out;
182
}
183
}
184
185
if (!(md.md_flags & G_ELI_FLAG_GELIBOOT)) {
186
/* The GELIBOOT feature is not activated */
187
goto out;
188
}
189
if ((md.md_flags & G_ELI_FLAG_ONETIME)) {
190
/* Swap device, skip it. */
191
goto out;
192
}
193
194
/*
195
* It's geli-encrypted, create a geli_dev for it and link it into the
196
* known_dev instance.
197
*/
198
gdev = malloc(sizeof(struct geli_dev));
199
if (gdev == NULL)
200
goto out;
201
gdev->part_end = lastsector;
202
gdev->keybuf_slot = -1;
203
gdev->md = md;
204
gdev->name = kdev->name;
205
eli_metadata_softc(&gdev->sc, &md, DEV_BSIZE,
206
(lastsector + DEV_BSIZE) * DEV_BSIZE);
207
kdev->gdev = gdev;
208
out:
209
free(buf);
210
if (kdev == NULL)
211
return (NULL);
212
return (kdev->gdev);
213
}
214
215
/*
216
* Attempt to decrypt the device. This will try existing keys first, then will
217
* prompt for a passphrase if there are no existing keys that work.
218
*/
219
static int
220
geli_probe(struct geli_dev *gdev, const char *passphrase, u_char *mkeyp)
221
{
222
u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
223
u_int keynum;
224
struct hmac_ctx ctx;
225
int error;
226
227
if (mkeyp != NULL) {
228
memcpy(&mkey, mkeyp, G_ELI_DATAIVKEYLEN);
229
explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN);
230
goto found_key;
231
}
232
233
if (geli_findkey(gdev, mkey) == 0) {
234
goto found_key;
235
}
236
237
g_eli_crypto_hmac_init(&ctx, NULL, 0);
238
/*
239
* Prepare Derived-Key from the user passphrase.
240
*/
241
if (gdev->md.md_iterations < 0) {
242
/* XXX TODO: Support loading key files. */
243
return (1);
244
} else if (gdev->md.md_iterations == 0) {
245
g_eli_crypto_hmac_update(&ctx, gdev->md.md_salt,
246
sizeof(gdev->md.md_salt));
247
g_eli_crypto_hmac_update(&ctx, (const uint8_t *)passphrase,
248
strlen(passphrase));
249
} else if (gdev->md.md_iterations > 0) {
250
printf("Calculating GELI Decryption Key for %s %d"
251
" iterations...\n", gdev->name, gdev->md.md_iterations);
252
u_char dkey[G_ELI_USERKEYLEN];
253
254
pkcs5v2_genkey(dkey, sizeof(dkey), gdev->md.md_salt,
255
sizeof(gdev->md.md_salt), passphrase,
256
gdev->md.md_iterations);
257
g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
258
explicit_bzero(dkey, sizeof(dkey));
259
}
260
261
g_eli_crypto_hmac_final(&ctx, key, 0);
262
263
error = g_eli_mkey_decrypt_any(&gdev->md, key, mkey, &keynum);
264
if (error == -1) {
265
explicit_bzero(mkey, sizeof(mkey));
266
explicit_bzero(key, sizeof(key));
267
printf("Bad GELI key: bad password?\n");
268
return (error);
269
} else if (error != 0) {
270
explicit_bzero(mkey, sizeof(mkey));
271
explicit_bzero(key, sizeof(key));
272
printf("Failed to decrypt GELI master key: %d\n", error);
273
return (error);
274
} else {
275
/* Add key to keychain */
276
geli_add_key(key);
277
explicit_bzero(&key, sizeof(key));
278
}
279
280
found_key:
281
/* Store the keys */
282
bcopy(mkey, gdev->sc.sc_mkey, sizeof(gdev->sc.sc_mkey));
283
bcopy(mkey, gdev->sc.sc_ivkey, sizeof(gdev->sc.sc_ivkey));
284
mkp = mkey + sizeof(gdev->sc.sc_ivkey);
285
if ((gdev->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
286
bcopy(mkp, gdev->sc.sc_ekey, G_ELI_DATAKEYLEN);
287
} else {
288
/*
289
* The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
290
*/
291
g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, (const uint8_t *)"\x10", 1,
292
gdev->sc.sc_ekey, 0);
293
}
294
explicit_bzero(mkey, sizeof(mkey));
295
296
/* Initialize the per-sector IV. */
297
switch (gdev->sc.sc_ealgo) {
298
case CRYPTO_AES_XTS:
299
break;
300
default:
301
SHA256_Init(&gdev->sc.sc_ivctx);
302
SHA256_Update(&gdev->sc.sc_ivctx, gdev->sc.sc_ivkey,
303
sizeof(gdev->sc.sc_ivkey));
304
break;
305
}
306
307
return (0);
308
}
309
310
int
311
geli_io(struct geli_dev *gdev, geli_op_t enc, off_t offset, u_char *buf,
312
size_t bytes)
313
{
314
u_char iv[G_ELI_IVKEYLEN];
315
u_char *pbuf;
316
int error;
317
off_t dstoff;
318
uint64_t keyno;
319
size_t n, nsec, secsize;
320
struct g_eli_key gkey;
321
322
pbuf = buf;
323
324
secsize = gdev->sc.sc_sectorsize;
325
nsec = bytes / secsize;
326
if (nsec == 0) {
327
/*
328
* A read of less than the GELI sector size has been
329
* requested. The caller provided destination buffer may
330
* not be big enough to boost the read to a full sector,
331
* so just attempt to decrypt the truncated sector.
332
*/
333
secsize = bytes;
334
nsec = 1;
335
}
336
337
for (n = 0, dstoff = offset; n < nsec; n++, dstoff += secsize) {
338
339
g_eli_crypto_ivgen(&gdev->sc, dstoff, iv, G_ELI_IVKEYLEN);
340
341
/* Get the key that corresponds to this offset. */
342
keyno = (dstoff >> G_ELI_KEY_SHIFT) / secsize;
343
g_eli_key_fill(&gdev->sc, &gkey, keyno);
344
345
error = geliboot_crypt(gdev->sc.sc_ealgo, enc, pbuf, secsize,
346
gkey.gek_key, gdev->sc.sc_ekeylen, iv);
347
348
if (error != 0) {
349
explicit_bzero(&gkey, sizeof(gkey));
350
printf("%s: Failed to %s!", __func__,
351
enc ? "encrypt" : "decrypt");
352
return (error);
353
}
354
pbuf += secsize;
355
}
356
explicit_bzero(&gkey, sizeof(gkey));
357
return (0);
358
}
359
360
int
361
geli_havekey(struct geli_dev *gdev)
362
{
363
u_char mkey[G_ELI_DATAIVKEYLEN];
364
int err;
365
366
err = ENOENT;
367
if (geli_findkey(gdev, mkey) == 0) {
368
if (geli_probe(gdev, NULL, mkey) == 0)
369
err = 0;
370
explicit_bzero(mkey, sizeof(mkey));
371
}
372
return (err);
373
}
374
375
int
376
geli_passphrase(struct geli_dev *gdev, char *pw)
377
{
378
int i;
379
380
/* TODO: Implement GELI keyfile(s) support */
381
for (i = 0; i < 3; i++) {
382
/* Try cached passphrase */
383
if (i == 0 && pw[0] != '\0') {
384
if (geli_probe(gdev, pw, NULL) == 0) {
385
return (0);
386
}
387
}
388
printf("GELI Passphrase for %s ", gdev->name);
389
pwgets(pw, GELI_PW_MAXLEN,
390
(gdev->md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS) == 0);
391
printf("\n");
392
if (geli_probe(gdev, pw, NULL) == 0) {
393
return (0);
394
}
395
}
396
397
return (1);
398
}
399
400