]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/geli/geliboot.c
Update the device tree source files to a Linux 4.7-RC.
[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 = (lastsector * DEV_BSIZE) &
81             ~(off_t)(DEV_GELIBOOT_BSIZE - 1);
82         error = read_func(NULL, dskp, alignsector, &buf, DEV_GELIBOOT_BSIZE);
83         if (error != 0) {
84                 return (error);
85         }
86         /* Extract the last DEV_BSIZE bytes from the block. */
87         error = eli_metadata_decode(buf + (DEV_GELIBOOT_BSIZE - DEV_BSIZE),
88             &md);
89         if (error != 0) {
90                 return (error);
91         }
92
93         if (!(md.md_flags & G_ELI_FLAG_GELIBOOT)) {
94                 /* The GELIBOOT feature is not activated */
95                 return (1);
96         }
97         if ((md.md_flags & G_ELI_FLAG_ONETIME)) {
98                 /* Swap device, skip it. */
99                 return (1);
100         }
101         if (md.md_iterations < 0) {
102                 /* XXX TODO: Support loading key files. */
103                 /* Disk does not have a passphrase, skip it. */
104                 return (1);
105         }
106         geli_e = malloc(sizeof(struct geli_entry));
107         if (geli_e == NULL)
108                 return (2);
109
110         geli_e->dsk = malloc(sizeof(struct dsk));
111         if (geli_e->dsk == NULL)
112                 return (2);
113         memcpy(geli_e->dsk, dskp, sizeof(struct dsk));
114         geli_e->part_end = lastsector;
115         if (dskp->part == 255) {
116                 geli_e->dsk->part = dskp->slice;
117         }
118
119         geli_e->md = md;
120         eli_metadata_softc(&geli_e->sc, &md, DEV_BSIZE,
121             (lastsector + DEV_BSIZE) * DEV_BSIZE);
122
123         SLIST_INSERT_HEAD(&geli_head, geli_e, entries);
124         geli_count++;
125
126         return (0);
127 }
128
129 /*
130  * Attempt to decrypt the device
131  */
132 int
133 geli_attach(struct dsk *dskp, const char *passphrase)
134 {
135         u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
136         u_int keynum;
137         struct hmac_ctx ctx;
138         int error;
139
140         SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
141                 if (geli_same_device(geli_e, dskp) != 0) {
142                         continue;
143                 }
144
145                 g_eli_crypto_hmac_init(&ctx, NULL, 0);
146                 /*
147                  * Prepare Derived-Key from the user passphrase.
148                  */
149                 if (geli_e->md.md_iterations < 0) {
150                         /* XXX TODO: Support loading key files. */
151                         return (1);
152                 } else if (geli_e->md.md_iterations == 0) {
153                         g_eli_crypto_hmac_update(&ctx, geli_e->md.md_salt,
154                             sizeof(geli_e->md.md_salt));
155                         g_eli_crypto_hmac_update(&ctx, passphrase,
156                             strlen(passphrase));
157                 } else if (geli_e->md.md_iterations > 0) {
158                         printf("Calculating GELI Decryption Key disk%dp%d @ %d"
159                             " iterations...\n", dskp->unit,
160                             (dskp->slice > 0 ? dskp->slice : dskp->part),
161                             geli_e->md.md_iterations);
162                         u_char dkey[G_ELI_USERKEYLEN];
163
164                         pkcs5v2_genkey(dkey, sizeof(dkey), geli_e->md.md_salt,
165                             sizeof(geli_e->md.md_salt), passphrase,
166                             geli_e->md.md_iterations);
167                         g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
168                         bzero(&dkey, sizeof(dkey));
169                 }
170
171                 g_eli_crypto_hmac_final(&ctx, key, 0);
172
173                 error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum);
174                 bzero(&key, sizeof(key));
175                 if (error == -1) {
176                         bzero(&mkey, sizeof(mkey));
177                         printf("Bad GELI key: %d\n", error);
178                         return (error);
179                 } else if (error != 0) {
180                         bzero(&mkey, sizeof(mkey));
181                         printf("Failed to decrypt GELI master key: %d\n", error);
182                         return (error);
183                 }
184
185                 /* Store the keys */
186                 bcopy(mkey, geli_e->sc.sc_mkey, sizeof(geli_e->sc.sc_mkey));
187                 bcopy(mkey, geli_e->sc.sc_ivkey, sizeof(geli_e->sc.sc_ivkey));
188                 mkp = mkey + sizeof(geli_e->sc.sc_ivkey);
189                 if ((geli_e->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
190                         bcopy(mkp, geli_e->sc.sc_ekey, G_ELI_DATAKEYLEN);
191                 } else {
192                         /*
193                          * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
194                          */
195                         g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, "\x10", 1,
196                             geli_e->sc.sc_ekey, 0);
197                 }
198                 bzero(&mkey, sizeof(mkey));
199
200                 /* Initialize the per-sector IV. */
201                 switch (geli_e->sc.sc_ealgo) {
202                 case CRYPTO_AES_XTS:
203                         break;
204                 default:
205                         SHA256_Init(&geli_e->sc.sc_ivctx);
206                         SHA256_Update(&geli_e->sc.sc_ivctx, geli_e->sc.sc_ivkey,
207                             sizeof(geli_e->sc.sc_ivkey));
208                         break;
209                 }
210
211                 return (0);
212         }
213
214         /* Disk not found. */
215         return (2);
216 }
217
218 int
219 is_geli(struct dsk *dskp)
220 {
221         SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
222                 if (geli_same_device(geli_e, dskp) == 0) {
223                         return (0);
224                 }
225         }
226         
227         return (1);
228 }
229
230 int
231 geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes)
232 {
233         u_char iv[G_ELI_IVKEYLEN];
234         u_char *pbuf;
235         int error;
236         off_t dstoff;
237         uint64_t keyno;
238         size_t n, nsec, secsize;
239         struct g_eli_key gkey;
240
241         pbuf = buf;
242         SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
243                 if (geli_same_device(geli_e, dskp) != 0) {
244                         continue;
245                 }
246
247                 secsize = geli_e->sc.sc_sectorsize;
248                 nsec = bytes / secsize;
249                 if (nsec == 0) {
250                         /*
251                          * A read of less than the GELI sector size has been
252                          * requested. The caller provided destination buffer may
253                          * not be big enough to boost the read to a full sector,
254                          * so just attempt to decrypt the truncated sector.
255                          */
256                         secsize = bytes;
257                         nsec = 1;
258                 }
259
260                 for (n = 0, dstoff = offset; n < nsec; n++, dstoff += secsize) {
261
262                         g_eli_crypto_ivgen(&geli_e->sc, dstoff, iv,
263                             G_ELI_IVKEYLEN);
264
265                         /* Get the key that corresponds to this offset. */
266                         keyno = (dstoff >> G_ELI_KEY_SHIFT) / secsize;
267                         g_eli_key_fill(&geli_e->sc, &gkey, keyno);
268
269                         error = geliboot_crypt(geli_e->sc.sc_ealgo, 0, pbuf,
270                             secsize, gkey.gek_key,
271                             geli_e->sc.sc_ekeylen, iv);
272
273                         if (error != 0) {
274                                 bzero(&gkey, sizeof(gkey));
275                                 printf("Failed to decrypt in geli_read()!");
276                                 return (error);
277                         }
278                         pbuf += secsize;
279                 }
280                 bzero(&gkey, sizeof(gkey));
281                 return (0);
282         }
283
284         printf("GELI provider not found\n");
285         return (1);
286 }
287
288 int
289 geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp)
290 {
291         int i;
292
293         /* TODO: Implement GELI keyfile(s) support */
294         for (i = 0; i < 3; i++) {
295                 /* Try cached passphrase */
296                 if (i == 0 && pw[0] != '\0') {
297                         if (geli_attach(dskp, pw) == 0) {
298                                 return (0);
299                         }
300                 }
301                 printf("GELI Passphrase for disk%d%c%d: ", disk, parttype, part);
302                 pwgets(pw, GELI_PW_MAXLEN);
303                 printf("\n");
304                 if (geli_attach(dskp, pw) == 0) {
305                         return (0);
306                 }
307         }
308
309         return (1);
310 }