From 418b7689e1ef575d036047354cad6b22eea0736d Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Wed, 13 Mar 2019 11:09:28 -0400 Subject: Add support for hashsig key export/import. --- utils/Makefile | 9 +-- utils/pkey-export.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++ utils/pkey-import.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 360 insertions(+), 4 deletions(-) create mode 100644 utils/pkey-export.c create mode 100644 utils/pkey-import.c (limited to 'utils') diff --git a/utils/Makefile b/utils/Makefile index c9899f6..e88cb87 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -29,14 +29,15 @@ LIBHAL_SRC ?= .. LIBHAL_BLD ?= ${LIBHAL_SRC} +LIBTFM_BLD ?= ../../thirdparty/libtfm -LIBS = ${LIBHAL_BLD}/libhal.a +LIBS = ${LIBHAL_BLD}/libhal.a ${LIBTFM_BLD}/libtfm.a -CFLAGS ?= -g3 -Wall -fPIC -std=c99 -I${LIBHAL_SRC} +CFLAGS ?= -g3 -Wall -fPIC -std=c99 -I${LIBHAL_SRC} -I${LIBTFM_BLD} -BIN = eim_peek_poke cores +BIN = $(if $(wildcard ${LIBHAL_BLD}/hal_io_eim.o),eim_peek_poke) $(if $(wildcard ${LIBHAL_BLD}/core.o),cores) pkey-export pkey-import -all: $(if $(wildcard ${LIBHAL_BLD}/hal_io_eim.o),eim_peek_poke) $(if $(wildcard ${LIBHAL_BLD}/core.o),cores) +all: ${BIN} clean: rm -f *.o ${BIN} diff --git a/utils/pkey-export.c b/utils/pkey-export.c new file mode 100644 index 0000000..660052e --- /dev/null +++ b/utils/pkey-export.c @@ -0,0 +1,187 @@ +/* + * pkey-export.c + * ------------- + * Export a key. + * + * Copyright (c) 2018, NORDUnet A/S + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of the NORDUnet 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 + * HOLDER 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. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define HAL_KS_WRAPPED_KEYSIZE ((2373 + 6 * 4096 / 8 + 6 * 4 + 15) & ~7) + +#define lose(...) do { printf(__VA_ARGS__); goto fail; } while (0) + +static int read_file(const char * const fn, uint8_t * const buf, size_t *buf_len, const size_t buf_max) +{ + int fd; + if ((fd = open(fn, O_RDONLY)) == -1) + lose("Error opening %s: %s\n", fn, strerror(errno)); + + size_t nread; + if ((nread = read(fd, buf, buf_max)) == -1) + lose("Error reading %s: %s\n", fn, strerror(errno)); + + *buf_len = nread; + + if (close(fd) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); + + return 0; + +fail: + return -1; +} + +static int write_buf(const char * const name, const char * const ext, const uint8_t * const buf, const size_t buf_len) +{ + char fn[strlen(name) + strlen(ext) + 1]; + strcpy(fn, name); + strcat(fn, ext); + + int fd = creat(fn, S_IRUSR); + if (fd == -1) + lose("Error opening %s: %s\n", fn, strerror(errno)); + + ssize_t nwrite; + if ((nwrite = write(fd, buf, buf_len)) != buf_len) + lose("Error writing %s: wrote %lu, expected %lu\n", fn, nwrite, buf_len); + + if (close(fd) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); + + return 0; + +fail: + return -1; +} + +#define lose_usage(...) do { printf(__VA_ARGS__); printf(usage, argv[0]); goto fail; } while (0) + +int main(int argc, char *argv[]) +{ + hal_error_t err; + const hal_client_handle_t client = {HAL_HANDLE_NONE}; + const hal_session_handle_t session = {HAL_HANDLE_NONE}; + char *pin = "fnord"; + char *kekek_fn = NULL; + char *save_fn = NULL; + char *keyname = NULL; + +char usage[] = "\ +Usage: %s [-p pin] <-k kekek> [-o outfile] keyname\n\ +"; + + int opt; + while ((opt = getopt(argc, argv, "p:k:o:")) != -1) { + switch (opt) { + case 'p': + pin = optarg; + break; + case 'k': + kekek_fn = optarg; + break; + case 'o': + save_fn = optarg; + break; + case 'h': + case '?': + printf(usage, argv[0]); + return 0; + } + } + keyname = argv[optind]; + + if (kekek_fn == NULL) + lose_usage("Error: missing option -k\n"); + if (save_fn == NULL) + save_fn = keyname; + if (keyname == NULL) + lose_usage("Error: missing keyname\n"); + + uint8_t kekek_der[HAL_KS_WRAPPED_KEYSIZE]; size_t kekek_der_len; + if (read_file(kekek_fn, kekek_der, &kekek_der_len, sizeof(kekek_der)) != 0) + goto fail; + + hal_uuid_t pkey_name; + + if ((err = hal_uuid_parse(&pkey_name, keyname)) != HAL_OK) + lose("Error parsing private key name: %s\n", hal_error_string(err)); + + + if ((err = hal_rpc_client_init()) != HAL_OK) + lose("Error initializing RPC client: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_login(client, HAL_USER_NORMAL, pin, strlen(pin))) != HAL_OK) + lose("Error logging into HSM: %s\n", hal_error_string(err)); + + hal_pkey_handle_t pkey = {HAL_HANDLE_NONE}; + + if ((err = hal_rpc_pkey_open(client, session, &pkey, &pkey_name)) != HAL_OK) + lose("Error opening private key: %s\n", hal_error_string(err)); + + hal_pkey_handle_t kekek = {HAL_HANDLE_NONE}; + hal_uuid_t kekek_name; + + if ((err = hal_rpc_pkey_load(client, session, &kekek, &kekek_name, + kekek_der, kekek_der_len, + HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT)) != HAL_OK) + lose("Error loading export key: %s\n", hal_error_string(err)); + + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; size_t der_len; + uint8_t kek[HAL_KS_WRAPPED_KEYSIZE]; size_t kek_len; + + if ((err = hal_rpc_pkey_export(pkey, kekek, + der, &der_len, sizeof(der), + kek, &kek_len, sizeof(kek))) != HAL_OK) + lose("Error exporting private key: %s\n", hal_error_string(err)); + + if (write_buf(save_fn, ".der", der, der_len) != 0 || + write_buf(save_fn, ".kek", kek, kek_len) != 0) + goto fail; + + if ((err = hal_rpc_logout(client)) != HAL_OK) + lose("Error logging out of HSM: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_client_close()) != HAL_OK) + lose("Error shutting down RPC client: %s\n", hal_error_string(err)); + + return 0; + +fail: + return -1; +} diff --git a/utils/pkey-import.c b/utils/pkey-import.c new file mode 100644 index 0000000..611448f --- /dev/null +++ b/utils/pkey-import.c @@ -0,0 +1,168 @@ +/* + * pkey-import.c + * ------------- + * Import a key. + * + * Copyright (c) 2018, NORDUnet A/S + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of the NORDUnet 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 + * HOLDER 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. + */ + +#include +#include +#include +#include +#include + +#include + +#define HAL_KS_WRAPPED_KEYSIZE ((2373 + 6 * 4096 / 8 + 6 * 4 + 15) & ~7) + +#define lose(...) do { printf(__VA_ARGS__); goto fail; } while (0) + +static int read_file(const char * const fn, uint8_t * const buf, size_t *buf_len, const size_t buf_max) +{ + int fd; + if ((fd = open(fn, O_RDONLY)) == -1) + lose("Error opening %s: %s\n", fn, strerror(errno)); + + size_t nread; + if ((nread = read(fd, buf, buf_max)) == -1) + lose("Error reading %s: %s\n", fn, strerror(errno)); + + *buf_len = nread; + + if (close(fd) != 0) + lose("Error closing %s: %s\n", fn, strerror(errno)); + + return 0; + +fail: + return -1; +} + +static int read_buf(const char * const name, const char * const ext, uint8_t * const buf, size_t *buf_len, const size_t buf_max) +{ + char fn[strlen(name) + strlen(ext) + 1]; + strcpy(fn, name); + strcat(fn, ext); + + return read_file(fn, buf, buf_len, buf_max); +} + +#define lose_usage(...) do { printf(__VA_ARGS__); printf(usage, argv[0]); goto fail; } while (0) + +int main(int argc, char *argv[]) +{ + hal_error_t err; + const hal_client_handle_t client = {HAL_HANDLE_NONE}; + const hal_session_handle_t session = {HAL_HANDLE_NONE}; + char *pin = "fnord"; + char *kekek_fn = NULL; + char *key_fn = NULL; + +char usage[] = "\ +Usage: %s [-p pin] <-k kekek> keyfile\n\ +"; + + int opt; + while ((opt = getopt(argc, argv, "p:k:")) != -1) { + switch (opt) { + case 'p': + pin = optarg; + break; + case 'k': + kekek_fn = optarg; + break; + case 'h': + case '?': + printf(usage, argv[0]); + return 0; + } + } + key_fn = argv[optind]; + + if (kekek_fn == NULL) + lose_usage("Error: missing option -k\n"); + if (key_fn == NULL) + lose_usage("Error: missing keyfile\n"); + + uint8_t kekek_der[HAL_KS_WRAPPED_KEYSIZE]; size_t kekek_der_len; + + if (read_file(kekek_fn, kekek_der, &kekek_der_len, sizeof(kekek_der)) != 0) + goto fail; + + uint8_t der[HAL_KS_WRAPPED_KEYSIZE]; size_t der_len; + uint8_t kek[HAL_KS_WRAPPED_KEYSIZE]; size_t kek_len; + + if (read_buf(key_fn, ".der", der, &der_len, sizeof(der)) != 0 || + read_buf(key_fn, ".kek", kek, &kek_len, sizeof(kek)) != 0) + goto fail; + + if ((err = hal_rpc_client_init()) != HAL_OK) + lose("Error initializing RPC client: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_login(client, HAL_USER_NORMAL, pin, strlen(pin))) != HAL_OK) + lose("Error logging into HSM: %s\n", hal_error_string(err)); + + hal_pkey_handle_t kekek = {HAL_HANDLE_NONE}; + hal_uuid_t kekek_name; + + if ((err = hal_rpc_pkey_load(client, session, &kekek, &kekek_name, + kekek_der, kekek_der_len, + HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT)) != HAL_OK) + lose("Error loading import key: %s\n", hal_error_string(err)); + + hal_pkey_handle_t private_key = {HAL_HANDLE_NONE}; + hal_uuid_t private_name; + + if ((err = hal_rpc_pkey_import(client, session, + &private_key, &private_name, + kekek, + der, der_len, + kek, kek_len, + HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_TOKEN | HAL_KEY_FLAG_EXPORTABLE)) != HAL_OK) + lose("Error importing private key: %s\n", hal_error_string(err)); + + char name_str[HAL_UUID_TEXT_SIZE]; + + if ((err = hal_uuid_format(&private_name, name_str, sizeof(name_str))) != HAL_OK) + lose("Error formatting private key name: %s\n", hal_error_string(err)); + printf("New private key name: %s\n", name_str); + + if ((err = hal_rpc_logout(client)) != HAL_OK) + lose("Error logging out of HSM: %s\n", hal_error_string(err)); + + if ((err = hal_rpc_client_close()) != HAL_OK) + lose("Error shutting down RPC client: %s\n", hal_error_string(err)); + + return 0; + +fail: + return -1; +} -- cgit v1.2.3