1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2012-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2016 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * Marco van Wieringen, March 2012
25 */
26 /**
27 * @file
28 * Load and clear an SCSI encryption key used by a tape drive
29 * using a lowlevel SCSI interface.
30 */
31
32 #include "include/bareos.h"
33 #include "lib/crypto_cache.h"
34 #include "lib/crypto_wrap.h"
35 #include "lib/passphrase.h"
36 #include "lib/scsi_crypto.h"
37
usage()38 static void usage()
39 {
40 fprintf(stderr,
41 "\n"
42 "Usage: bscrypto <options> [<device_name>]\n"
43 " -b Perform base64 encoding of keydata\n"
44 " -c Clear encryption key\n"
45 " -D <cachefile> Dump content of given cachefile\n"
46 " -d <nn> Set debug level to <nn>\n"
47 " -e Show drive encryption status\n"
48 " -g <keyfile> Generate new encryption passphrase in keyfile\n"
49 " -k <keyfile> Show content of keyfile\n"
50 " -p <cachefile> Populate given cachefile with crypto keys\n"
51 " -r <cachefile> Reset expiry time for entries of given cachefile\n"
52 " -s <keyfile> Set encryption key loaded from keyfile\n"
53 " -v Show volume encryption status\n"
54 " -w <keyfile> Wrap/Unwrap the key using RFC3394 aes-(un)wrap\n"
55 " using the key in keyfile as a Key Encryption Key\n"
56 " -? print this message.\n"
57 "\n"
58 " A keyfile named - is either stdin or stdout depending on the option\n"
59 "\n");
60 }
61
main(int argc,char * const * argv)62 int main(int argc, char *const *argv)
63 {
64 int retval = 0;
65 int ch, kfd, length;
66 bool base64_transform = false,
67 clear_encryption = false,
68 dump_cache = false,
69 drive_encryption_status = false,
70 generate_passphrase = false,
71 populate_cache = false,
72 reset_cache = false,
73 set_encryption = false,
74 show_keydata = false,
75 volume_encryption_status = false,
76 wrapped_keys = false;
77 char *keyfile = NULL;
78 char *cache_file = NULL;
79 char *wrap_keyfile = NULL;
80 char keydata[64];
81 char wrapdata[64];
82
83 setlocale(LC_ALL, "");
84 bindtextdomain("bareos", LOCALEDIR);
85 textdomain("bareos");
86
87 while ((ch = getopt(argc, argv, "bcD:d:eg:k:p:r:s:vw:?")) != -1) {
88 switch (ch) {
89 case 'b':
90 base64_transform = true;
91 break;
92
93 case 'c':
94 clear_encryption = true;
95 break;
96
97 case 'D':
98 dump_cache = true;
99 cache_file = bstrdup(optarg);
100 break;
101
102 case 'd':
103 debug_level = atoi(optarg);
104 if (debug_level <= 0) {
105 debug_level = 1;
106 }
107 break;
108
109 case 'e':
110 drive_encryption_status = true;
111 break;
112
113 case 'g':
114 generate_passphrase = true;
115 if (keyfile) {
116 usage();
117 goto bail_out;
118 }
119 keyfile = bstrdup(optarg);
120 break;
121
122 case 'k':
123 show_keydata = true;
124 if (keyfile) {
125 usage();
126 goto bail_out;
127 }
128 keyfile = bstrdup(optarg);
129 break;
130
131 case 'p':
132 populate_cache = true;
133 cache_file = bstrdup(optarg);
134 break;
135
136 case 'r':
137 reset_cache = true;
138 cache_file = bstrdup(optarg);
139 break;
140
141 case 's':
142 set_encryption = true;
143 if (keyfile) {
144 usage();
145 goto bail_out;
146 }
147 keyfile = bstrdup(optarg);
148 break;
149
150 case 'v':
151 volume_encryption_status = true;
152 break;
153
154 case 'w':
155 wrapped_keys = true;
156 wrap_keyfile = bstrdup(optarg);
157 break;
158
159 case '?':
160 default:
161 usage();
162 goto bail_out;
163
164 }
165 }
166
167 argc -= optind;
168 argv += optind;
169
170 if (!generate_passphrase && !show_keydata && !dump_cache && !populate_cache && !reset_cache && argc < 1) {
171 fprintf(stderr, _("Missing device_name argument for this option\n"));
172 usage();
173 retval = 1;
174 goto bail_out;
175 }
176
177 if (generate_passphrase && show_keydata) {
178 fprintf(stderr, _("Either use -g or -k not both\n"));
179 retval = 1;
180 goto bail_out;
181 }
182
183 if (clear_encryption && set_encryption) {
184 fprintf(stderr, _("Either use -c or -s not both\n"));
185 retval = 1;
186 goto bail_out;
187 }
188
189 if ((clear_encryption ||
190 set_encryption) &&
191 (drive_encryption_status ||
192 volume_encryption_status)) {
193 fprintf(stderr, _("Either set or clear the crypto key or ask for status not both\n"));
194 retval = 1;
195 goto bail_out;
196 }
197
198 if ((clear_encryption ||
199 set_encryption ||
200 drive_encryption_status ||
201 volume_encryption_status) &&
202 (generate_passphrase ||
203 show_keydata ||
204 dump_cache ||
205 populate_cache ||
206 reset_cache)) {
207 fprintf(stderr, _("Don't mix operations which are incompatible "
208 "e.g. generate/show vs set/clear etc.\n"));
209 retval = 1;
210 goto bail_out;
211 }
212
213 OSDependentInit();
214 InitMsg(NULL, NULL);
215
216 if (dump_cache) {
217 /*
218 * Load any keys currently in the cache.
219 */
220 ReadCryptoCache(cache_file);
221
222 /*
223 * Dump the content of the cache.
224 */
225 DumpCryptoCache(1);
226
227 FlushCryptoCache();
228 goto bail_out;
229 }
230
231 if (populate_cache) {
232 char *VolumeName, *EncrKey;
233 char new_cache_entry[256];
234
235 /*
236 * Load any keys currently in the cache.
237 */
238 ReadCryptoCache(cache_file);
239
240 /*
241 * Read new entries from stdin and parse them to update
242 * the cache.
243 */
244 fprintf(stdout, _("Enter cache entrie(s) (close with ^D): "));
245 fflush(stdout);
246
247 memset(new_cache_entry, 0, sizeof(new_cache_entry));
248 while (read(1, new_cache_entry, sizeof(new_cache_entry)) > 0) {
249 StripTrailingJunk(new_cache_entry);
250
251 /*
252 * Try to parse the entry.
253 */
254 VolumeName = new_cache_entry;
255 EncrKey = strchr(new_cache_entry, '\t');
256 if (!EncrKey) {
257 break;
258 }
259
260 *EncrKey++ = '\0';
261 UpdateCryptoCache(VolumeName, EncrKey);
262 memset(new_cache_entry, 0, sizeof(new_cache_entry));
263 }
264
265 /*
266 * Write out the new cache entries.
267 */
268 WriteCryptoCache(cache_file);
269
270 FlushCryptoCache();
271 goto bail_out;
272 }
273
274 if (reset_cache) {
275 /*
276 * Load any keys currently in the cache.
277 */
278 ReadCryptoCache(cache_file);
279
280 /*
281 * Reset all entries.
282 */
283 ResetCryptoCache();
284
285 /*
286 * Write out the new cache entries.
287 */
288 WriteCryptoCache(cache_file);
289
290 FlushCryptoCache();
291 goto bail_out;
292 }
293
294 memset(keydata, 0, sizeof(keydata));
295 memset(wrapdata, 0, sizeof(wrapdata));
296
297 if (wrapped_keys) {
298 /*
299 * Read the key bits from the keyfile.
300 * - == stdin
301 */
302 if (bstrcmp(wrap_keyfile, "-")) {
303 kfd = 0;
304 fprintf(stdout, _("Enter Key Encryption Key: "));
305 fflush(stdout);
306 } else {
307 kfd = open(wrap_keyfile, O_RDONLY);
308 if (kfd < 0) {
309 fprintf(stderr, _("Cannot open keyfile %s\n"), wrap_keyfile);
310 retval = 1;
311 goto bail_out;
312 }
313 }
314 read(kfd, wrapdata, sizeof(wrapdata));
315 if (kfd > 0) {
316 close(kfd);
317 }
318 StripTrailingJunk(wrapdata);
319 Dmsg1(10, "Wrapped keydata = %s\n", wrapdata);
320 }
321
322 /*
323 * Generate a new passphrase allow it to be wrapped using the given wrapkey
324 * and base64 if specified or when wrapped.
325 */
326 if (generate_passphrase) {
327 int cnt;
328 char *passphrase;
329
330 passphrase = generate_crypto_passphrase(DEFAULT_PASSPHRASE_LENGTH);
331 if (!passphrase) {
332 retval = 1;
333 goto bail_out;
334 }
335
336 Dmsg1(10, "Generated passphrase = %s\n", passphrase);
337
338 /*
339 * See if we need to wrap the passphrase.
340 */
341 if (wrapped_keys) {
342 char *wrapped_passphrase;
343
344 length = DEFAULT_PASSPHRASE_LENGTH + 8;
345 wrapped_passphrase = (char *)malloc(length);
346 memset(wrapped_passphrase, 0, length);
347 AesWrap((unsigned char *)wrapdata,
348 DEFAULT_PASSPHRASE_LENGTH / 8,
349 (unsigned char *)passphrase,
350 (unsigned char *)wrapped_passphrase);
351
352 free(passphrase);
353 passphrase = wrapped_passphrase;
354 } else {
355 length = DEFAULT_PASSPHRASE_LENGTH;
356 }
357
358 /*
359 * See where to write the key.
360 * - == stdout
361 */
362 if (bstrcmp(keyfile, "-")) {
363 kfd = 1;
364 } else {
365 kfd = open(keyfile, O_WRONLY | O_CREAT, 0644);
366 if (kfd < 0) {
367 fprintf(stderr, _("Cannot open keyfile %s\n"), keyfile);
368 free(passphrase);
369 retval = 1;
370 goto bail_out;
371 }
372 }
373
374 if (base64_transform || wrapped_keys) {
375 cnt = BinToBase64(keydata, sizeof(keydata), passphrase, length, true);
376 if (write(kfd, keydata, cnt) != cnt) {
377 fprintf(stderr, _("Failed to write %d bytes to keyfile %s\n"), cnt, keyfile);
378 }
379 } else {
380 cnt = DEFAULT_PASSPHRASE_LENGTH;
381 if (write(kfd, passphrase, cnt) != cnt) {
382 fprintf(stderr, _("Failed to write %d bytes to keyfile %s\n"), cnt, keyfile);
383 }
384 }
385
386 Dmsg1(10, "Keydata = %s\n", keydata);
387
388 if (kfd > 1) {
389 close(kfd);
390 } else {
391 write(kfd, "\n", 1);
392 }
393 free(passphrase);
394 goto bail_out;
395 }
396
397 if (show_keydata) {
398 char *passphrase;
399
400 /*
401 * Read the key bits from the keyfile.
402 * - == stdin
403 */
404 if (bstrcmp(keyfile, "-")) {
405 kfd = 0;
406 fprintf(stdout, _("Enter Encryption Key: "));
407 fflush(stdout);
408 } else {
409 kfd = open(keyfile, O_RDONLY);
410 if (kfd < 0) {
411 fprintf(stderr, _("Cannot open keyfile %s\n"), keyfile);
412 retval = 1;
413 goto bail_out;
414 }
415 }
416 read(kfd, keydata, sizeof(keydata));
417 if (kfd > 0) {
418 close(kfd);
419 }
420 StripTrailingJunk(keydata);
421 Dmsg1(10, "Keydata = %s\n", keydata);
422
423 /*
424 * See if we need to unwrap the passphrase.
425 */
426 if (wrapped_keys) {
427 char *wrapped_passphrase;
428 /*
429 * A wrapped key is base64 encoded after it was wrapped so first
430 * convert it from base64 to bin. As we first go from base64 to bin
431 * and the Base64ToBin has a check if the decoded string will fit
432 * we need to alocate some more bytes for the decoded buffer to be
433 * sure it will fit.
434 */
435 length = DEFAULT_PASSPHRASE_LENGTH + 12;
436 wrapped_passphrase = (char *)malloc(length);
437 memset(wrapped_passphrase, 0, length);
438 if (Base64ToBin(wrapped_passphrase, length,
439 keydata, strlen(keydata)) == 0) {
440 fprintf(stderr,
441 _("Failed to base64 decode the keydata read from %s, aborting...\n"),
442 keyfile);
443 free(wrapped_passphrase);
444 goto bail_out;
445 }
446
447 length = DEFAULT_PASSPHRASE_LENGTH;
448 passphrase = (char *)malloc(length);
449 memset(passphrase, 0, length);
450
451 if (AesUnwrap((unsigned char *)wrapdata,
452 length / 8,
453 (unsigned char *)wrapped_passphrase,
454 (unsigned char *)passphrase) == -1) {
455 fprintf(stderr,
456 _("Failed to aes unwrap the keydata read from %s using the wrap data from %s, aborting...\n"),
457 keyfile, wrap_keyfile);
458 free(wrapped_passphrase);
459 goto bail_out;
460 }
461
462 free(wrapped_passphrase);
463 } else {
464 if (base64_transform) {
465 /*
466 * As we first go from base64 to bin and the Base64ToBin has a check
467 * if the decoded string will fit we need to alocate some more bytes
468 * for the decoded buffer to be sure it will fit.
469 */
470 length = DEFAULT_PASSPHRASE_LENGTH + 4;
471 passphrase = (char *)malloc(length);
472 memset(passphrase, 0, length);
473
474 Base64ToBin(passphrase, length, keydata, strlen(keydata));
475 } else {
476 length = DEFAULT_PASSPHRASE_LENGTH;
477 passphrase = (char *)malloc(length);
478 memset(passphrase, 0, length);
479 bstrncpy(passphrase, keydata, length);
480 }
481 }
482
483 Dmsg1(10, "Unwrapped passphrase = %s\n", passphrase);
484 fprintf(stdout, "%s\n", passphrase);
485
486 free(passphrase);
487 goto bail_out;
488 }
489
490 /*
491 * Clear the loaded encryption key of the given drive.
492 */
493 if (clear_encryption) {
494 if (ClearScsiEncryptionKey(-1, argv[0])) {
495 goto bail_out;
496 } else {
497 retval = 1;
498 goto bail_out;
499 }
500 }
501
502 /*
503 * Get the drive encryption status of the given drive.
504 */
505 if (drive_encryption_status) {
506 POOLMEM *encryption_status = GetPoolMemory(PM_MESSAGE);
507
508 if (GetScsiDriveEncryptionStatus(-1, argv[0], encryption_status, 0)) {
509 fprintf(stdout, "%s", encryption_status);
510 FreePoolMemory(encryption_status);
511 } else {
512 retval = 1;
513 FreePoolMemory(encryption_status);
514 goto bail_out;
515 }
516 }
517
518 /*
519 * Load a new encryption key onto the given drive.
520 */
521 if (set_encryption) {
522 /*
523 * Read the key bits from the keyfile.
524 * - == stdin
525 */
526 if (bstrcmp(keyfile, "-")) {
527 kfd = 0;
528 fprintf(stdout, _("Enter Encryption Key (close with ^D): "));
529 fflush(stdout);
530 } else {
531 kfd = open(keyfile, O_RDONLY);
532 if (kfd < 0) {
533 fprintf(stderr, _("Cannot open keyfile %s\n"), keyfile);
534 retval = 1;
535 goto bail_out;
536 }
537 }
538 read(kfd, keydata, sizeof(keydata));
539 if (kfd > 0) {
540 close(kfd);
541 }
542 StripTrailingJunk(keydata);
543
544 if (SetScsiEncryptionKey(-1, argv[0], keydata)) {
545 goto bail_out;
546 } else {
547 retval = 1;
548 goto bail_out;
549 }
550 }
551
552 /*
553 * Get the volume encryption status of volume currently loaded in the given drive.
554 */
555 if (volume_encryption_status) {
556 POOLMEM *encryption_status = GetPoolMemory(PM_MESSAGE);
557
558 if (GetScsiVolumeEncryptionStatus(-1, argv[0], encryption_status, 0)) {
559 fprintf(stdout, "%s", encryption_status);
560 FreePoolMemory(encryption_status);
561 } else {
562 retval = 1;
563 FreePoolMemory(encryption_status);
564 goto bail_out;
565 }
566 }
567
568 bail_out:
569 if (cache_file) {
570 free(cache_file);
571 }
572
573 if (keyfile) {
574 free(keyfile);
575 }
576
577 if (wrap_keyfile) {
578 free(wrap_keyfile);
579 }
580
581 exit(retval);
582 }
583