diff --git a/Makefile.am b/Makefile.am index 7133a020..27c9e5de 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,7 +3,8 @@ # FIXME run cppcheck -SUBDIRS = lvm +SUBDIRS = lib +SUBDIRS += lvm SUBDIRS += vhd SUBDIRS += cpumond SUBDIRS += control diff --git a/cbt/Makefile.am b/cbt/Makefile.am index 00eda090..0aa635a0 100644 --- a/cbt/Makefile.am +++ b/cbt/Makefile.am @@ -9,7 +9,7 @@ sbin_PROGRAMS = cbt-util noinst_LTLIBRARIES = libcbtutil.la libcbtutil_la_SOURCES = cbt-util.c -libcbtutil_la_LIBADD = -luuid +libcbtutil_la_LIBADD = -luuid $(top_builddir)/lib/libblktaputil.la cbt_util_SOURCES = main.c cbt_util_LDADD = libcbtutil.la diff --git a/cbt/cbt-util.c b/cbt/cbt-util.c index cb05a758..cd218d90 100644 --- a/cbt/cbt-util.c +++ b/cbt/cbt-util.c @@ -42,6 +42,7 @@ #include "cbt-util.h" #include "cbt-util-priv.h" +#include "util.h" int cbt_util_create(int , char **); int cbt_util_set(int , char **); @@ -148,7 +149,7 @@ cbt_util_get(int argc, char **argv) { char *name, uuid_str[37], *buf; int err, c, ret; - int parent, child, flag, size, bitmap; + int parent, child, flag, size, bitmap, use_base64; FILE *f = NULL; err = 0; @@ -159,6 +160,7 @@ cbt_util_get(int argc, char **argv) size = 0; buf = NULL; bitmap = 0; + use_base64 = 0; if (!argc || !argv) goto usage; @@ -166,7 +168,7 @@ cbt_util_get(int argc, char **argv) /* Make sure we start from the start of the args */ optind = 1; - while ((c = getopt(argc, argv, "n:pcfsbh")) != -1) { + while ((c = getopt(argc, argv, "n:pcfsbEh")) != -1) { switch (c) { case 'n': name = optarg; @@ -186,6 +188,9 @@ cbt_util_get(int argc, char **argv) case 'b': bitmap = 1; break; + case 'E': + use_base64 = 1; + break; case 'h': default: goto usage; @@ -252,7 +257,18 @@ cbt_util_get(int argc, char **argv) bmsize, name); } - fwrite(buf, bmsize, 1, stdout); + if (use_base64) { + char *encoded_buf; + if (base64_encode_data((uint8_t*)buf, bmsize, &encoded_buf) != 0) { + fprintf(stderr, "Failed to encode bitmap to base64\n"); + err = -EIO; + goto error; + } + printf("%s", encoded_buf); + free(encoded_buf); + } else { + fwrite(buf, bmsize, 1, stdout); + } } error: @@ -273,6 +289,7 @@ cbt_util_get(int argc, char **argv) printf("[-f]\t\tPrint consistency flag\n"); printf("[-s]\t\tPrint size of disk in bytes\n"); printf("[-b]\t\tPrint bitmap contents\n"); + printf("[-E]\t\tEncode bitmap output as base64\n"); printf("[-h]\t\thelp\n"); return -EINVAL; diff --git a/configure.ac b/configure.ac index a419f8ae..28583575 100644 --- a/configure.ac +++ b/configure.ac @@ -58,6 +58,7 @@ AC_DEFINE(_BLKTAP, 1, Indicates whether this is an internal or external compilation.) AC_CONFIG_FILES([ Makefile +lib/Makefile lvm/Makefile cpumond/Makefile cbt/Makefile diff --git a/control/Makefile.am b/control/Makefile.am index 5fc8f000..ce12fd2c 100644 --- a/control/Makefile.am +++ b/control/Makefile.am @@ -12,7 +12,8 @@ AM_CPPFLAGS += -DTAPDISK_EXECDIR='"$(libexecdir)"' AM_CPPFLAGS += -DTAPDISK_BUILDDIR='"$(top_builddir)/drivers"' sbin_PROGRAMS = tap-ctl -tap_ctl_LDADD = libblktapctl.la +tap_ctl_SOURCES = tap-ctl.c +tap_ctl_LDADD = libblktapctl.la $(top_builddir)/lib/libblktaputil.la lib_LTLIBRARIES = libblktapctl.la diff --git a/control/tap-ctl.c b/control/tap-ctl.c index baa4463e..00da72d3 100644 --- a/control/tap-ctl.c +++ b/control/tap-ctl.c @@ -41,8 +41,7 @@ #include #include "tap-ctl.h" - -#define MAX_AES_XTS_PLAIN_KEYSIZE 1024 +#include "util.h" typedef int (*tap_ctl_func_t) (int, char **); @@ -708,7 +707,7 @@ tap_cli_open_usage(FILE *stream) "fail over to the secondary image on ENOSPC] " "[-t request timeout in seconds] [-D no O_DIRECT] " "[-C insert log layer to track changed blocks] " - "[-E read encryption key from stdin]\n"); + "[-E read base64-encoded encryption key from stdin]\n"); } static int @@ -773,13 +772,33 @@ tap_cli_open(int argc, char **argv) fprintf(stderr, "Only supply -E once\n"); exit(1); } - /* Allocate the space for the key, */ + + char base64_key[512]; + ssize_t read_len = read(STDIN_FILENO, base64_key, sizeof(base64_key) - 1); + if (read_len <= 0) { + fprintf(stderr, "Failed to read base64 key from stdin\n"); + exit(1); + } + base64_key[read_len] = '\0'; + + if (read_len > 0 && base64_key[read_len - 1] == '\n') { + base64_key[read_len - 1] = '\0'; + } + encryption_key = malloc(MAX_AES_XTS_PLAIN_KEYSIZE / sizeof(uint8_t)); if (!encryption_key) { - fprintf(stderr, "Failed to allocate space for encrpytion key\n"); + fprintf(stderr, "Failed to allocate space for encryption key\n"); + exit(1); + } + + /* Decode base64 to binary key */ + size_t decoded_len; + if (base64_decode_key(base64_key, encryption_key, &decoded_len) != 0) { + fprintf(stderr, "Failed to decode base64 encryption key\n"); + free(encryption_key); exit(1); } - key_size = read(STDIN_FILENO, (void*)encryption_key, MAX_AES_XTS_PLAIN_KEYSIZE / sizeof(uint8_t)); + key_size = decoded_len; if (key_size != 32 && key_size != 64){ fprintf(stderr, "Unsupported keysize, use either 256 bit or 512 bit key\n"); free(encryption_key); diff --git a/include/util.h b/include/util.h index e2529a51..2ea46f24 100644 --- a/include/util.h +++ b/include/util.h @@ -33,6 +33,7 @@ #include #include +#include #define ARRAY_SIZE(_a) (sizeof(_a)/sizeof((_a)[0])) @@ -49,4 +50,15 @@ safe_strncpy(char *dest, const char *src, size_t n) return pdest; } +/* + * Constants for cryptographic operations + */ +#define MAX_AES_XTS_PLAIN_KEYSIZE 1024 + +/* + * Base64 encoding/decoding utilities using OpenSSL + */ +int base64_encode_data(const uint8_t *input, size_t input_len, char **output); +int base64_decode_key(const char *input, uint8_t *output, size_t *output_len); + #endif /* __TAPDISK_UTIL_H__ */ diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..f7fc620d --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,14 @@ +AM_CFLAGS = -Wall +AM_CFLAGS += -Werror +AM_CFLAGS += $(if $(GCOV),-fprofile-dir=/tmp/coverage/blktap/lib -fprofile-arcs -ftest-coverage) + +AM_CPPFLAGS = -I$(top_srcdir)/include + +lib_LTLIBRARIES = libblktaputil.la + +libblktaputil_la_SOURCES = util.c +libblktaputil_la_LDFLAGS = -version-info 1:0:0 +libblktaputil_la_LIBADD = -lssl -lcrypto + +clean-local: + -rm -rf *.gc?? diff --git a/lib/util.c b/lib/util.c new file mode 100644 index 00000000..c26d9b8f --- /dev/null +++ b/lib/util.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) Cloud Software Group, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "util.h" + +int +base64_encode_data(const uint8_t *input, size_t input_len, char **output) +{ + BIO *bio, *b64; + BUF_MEM *bufferPtr; + + if (!input || input_len == 0 || !output) { + return -1; + } + + *output = NULL; + + b64 = BIO_new(BIO_f_base64()); + bio = BIO_new(BIO_s_mem()); + if (!b64 || !bio) { + if (b64) BIO_free(b64); + if (bio) BIO_free(bio); + return -1; + } + + bio = BIO_push(b64, bio); + BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); + + if (BIO_write(bio, input, input_len) != (int)input_len) { + BIO_free_all(bio); + return -1; + } + + if (BIO_flush(bio) != 1) { + BIO_free_all(bio); + return -1; + } + + BIO_get_mem_ptr(bio, &bufferPtr); + *output = malloc(bufferPtr->length + 1); + if (!*output) { + BIO_free_all(bio); + return -1; + } + + memcpy(*output, bufferPtr->data, bufferPtr->length); + (*output)[bufferPtr->length] = '\0'; + + BIO_free_all(bio); + return 0; +} + +int +base64_decode_key(const char *input, uint8_t *output, size_t *output_len) +{ + BIO *bio, *b64; + int decoded_len; + + if (!input || !output || !output_len || strlen(input) == 0) { + return -1; + } + + *output_len = 0; + + b64 = BIO_new(BIO_f_base64()); + bio = BIO_new_mem_buf((void*)input, strlen(input)); + if (!b64 || !bio) { + if (b64) BIO_free(b64); + if (bio) BIO_free(bio); + return -1; + } + + bio = BIO_push(b64, bio); + BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); + + decoded_len = BIO_read(bio, output, MAX_AES_XTS_PLAIN_KEYSIZE); + BIO_free_all(bio); + + if (decoded_len < 0) { + return -1; + } + + *output_len = decoded_len; + return 0; +} diff --git a/vhd/lib/Makefile.am b/vhd/lib/Makefile.am index 69500739..463c8ae5 100644 --- a/vhd/lib/Makefile.am +++ b/vhd/lib/Makefile.am @@ -42,7 +42,7 @@ libvhd_la_SOURCES += xattr.h libvhd_la_LDFLAGS = -version-info 1:1:1 -libvhd_la_LIBADD = -luuid -ldl $(LIBICONV) $(top_srcdir)/lvm/liblvmutil.la +libvhd_la_LIBADD = -luuid -ldl $(LIBICONV) $(top_builddir)/lib/libblktaputil.la $(top_srcdir)/lvm/liblvmutil.la if ENABLE_TESTS MAYBE_test = test diff --git a/vhd/lib/vhd-util-read.c b/vhd/lib/vhd-util-read.c index 8d1bc4bc..68150065 100644 --- a/vhd/lib/vhd-util-read.c +++ b/vhd/lib/vhd-util-read.c @@ -41,6 +41,7 @@ #include "libvhd.h" #include "vhd-util.h" +#include "util.h" #define nsize 21 static char nbuf[nsize]; @@ -418,7 +419,7 @@ vhd_print_bat(vhd_context_t *vhd, uint64_t block, int count, int hex) } static int -vhd_print_bat_str(vhd_context_t *vhd) +vhd_print_bat_str(vhd_context_t *vhd, int use_base64) { int i, err, total_blocks, bitmap_size; char *bitmap; @@ -444,9 +445,20 @@ vhd_print_bat_str(vhd_context_t *vhd) set_bit(bitmap, i); } - n = write(STDOUT_FILENO, bitmap, bitmap_size); - if (n < 0) - err = -errno; + if (use_base64) { + char *encoded_buf; + if (base64_encode_data((uint8_t*)bitmap, bitmap_size, &encoded_buf) != 0) { + fprintf(stderr, "Failed to encode BAT bitmap to base64\n"); + err = -EIO; + } else { + printf("%s", encoded_buf); + free(encoded_buf); + } + } else { + n = write(STDOUT_FILENO, bitmap, bitmap_size); + if (n < 0) + err = -errno; + } free(bitmap); @@ -760,7 +772,7 @@ vhd_util_read(int argc, char **argv) { char *name; vhd_context_t vhd; - int c, err, headers, hex, bat_str, cache, flags; + int c, err, headers, hex, bat_str, cache, flags, bat_base64; uint64_t bat, bitmap, tbitmap, ebitmap, batmap, tbatmap, data, lsec, count, read; uint64_t bread; @@ -769,6 +781,7 @@ vhd_util_read(int argc, char **argv) cache = 0; headers = 0; bat_str = 0; + bat_base64 = 0; count = 1; bat = -1; bitmap = -1; @@ -786,7 +799,7 @@ vhd_util_read(int argc, char **argv) goto usage; optind = 0; - while ((c = getopt(argc, argv, "n:pt:b:Bm:i:e:aj:d:c:r:R:xCh")) != -1) { + while ((c = getopt(argc, argv, "n:pt:b:Bm:i:e:aj:d:c:r:R:xCEh")) != -1) { switch(c) { case 'n': name = optarg; @@ -836,6 +849,10 @@ vhd_util_read(int argc, char **argv) case 'x': hex = 1; break; + + case 'E': + bat_base64 = 1; + break; case 'h': default: goto usage; @@ -877,7 +894,7 @@ vhd_util_read(int argc, char **argv) } if (bat_str) { - err = vhd_print_bat_str(&vhd); + err = vhd_print_bat_str(&vhd, bat_base64); if (err) goto out; } @@ -953,6 +970,7 @@ vhd_util_read(int argc, char **argv) "-c num num units\n" "-r sec read num sectors at sec\n" "-R byte read num bytes at byte\n" - "-x print in hex\n"); + "-x print in hex\n" + "-E encode BAT bitmap output as base64\n"); return EINVAL; }