Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2010, XenSource Inc.
3 : : * All rights reserved.
4 : : *
5 : : * Redistribution and use in source and binary forms, with or without
6 : : * modification, are permitted provided that the following conditions are met:
7 : : * * Redistributions of source code must retain the above copyright
8 : : * notice, this list of conditions and the following disclaimer.
9 : : * * Redistributions in binary form must reproduce the above copyright
10 : : * notice, this list of conditions and the following disclaimer in the
11 : : * documentation and/or other materials provided with the distribution.
12 : : * * Neither the name of XenSource Inc. nor the names of its contributors
13 : : * may be used to endorse or promote products derived from this software
14 : : * without specific prior written permission.
15 : : *
16 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : : */
28 : :
29 : : /*
30 : : * Copyright (c) 2014 Citrix Systems, Inc.
31 : : */
32 : :
33 : :
34 : : #include <stdio.h>
35 : : #include <sys/types.h>
36 : : #include <sys/stat.h>
37 : : #include <fcntl.h>
38 : : #include <errno.h>
39 : : #include <unistd.h>
40 : :
41 : : #include "list.h"
42 : : #include "libvhd.h"
43 : : #include "tapdisk.h"
44 : : #include "vhd-util.h"
45 : :
46 : : #include "crypto/compat-crypto-openssl.h"
47 : : #include "crypto/xts_aes.h"
48 : :
49 : : #define MAX_AES_XTS_PLAIN_KEYSIZE 1024
50 : :
51 : : char * vhd_util_get_vhd_basename(vhd_context_t *vhd);
52 : : extern int CRYPTO_SUPPORTED_KEYSIZE[];
53 : :
54 : : /*
55 : : * calculates keyhash by taking a SHA256 hash of @keyhash->nonce + key
56 : : */
57 : : int
58 : 0 : vhd_calculate_keyhash(struct vhd_keyhash *keyhash,
59 : : const uint8_t *key, size_t key_bytes)
60 : : {
61 : : int err;
62 : 0 : EVP_MD_CTX *evp = NULL;
63 : :
64 : 0 : err = -1;
65 : 0 : evp = EVP_MD_CTX_new();
66 : 0 : if (!EVP_DigestInit_ex(evp, EVP_sha256(), NULL)) {
67 : : EPRINTF("failed to init sha256 context\n");
68 : : goto cleanup;
69 : : }
70 : :
71 : 0 : if (!EVP_DigestUpdate(evp, keyhash->nonce, sizeof(keyhash->nonce))) {
72 : : EPRINTF("failed to hash nonce\n");
73 : : goto cleanup;
74 : : }
75 : :
76 : 0 : if (!EVP_DigestUpdate(evp, key, key_bytes)) {
77 : : EPRINTF("failed to hash key\n");
78 : : goto cleanup;
79 : : }
80 : :
81 : 0 : if (!EVP_DigestFinal_ex(evp, keyhash->hash, NULL)) {
82 : : EPRINTF("failed to finalize hash\n");
83 : : goto cleanup;
84 : : }
85 : :
86 : : err = 0;
87 : :
88 : : cleanup:
89 : 0 : EVP_MD_CTX_free(evp);
90 : 0 : return err;
91 : : }
92 : :
93 : : static int
94 : 0 : check_key(const uint8_t *keybuf, unsigned int keysize,
95 : : const struct vhd_keyhash *vhdhash)
96 : : {
97 : : int err;
98 : : struct vhd_keyhash keyhash;
99 : :
100 : 0 : if (!vhdhash->cookie) {
101 : : DPRINTF("missing key hash\n");
102 : : err = 1;
103 : : goto out;
104 : : }
105 : :
106 : 0 : memcpy(keyhash.nonce, vhdhash->nonce, sizeof(keyhash.nonce));
107 : 0 : err = vhd_calculate_keyhash(&keyhash, keybuf, keysize / 8);
108 : 0 : if (err) {
109 : : DPRINTF("failed to calculate keyhash: %d\n", err);
110 : : goto out;
111 : : }
112 : :
113 : 0 : if (memcmp(keyhash.hash, vhdhash->hash, sizeof(keyhash.hash))) {
114 : : DPRINTF("key hash mismatch\n");
115 : : err = 1;
116 : : goto out;
117 : : }
118 : :
119 : : out:
120 : 0 : if (err) {
121 : : DPRINTF("key check failed\n");
122 : : err = -ENOKEY;
123 : : }
124 : 0 : return err;
125 : : }
126 : :
127 : : #ifdef OPEN_XT
128 : : static int
129 : : find_keyfile(char **keyfile, const char *dirs,
130 : : const char *basename, int keysize)
131 : : {
132 : : char *sep = NULL;
133 : : *keyfile = NULL;
134 : :
135 : : while (dirs && strlen(dirs) > 0) {
136 : : char keydir[256] = { 0 }, path[256] = { 0 };
137 : : struct stat st;
138 : : int err;
139 : :
140 : : sep = strchr(dirs, ',');
141 : : /* get directory element */
142 : : if (sep == NULL) {
143 : : safe_strncpy(keydir, dirs, sizeof(keydir));
144 : : dirs = NULL;
145 : : } else {
146 : : size_t len = sep - dirs;
147 : : safe_strncpy(keydir, dirs, len);
148 : : dirs = sep+1;
149 : : }
150 : :
151 : : /* check if keyfile is inside dir */
152 : : snprintf(path, sizeof(path),
153 : : "%s/%s,aes-xts-plain,%d.key",
154 : : keydir, basename, keysize);
155 : : err = stat(path, &st);
156 : : if (err == 0) {
157 : : /* found */
158 : : *keyfile = strdup(path);
159 : : if (*keyfile == NULL) {
160 : : return -ENOMEM;
161 : : }
162 : : DPRINTF("found keyfile %s\n", path);
163 : : return 0;
164 : : } else if (err < 0 && errno != ENOENT) {
165 : : return -errno;
166 : : } else {
167 : : DPRINTF("keyfile %s not found\n", path);
168 : : }
169 : : }
170 : :
171 : : return -ENOENT;
172 : : }
173 : :
174 : : static int
175 : : read_keyfile(const char *keydir, const char *basename,
176 : : uint8_t *keybuf, size_t keysize)
177 : : {
178 : : int err, fd = -1;
179 : : char *keyfile = NULL;
180 : :
181 : : err = find_keyfile(&keyfile, keydir, basename, keysize);
182 : : if (err) {
183 : : keyfile = NULL;
184 : : goto out;
185 : : }
186 : :
187 : : fd = open(keyfile, O_RDONLY);
188 : : if (fd == -1) {
189 : : err = -errno;
190 : : goto out;
191 : : }
192 : :
193 : : err = read(fd, keybuf, keysize / 8);
194 : : if (err != keysize / 8) {
195 : : err = err == -1 ? -errno : -EINVAL;
196 : : goto out;
197 : : }
198 : :
199 : : DPRINTF("using keyfile %s, keysize %d\n", keyfile, (int)keysize);
200 : : err = 0;
201 : :
202 : : out:
203 : : if (fd != -1)
204 : : close(fd);
205 : : free(keyfile);
206 : : return err;
207 : : }
208 : :
209 : : // try 512bit, 256bit keys
210 : : static int
211 : : read_preferred_keyfile(const char *keydir, const char *basename, uint8_t *keybuf, int *keysize)
212 : : {
213 : : int err, i;
214 : : *keysize = 0;
215 : : err = -EINVAL;
216 : : for (i = 0; CRYPTO_SUPPORTED_KEYSIZE[i] > 0; ++i) {
217 : : err = read_keyfile(keydir, basename, keybuf, CRYPTO_SUPPORTED_KEYSIZE[i]);
218 : : if (err == 0) {
219 : : *keysize = CRYPTO_SUPPORTED_KEYSIZE[i];
220 : : return 0;
221 : : }
222 : : }
223 : : return err;
224 : : }
225 : :
226 : :
227 : : static vhd_context_t *
228 : : vhd_open_parent(vhd_context_t *ctx)
229 : : {
230 : : vhd_context_t *parent = NULL;
231 : : char *next = NULL;
232 : : int err;
233 : : if (ctx->footer.type != HD_TYPE_DIFF)
234 : : goto out;
235 : : if (vhd_parent_raw(ctx))
236 : : goto out;
237 : : err = vhd_parent_locator_get(ctx, &next);
238 : : if (err)
239 : : goto out;
240 : :
241 : : parent = calloc(1, sizeof(*parent));
242 : : if (!parent)
243 : : goto out;
244 : :
245 : : err = vhd_open(parent, next, VHD_OPEN_RDONLY);
246 : : if (err) {
247 : : DPRINTF("vhd_open failed: %d\n", err);
248 : : free(parent);
249 : : parent = NULL;
250 : : goto out;
251 : : }
252 : : out:
253 : : free(next);
254 : : return parent;
255 : : }
256 : :
257 : : /* look up the chain for first parent VHD with encryption key */
258 : : static int
259 : : chain_find_keyed_vhd(vhd_context_t *vhd, uint8_t *key, int *keysize, struct vhd_keyhash *out_keyhash)
260 : : {
261 : : int err;
262 : : struct vhd_keyhash keyhash;
263 : : vhd_context_t *p = vhd, *p2;
264 : : char *basename;
265 : : const char *keydir;
266 : : int found = 0;
267 : :
268 : : memset(out_keyhash, 0, sizeof(*out_keyhash));
269 : :
270 : : keydir = getenv("TAPDISK3_CRYPTO_KEYDIR");
271 : : if (keydir == NULL) {
272 : : keydir = CRYPTO_DEFAULT_KEYDIR;
273 : : }
274 : :
275 : : while (p) {
276 : : err = vhd_get_keyhash(p, &keyhash);
277 : : if (err) {
278 : : DPRINTF("error getting keyhash: %d\n", err);
279 : : return err;
280 : : }
281 : :
282 : : if (keyhash.cookie && keydir == NULL) {
283 : : DPRINTF("this vhd requires TAPDISK3_CRYPTO_KEYDIR\n");
284 : : return -ENOKEY;
285 : : }
286 : :
287 : : /* if keydir is set, we check if a key exists (with the same basename)
288 : : * regardless the keyhash.cookie value to prevent an issue where
289 : : * the vhd has been replaced by another one that is clear */
290 : : if (keydir) {
291 : : basename = vhd_util_get_vhd_basename(p);
292 : : if (!basename) {
293 : : err = -ENOMEM;
294 : : goto out;
295 : : }
296 : :
297 : : err = read_preferred_keyfile(keydir, basename, key, keysize);
298 : : free(basename);
299 : : switch (err) {
300 : : case 0: /* a key has been found with the same basename */
301 : : if (keyhash.cookie == 0) {
302 : : DPRINTF("key found for %s but no hash set\n", p->file);
303 : : err = -EACCES;
304 : : goto out;
305 : : }
306 : : err = check_key(key, *keysize, &keyhash);
307 : : if (err)
308 : : goto out;
309 : : DPRINTF("using key from vhd: %s\n", p->file);
310 : : *out_keyhash = keyhash;
311 : : found = 1;
312 : : break;
313 : : case -ENOENT: /* no key found, get to the next one if the cookie's not set */
314 : : if (keyhash.cookie != 0) {
315 : : err = -ENOKEY;
316 : : goto out;
317 : : }
318 : : break;
319 : : default: /* some another error */
320 : : goto out;
321 : : }
322 : : }
323 : :
324 : : if (found)
325 : : goto out;
326 : :
327 : : p2 = p;
328 : : p = vhd_open_parent(p);
329 : :
330 : : if (p2 != vhd) {
331 : : vhd_close(p2);
332 : : free(p2);
333 : : }
334 : : }
335 : : return 0;
336 : : out:
337 : : if (p != vhd) {
338 : : vhd_close(p);
339 : : free(p);
340 : : }
341 : : return err;
342 : : }
343 : : #endif
344 : :
345 : : int
346 : 0 : vhd_open_crypto(vhd_context_t *vhd, const uint8_t *key, size_t key_bytes, const char *name)
347 : : {
348 : : struct vhd_keyhash keyhash;
349 : : int err;
350 : : #ifdef OPEN_XT
351 : : uint8_t key[MAX_AES_XTS_PLAIN_KEYSIZE / sizeof(uint8_t)] = { 0 };
352 : : int keysize = 0;
353 : : #endif
354 : :
355 : 0 : if (vhd->xts_tfm)
356 : 0 : return 0;
357 : :
358 : : #ifdef OPEN_XT
359 : : err = chain_find_keyed_vhd(vhd, key, &keysize, &keyhash);
360 : : if (err) {
361 : : DPRINTF("error in vhd chain: %d\n", err);
362 : : return err;
363 : : }
364 : :
365 : : if (keyhash.cookie == 0) {
366 : : return 0;
367 : : }
368 : : #else
369 : : memset(&keyhash, 0, sizeof(keyhash));
370 : 0 : err = vhd_get_keyhash(vhd, &keyhash);
371 : 0 : if (err) {
372 : : EPRINTF("error getting keyhash: %d\n", err);
373 : : return err;
374 : : }
375 : :
376 : 0 : if (keyhash.cookie == 0) {
377 : 0 : if (!key) {
378 : : DPRINTF("No crypto, not starting crypto\n");
379 : : return 0;
380 : : }
381 : :
382 : : EPRINTF("VHD %s has no keyhash when encryption is requested\n", name);
383 : : return -EINVAL;
384 : 0 : } else if (!key) {
385 : : EPRINTF("No encryption key supplied for encrypted VHD, %s\n", name);
386 : : return -EINVAL;
387 : : }
388 : :
389 : 0 : err = check_key(key, key_bytes * 8, &keyhash);
390 : 0 : if (err) {
391 : : EPRINTF("Keyhash doesn't match vhd key for %s\n", name);
392 : : return err;
393 : : }
394 : :
395 : : DPRINTF("Keyhash verified, starting crypto for %s\n", name);
396 : : #endif
397 : :
398 : 0 : vhd->xts_tfm = xts_aes_setup();
399 : 0 : if (vhd->xts_tfm == NULL) {
400 : : err = -EINVAL;
401 : : return err;
402 : : }
403 : :
404 : 0 : xts_aes_setkey(vhd->xts_tfm, key, key_bytes);
405 : : return 0;
406 : : }
407 : :
408 : : void
409 : 0 : vhd_close_crypto(vhd_context_t *vhd)
410 : : {
411 : 0 : if (vhd->xts_tfm)
412 : : {
413 : 0 : EVP_CIPHER_CTX_free(vhd->xts_tfm->en_ctx);
414 : 0 : EVP_CIPHER_CTX_free(vhd->xts_tfm->de_ctx);
415 : 0 : free(vhd->xts_tfm);
416 : : }
417 : 0 : }
418 : :
419 : : void
420 : 0 : vhd_crypto_decrypt(vhd_context_t *vhd, td_request_t *t)
421 : : {
422 : : int sec, ret;
423 : :
424 : 0 : for (sec = 0; sec < t->secs; sec++) {
425 : 0 : ret = xts_aes_plain_decrypt(vhd->xts_tfm, t->sec + sec,
426 : 0 : (uint8_t *)t->buf +
427 : 0 : sec * VHD_SECTOR_SIZE,
428 : : (uint8_t *)t->buf +
429 : : sec * VHD_SECTOR_SIZE,
430 : : VHD_SECTOR_SIZE);
431 : 0 : if (ret) {
432 : : DPRINTF("crypto decrypt failed: %d : TERMINATED\n", ret);
433 : 0 : exit(1); /* XXX */
434 : : }
435 : : }
436 : 0 : }
437 : :
438 : : int
439 : 0 : vhd_crypto_encrypt_block(vhd_context_t *vhd, sector_t sector, uint8_t *source,
440 : : uint8_t *dst, unsigned int block_size)
441 : : {
442 : 0 : return xts_aes_plain_encrypt(vhd->xts_tfm, sector, dst, source, block_size);
443 : : }
444 : :
445 : : void
446 : 0 : vhd_crypto_encrypt(vhd_context_t *vhd, td_request_t *t, char *orig_buf)
447 : : {
448 : : int sec, ret;
449 : :
450 : 0 : for (sec = 0; sec < t->secs; sec++) {
451 : 0 : ret = vhd_crypto_encrypt_block(
452 : 0 : vhd, t->sec + sec,
453 : : (uint8_t *)orig_buf + sec * VHD_SECTOR_SIZE,
454 : 0 : (uint8_t *)t->buf + sec * VHD_SECTOR_SIZE,
455 : : VHD_SECTOR_SIZE);
456 : 0 : if (ret) {
457 : : DPRINTF("crypto encrypt failed: %d : TERMINATED\n", ret);
458 : 0 : exit(1); /* XXX */
459 : : }
460 : : }
461 : 0 : }
462 : :
|