From e77dba6def5ceb44ea83e7ba5422098cd9c91ad2 Mon Sep 17 00:00:00 2001 From: Aveen Ismail Date: Wed, 18 Sep 2024 18:15:06 +0200 Subject: [PATCH] Add support for X509Certificate through cmd line flag --- lib/CMakeLists.txt | 15 +++++++++++++-- lib/yubihsm.c | 41 +++++++++++++++++++++++++++++++++++++++ lib/yubihsm.h | 34 +++++++++++++++++++++++++------- src/cmdline.ggo | 1 + src/commands.c | 48 ++++++++++++++-------------------------------- src/main.c | 14 ++++++++------ 6 files changed, 104 insertions(+), 49 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 79d82944..5319f8f7 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -37,6 +37,17 @@ set ( yubihsm.c ) +if (ENABLE_CERT_COMPRESS) + set(SOURCE ${SOURCE} ../common/data_compress.c) + + find_library(ZLIB zlib PATHS ${ZLIB_LIB_DIR}) + include_directories(${ZLIB_INCL_DIR}) + + find_package(ZLIB REQUIRED) + + set(ZLIB_LIBS "ZLIB::ZLIB") +endif() + if(MSVC) set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/../common/time_win.c) endif(MSVC) @@ -148,11 +159,11 @@ add_coverage (yubihsm_http) add_definitions (-DVERSION="${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") add_definitions (-DSOVERSION="${yubihsm_shell_VERSION_MAJOR}") -target_link_libraries (yubihsm ${CRYPT_LIBRARY} ${ADDITIONAL_LIBRARY}) +target_link_libraries (yubihsm ${CRYPT_LIBRARY} ${ADDITIONAL_LIBRARY} ${ZLIB_LIBS}) target_link_libraries (yubihsm_usb ${USB_LIBRARY}) target_link_libraries (yubihsm_http ${HTTP_LIBRARY}) if(ENABLE_STATIC) - target_link_libraries (yubihsm_static ${CRYPT_LIBRARY} ${ADDITIONAL_LIBRARY} ${HTTP_LIBRARY} ${USB_LIBRARY}) + target_link_libraries (yubihsm_static ${CRYPT_LIBRARY} ${ADDITIONAL_LIBRARY} ${HTTP_LIBRARY} ${USB_LIBRARY} ${ZLIB_LIBS}) endif(ENABLE_STATIC) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yubihsm.pc.in ${CMAKE_CURRENT_BINARY_DIR}/yubihsm.pc @ONLY) diff --git a/lib/yubihsm.c b/lib/yubihsm.c index 1ce641ca..f65ded75 100644 --- a/lib/yubihsm.c +++ b/lib/yubihsm.c @@ -41,6 +41,7 @@ #include "../common/insecure_memzero.h" #include "../ykhsmauth/ykhsmauth.h" +#include "../common/data_compress.h" #define STATIC_USB_BACKEND "usb" #define STATIC_HTTP_BACKEND "http" @@ -3366,6 +3367,46 @@ yh_rc yh_util_get_opaque(yh_session *session, uint16_t object_id, uint8_t *out, return YHR_SUCCESS; } +yh_rc yh_util_import_opaque_ex(yh_session *session, uint16_t *object_id, + const char *label, uint16_t domains, + const yh_capabilities *capabilities, + yh_algorithm algorithm, bool compress, + const uint8_t *in, size_t in_len) { +#ifndef USE_CERT_COMPRESS + if(compress) { + DBG_ERR("Compression not supported"); + return YHR_INVALID_PARAMETERS; + } +#endif + + if(compress && algorithm != YH_ALGO_OPAQUE_X509_CERTIFICATE) { + DBG_ERR("Compression of non-X509Cerificate is not supported"); + return YHR_INVALID_PARAMETERS; + } + + if(compress) { + if (in == NULL) { + DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); + return YHR_INVALID_PARAMETERS; + } + + uint8_t compressed_data[YH_MSG_BUF_SIZE] = {0}; + size_t compressed_data_len = sizeof(compressed_data); + + if (compress_data((unsigned char *) in, in_len, compressed_data, + &compressed_data_len) != 0) { + fprintf(stderr, "Couldn't compress certificate\n"); + return YHR_GENERIC_ERROR; + } + return yh_util_import_opaque(session, object_id, label, domains, + capabilities, algorithm, compressed_data, + compressed_data_len); + } else { + return yh_util_import_opaque(session, object_id, label, domains, + capabilities, algorithm, in, in_len); + } +} + yh_rc yh_util_import_opaque(yh_session *session, uint16_t *object_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, diff --git a/lib/yubihsm.h b/lib/yubihsm.h index 6ed01f69..ace6b3a5 100644 --- a/lib/yubihsm.h +++ b/lib/yubihsm.h @@ -529,10 +529,6 @@ typedef enum { YH_ALGO_AES_CBC = 54, /// aes-kwp YH_ALGO_AES_KWP = 55, -#ifdef USE_CERT_COMPRESS - /// Compressed certificate - YH_ALGO_OPAQUE_X509_COMPRESSED = 128, -#endif } yh_algorithm; /** @@ -752,9 +748,6 @@ static const struct { {"mgf1-sha512", YH_ALGO_MGF1_SHA512}, {"opaque-data", YH_ALGO_OPAQUE_DATA}, {"opaque-x509-certificate", YH_ALGO_OPAQUE_X509_CERTIFICATE}, -#ifdef USE_CERT_COMPRESS - {"opaque-x509-compressed", YH_ALGO_OPAQUE_X509_COMPRESSED}, -#endif {"rsa-oaep-sha1", YH_ALGO_RSA_OAEP_SHA1}, {"rsa-oaep-sha256", YH_ALGO_RSA_OAEP_SHA256}, {"rsa-oaep-sha384", YH_ALGO_RSA_OAEP_SHA384}, @@ -2221,6 +2214,33 @@ yh_rc yh_util_set_log_index(yh_session *session, uint16_t index); yh_rc yh_util_get_opaque(yh_session *session, uint16_t object_id, uint8_t *out, size_t *out_len); +/** + * Import an #YH_OPAQUE object into the device + * + * @param session Authenticated session to use + * @param object_id Object ID of the Opaque object. 0 if the Object ID should be + *generated by the device + * @param label Label of the Opaque object. Maximum length is #YH_OBJ_LABEL_LEN + * @param domains Domains the Opaque object will be operating within. See + *#yh_string_to_domains() + * @param capabilities Capabilities of the Opaque object. See + *#yh_string_to_capabilities() + * @param algorithm Algorithm of the Opaque object + * @param compress If true, compress cert data before import + * @param in the Opaque object to import + * @param in_len Length of the Opaque object to import + * + * @return #YHR_SUCCESS if successful. + * #YHR_INVALID_PARAMETERS if input parameters are NULL or + *in_len is too big. + * See #yh_rc for other possible errors + **/ +yh_rc yh_util_import_opaque_ex(yh_session *session, uint16_t *object_id, + const char *label, uint16_t domains, + const yh_capabilities *capabilities, + yh_algorithm algorithm, bool compress, + const uint8_t *in, size_t in_len); + /** * Import an #YH_OPAQUE object into the device * diff --git a/src/cmdline.ggo b/src/cmdline.ggo index 63e41ccb..e920d8c6 100644 --- a/src/cmdline.ggo +++ b/src/cmdline.ggo @@ -97,6 +97,7 @@ option "attestation-id" - "Attestation ID" int optional option "log-index" - "Log index" int optional option "opt-name" - "Device option name" string optional option "opt-value" - "Device option value" string optional +option "compress" - "Compress a large certificate before import" flag off option "in" - "Input data (filename)" string optional default="-" option "out" - "Output data (filename)" string optional default="-" diff --git a/src/commands.c b/src/commands.c index bc16412e..898bec3f 100644 --- a/src/commands.c +++ b/src/commands.c @@ -917,9 +917,9 @@ int yh_com_get_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, const unsigned char *ptr = response; X509 *x509 = d2i_X509(NULL, &ptr, response_len); if (!x509) { - fprintf(stderr, "Failed parsing x509 information.\n"); + fprintf(stderr, "Failed parsing x509 information. Possibly compressed certificate\n"); #ifdef USE_CERT_COMPRESS - fprintf(stderr, "Trying to parse it as compressed certificate\n"); + fprintf(stdio, "Trying to parse it as compressed certificate\n"); uint8_t certdata[4096] = {0}; size_t certdata_len = sizeof(certdata); if(uncompress_data(response, response_len, certdata, &certdata_len) != 0) { @@ -2287,16 +2287,15 @@ int yh_com_put_authentication_asym(yubihsm_context *ctx, Argument *argv, // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm -// arg 6: i:datafile +// arg 6: b:compress +// arg 7: i:datafile int yh_com_put_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(fmt); - unsigned char buf[YH_MSG_BUF_SIZE], *data = argv[6].x; - size_t len = argv[6].len; - - X509 *cert = NULL; + unsigned char buf[YH_MSG_BUF_SIZE], *data = argv[7].x; + size_t len = argv[7].len; if (in_fmt == fmt_PEM) { // Decode X.509 Certificate regardless of algorithm in case fmt_PEM is @@ -2306,7 +2305,7 @@ int yh_com_put_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, fprintf(stderr, "Couldn't wrap PEM-encoded certificate data\n"); return 0; } - cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + X509 *cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); if (!cert) { fprintf(stderr, "Couldn't parse PEM-encoded certificate\n"); BIO_free(bio); @@ -2322,40 +2321,21 @@ int yh_com_put_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, data = buf; i2d_X509(cert, &data); data = buf; - } - - if (!cert && (argv[5].a == YH_ALGO_OPAQUE_X509_CERTIFICATE -#ifdef USE_CERT_COMPRESS - || argv[5].a == YH_ALGO_OPAQUE_X509_COMPRESSED -#endif - )) { + X509_free(cert); + } else if (argv[5].a == YH_ALGO_OPAQUE_X509_CERTIFICATE) { // Enforce valid X.509 certificate const unsigned char *p = data; - cert = d2i_X509(NULL, &p, len); + X509 *cert = d2i_X509(NULL, &p, len); if (!cert) { fprintf(stderr, "Couldn't parse DER-encoded certificate\n"); return 0; } + X509_free(cert); } -#ifdef USE_CERT_COMPRESS - if (cert && argv[5].a == YH_ALGO_OPAQUE_X509_COMPRESSED) { - - uint8_t compressed_data[YH_MSG_BUF_SIZE] = {0}; - size_t compressed_data_len = sizeof(compressed_data); - - if (compress_data(data, len, compressed_data, &compressed_data_len) != 0) { - fprintf(stderr, "Couldn't compress certificate\n"); - return 0; - } - memcpy(data, compressed_data, compressed_data_len); - len = compressed_data_len; - } -#endif - X509_free(cert); - - yh_rc yrc = yh_util_import_opaque(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, - &argv[4].c, argv[5].a, data, len); + yh_rc yrc = + yh_util_import_opaque_ex(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, + &argv[4].c, argv[5].a, argv[6].b, data, len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store opaque object: %s\n", yh_strerror(yrc)); return -1; diff --git a/src/main.c b/src/main.c index 06344780..30fdd653 100644 --- a/src/main.c +++ b/src/main.c @@ -483,11 +483,11 @@ static void create_command_list(CommandList *c) { fmt_PEM, fmt_nofmt, "Store an asymmetric authentication key", NULL, NULL}); - register_subcommand(*c, (Command){"opaque", yh_com_put_opaque, - "e:session,w:object_id,s:label,d:domains,c:" - "capabilities,a:algorithm,i:data=-", - fmt_binary, fmt_nofmt, - "Store an opaque object", NULL, NULL}); + register_subcommand( + *c, (Command){"opaque", yh_com_put_opaque, + "e:session,w:object_id,s:label,d:domains,c:" + "capabilities,a:algorithm,b:compress=0,i:data=-", + fmt_binary, fmt_nofmt, "Store an opaque object", NULL, NULL}); register_subcommand(*c, (Command){"option", yh_com_put_option, "e:session,o:option,i:data", fmt_hex, fmt_nofmt, @@ -2646,7 +2646,9 @@ int main(int argc, char *argv[]) { yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); - if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len, + arg[6].b = args_info.compress_given; + + if (get_input_data(args_info.in_arg, &arg[7].x, &arg[7].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n");