]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/geli/geliboot.c
Merge ACPICA 20170303.
[FreeBSD/FreeBSD.git] / sys / boot / geli / geliboot.c
1 /*-
2  * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
3  * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
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  * $FreeBSD$
28  */
29
30 #include "geliboot.h"
31
32 SLIST_HEAD(geli_list, geli_entry) geli_head = SLIST_HEAD_INITIALIZER(geli_head);
33 struct geli_list *geli_headp;
34
35 static int
36 geli_same_device(struct geli_entry *ge, struct dsk *dskp)
37 {
38
39         if (geli_e->dsk->drive == dskp->drive &&
40             dskp->part == 255 && geli_e->dsk->part == dskp->slice) {
41                 /*
42                  * Sometimes slice = slice, and sometimes part = slice
43                  * If the incoming struct dsk has part=255, it means look at
44                  * the slice instead of the part number
45                  */
46                 return (0);
47         }
48
49         /* Is this the same device? */
50         if (geli_e->dsk->drive != dskp->drive ||
51             geli_e->dsk->slice != dskp->slice ||
52             geli_e->dsk->part != dskp->part) {
53                 return (1);
54         }
55
56         return (0);
57 }
58
59 void
60 geli_init(void)
61 {
62
63         geli_count = 0;
64         SLIST_INIT(&geli_head);
65 }
66
67 /*
68  * Read the last sector of the drive or partition pointed to by dsk and see
69  * if it is GELI encrypted
70  */
71 int
72 geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf,
73     size_t bytes), struct dsk *dskp, daddr_t lastsector)
74 {
75         struct g_eli_metadata md;
76         u_char buf[DEV_GELIBOOT_BSIZE];
77         int error;
78         off_t alignsector;
79
80         alignsector = rounddown2(lastsector * DEV_BSIZE, DEV_GELIBOOT_BSIZE);
81         if (alignsector + DEV_GELIBOOT_BSIZE > ((lastsector + 1) * DEV_BSIZE)) {
82                 /* Don't read past the end of the disk */
83                 alignsector = (lastsector * DEV_BSIZE) + DEV_BSIZE
84                     - DEV_GELIBOOT_BSIZE;
85         }
86         error = read_func(NULL, dskp, alignsector, &buf, DEV_GELIBOOT_BSIZE);
87         if (error != 0) {
88                 return (error);
89         }
90         /* Extract the last 4k sector of the disk. */
91         error = eli_metadata_decode(buf, &md);
92         if (error != 0) {
93                 /* Try the last 512 byte sector instead. */
94                 error = eli_metadata_decode(buf +
95                     (DEV_GELIBOOT_BSIZE - DEV_BSIZE), &md);
96                 if (error != 0) {
97                         return (error);
98                 }
99         }
100
101         if (!(md.md_flags & G_ELI_FLAG_GELIBOOT)) {
102                 /* The GELIBOOT feature is not activated */
103                 return (1);
104         }
105         if ((md.md_flags & G_ELI_FLAG_ONETIME)) {
106                 /* Swap device, skip it. */
107                 return (1);
108         }
109         if (md.md_iterations < 0) {
110                 /* XXX TODO: Support loading key files. */
111                 /* Disk does not have a passphrase, skip it. */
112                 return (1);
113         }
114         geli_e = malloc(sizeof(struct geli_entry));
115         if (geli_e == NULL)
116                 return (2);
117
118         geli_e->dsk = malloc(sizeof(struct dsk));
119         if (geli_e->dsk == NULL)
120                 return (2);
121         memcpy(geli_e->dsk, dskp, sizeof(struct dsk));
122         geli_e->part_end = lastsector;
123         if (dskp->part == 255) {
124                 geli_e->dsk->part = dskp->slice;
125         }
126
127         geli_e->md = md;
128         eli_metadata_softc(&geli_e->sc, &md, DEV_BSIZE,
129             (lastsector + DEV_BSIZE) * DEV_BSIZE);
130
131         SLIST_INSERT_HEAD(&geli_head, geli_e, entries);
132         geli_count++;
133
134         return (0);
135 }
136
137 /*
138  * Attempt to decrypt the device
139  */
140 int
141 geli_attach(struct dsk *dskp, const char *passphrase)
142 {
143         u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
144         u_int keynum;
145         struct hmac_ctx ctx;
146         int error;
147
148         SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
149                 if (geli_same_device(geli_e, dskp) != 0) {
150                         continue;
151                 }
152
153                 g_eli_crypto_hmac_init(&ctx, NULL, 0);
154                 /*
155                  * Prepare Derived-Key from the user passphrase.
156                  */
157                 if (geli_e->md.md_iterations < 0) {
158                         /* XXX TODO: Support loading key files. */
159                         return (1);
160                 } else if (geli_e->md.md_iterations == 0) {
161                         g_eli_crypto_hmac_update(&ctx, geli_e->md.md_salt,
162                             sizeof(geli_e->md.md_salt));
163                         g_eli_crypto_hmac_update(&ctx, passphrase,
164                             strlen(passphrase));
165                 } else if (geli_e->md.md_iterations > 0) {
166                         printf("Calculating GELI Decryption Key disk%dp%d @ %d"
167                             " iterations...\n", dskp->unit,
168                             (dskp->slice > 0 ? dskp->slice : dskp->part),
169                             geli_e->md.md_iterations);
170                         u_char dkey[G_ELI_USERKEYLEN];
171
172                         pkcs5v2_genkey(dkey, sizeof(dkey), geli_e->md.md_salt,
173                             sizeof(geli_e->md.md_salt), passphrase,
174                             geli_e->md.md_iterations);
175                         g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
176                         bzero(&dkey, sizeof(dkey));
177                 }
178
179                 g_eli_crypto_hmac_final(&ctx, key, 0);
180
181                 error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum);
182                 bzero(&key, sizeof(key));
183                 if (error == -1) {
184                         bzero(&mkey, sizeof(mkey));
185                         printf("Bad GELI key: %d\n", error);
186                         return (error);
187                 } else if (error != 0) {
188                         bzero(&mkey, sizeof(mkey));
189                         printf("Failed to decrypt GELI master key: %d\n", error);
190                         return (error);
191                 }
192
193                 /* Store the keys */
194                 bcopy(mkey, geli_e->sc.sc_mkey, sizeof(geli_e->sc.sc_mkey));
195                 bcopy(mkey, geli_e->sc.sc_ivkey, sizeof(geli_e->sc.sc_ivkey));
196                 mkp = mkey + sizeof(geli_e->sc.sc_ivkey);
197                 if ((geli_e->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
198                         bcopy(mkp, geli_e->sc.sc_ekey, G_ELI_DATAKEYLEN);
199                 } else {
200                         /*
201                          * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
202                          */
203                         g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, "\x10", 1,
204                             geli_e->sc.sc_ekey, 0);
205                 }
206                 bzero(&mkey, sizeof(mkey));
207
208                 /* Initialize the per-sector IV. */
209                 switch (geli_e->sc.sc_ealgo) {
210                 case CRYPTO_AES_XTS:
211                         break;
212                 default:
213                         SHA256_Init(&geli_e->sc.sc_ivctx);
214                         SHA256_Update(&geli_e->sc.sc_ivctx, geli_e->sc.sc_ivkey,
215                             sizeof(geli_e->sc.sc_ivkey));
216                         break;
217                 }
218
219                 return (0);
220         }
221
222         /* Disk not found. */
223         return (2);
224 }
225
226 int
227 is_geli(struct dsk *dskp)
228 {
229         SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
230                 if (geli_same_device(geli_e, dskp) == 0) {
231                         return (0);
232                 }
233         }
234         
235         return (1);
236 }
237
238 int
239 geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes)
240 {
241         u_char iv[G_ELI_IVKEYLEN];
242         u_char *pbuf;
243         int error;
244         off_t dstoff;
245         uint64_t keyno;
246         size_t n, nsec, secsize;
247         struct g_eli_key gkey;
248
249         pbuf = buf;
250         SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
251                 if (geli_same_device(geli_e, dskp) != 0) {
252                         continue;
253                 }
254
255                 secsize = geli_e->sc.sc_sectorsize;
256                 nsec = bytes / secsize;
257                 if (nsec == 0) {
258                         /*
259                          * A read of less than the GELI sector size has been
260                          * requested. The caller provided destination buffer may
261                          * not be big enough to boost the read to a full sector,
262                          * so just attempt to decrypt the truncated sector.
263                          */
264                         secsize = bytes;
265                         nsec = 1;
266                 }
267
268                 for (n = 0, dstoff = offset; n < nsec; n++, dstoff += secsize) {
269
270                         g_eli_crypto_ivgen(&geli_e->sc, dstoff, iv,
271                             G_ELI_IVKEYLEN);
272
273                         /* Get the key that corresponds to this offset. */
274                         keyno = (dstoff >> G_ELI_KEY_SHIFT) / secsize;
275                         g_eli_key_fill(&geli_e->sc, &gkey, keyno);
276
277                         error = geliboot_crypt(geli_e->sc.sc_ealgo, 0, pbuf,
278                             secsize, gkey.gek_key,
279                             geli_e->sc.sc_ekeylen, iv);
280
281                         if (error != 0) {
282                                 bzero(&gkey, sizeof(gkey));
283                                 printf("Failed to decrypt in geli_read()!");
284                                 return (error);
285                         }
286                         pbuf += secsize;
287                 }
288                 bzero(&gkey, sizeof(gkey));
289                 return (0);
290         }
291
292         printf("GELI provider not found\n");
293         return (1);
294 }
295
296 int
297 geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp)
298 {
299         int i;
300
301         /* TODO: Implement GELI keyfile(s) support */
302         for (i = 0; i < 3; i++) {
303                 /* Try cached passphrase */
304                 if (i == 0 && pw[0] != '\0') {
305                         if (geli_attach(dskp, pw) == 0) {
306                                 return (0);
307                         }
308                 }
309                 printf("GELI Passphrase for disk%d%c%d: ", disk, parttype, part);
310                 pwgets(pw, GELI_PW_MAXLEN);
311                 printf("\n");
312                 if (geli_attach(dskp, pw) == 0) {
313                         return (0);
314                 }
315         }
316
317         return (1);
318 }