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