yubihsm-shell-2.7.3/0000755000175000017500000000000015167357340013301 5ustar aveenaveenyubihsm-shell-2.7.3/pkcs11/0000755000175000017500000000000015167357143014404 5ustar aveenaveenyubihsm-shell-2.7.3/pkcs11/debug_p11.c0000644000175000017500000000303115167357110016306 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "debug_p11.h" #include "yubihsm.h" int _YHP11_DBG = 0; int _YHP11_DINOUT = 0; FILE *_YHP11_OUTPUT = NULL; void yh_dbg_init(int dbg, int dinout, int libdbg, const char *debug_file) { if (_YHP11_OUTPUT != stderr && _YHP11_OUTPUT != stdout && _YHP11_OUTPUT != NULL) { fclose(_YHP11_OUTPUT); _YHP11_OUTPUT = stderr; } if (strcmp(debug_file, "stderr") == 0) { _YHP11_OUTPUT = stderr; } else if (strcmp(debug_file, "stdout") == 0) { _YHP11_OUTPUT = stdout; } else { FILE *file = fopen(debug_file, "ab"); if (file) { _YHP11_OUTPUT = file; } else { _YHP11_OUTPUT = stderr; } } yh_set_debug_output(NULL, _YHP11_OUTPUT); if (dbg || getenv("YUBIHSM_PKCS11_DBG")) { _YHP11_DBG = 1; } if (dinout || getenv("YUBIHSM_PKCS11_DINOUT")) { _YHP11_DINOUT = 1; } if (libdbg || getenv("YUBIHSM_LIB_DBG")) { yh_set_verbosity(NULL, YH_VERB_ALL); } } yubihsm-shell-2.7.3/pkcs11/debug_p11.h0000644000175000017500000000415515167357110016323 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef DEBUG_P11_H #define DEBUG_P11_H #include #include #include "../common/debug.h" extern int _YHP11_DBG; extern int _YHP11_DINOUT; extern FILE *_YHP11_OUTPUT; void yh_dbg_init(int dbg, int dinout, int libdbg, const char *debug_file); #define DBG_INFO(...) \ do { \ DLN(_YHP11_DBG, _YHP11_OUTPUT, ANSI_BLUE, "P11", "INF", __VA_ARGS__); \ } while (0) #define DBG_WARN(...) \ do { \ DLN(_YHP11_DBG, _YHP11_OUTPUT, ANSI_YELLOW, "P11", "WRN", __VA_ARGS__); \ } while (0) #define DBG_ERR(...) \ do { \ DLN(_YHP11_DBG, _YHP11_OUTPUT, ANSI_RED, "P11", "ERR", __VA_ARGS__); \ } while (0) #define DIN \ do { \ DLN(_YHP11_DINOUT, _YHP11_OUTPUT, ANSI_BLUE, "P11", "INF", ("In")); \ } while (0) #define DOUT \ do { \ DLN(_YHP11_DINOUT, _YHP11_OUTPUT, ANSI_BLUE, "P11", "INF", ("Out")); \ } while (0) #endif yubihsm-shell-2.7.3/pkcs11/cmdline.h0000644000175000017500000003334115167357143016174 0ustar aveenaveen/** @file cmdline.h * @brief The header file for the command line option parser * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten * @author GNU Gengetopt */ #ifndef CMDLINE_H #define CMDLINE_H /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* for FILE */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef CMDLINE_PARSER_PACKAGE /** @brief the program name (used for printing errors) */ #define CMDLINE_PARSER_PACKAGE PACKAGE #endif #ifndef CMDLINE_PARSER_PACKAGE_NAME /** @brief the complete program name (used for help and version) */ #ifdef PACKAGE_NAME #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE_NAME #else #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE #endif #endif #ifndef CMDLINE_PARSER_VERSION /** @brief the program version */ #define CMDLINE_PARSER_VERSION VERSION #endif /** @brief Where the command line options are stored */ struct gengetopt_args_info { const char *help_help; /**< @brief Print help and exit help description. */ const char *version_help; /**< @brief Print version and exit help description. */ char * config_file_arg; /**< @brief Configuration file to read (default='./yubihsm_pkcs11.conf'). */ char * config_file_orig; /**< @brief Configuration file to read original value given at command line. */ const char *config_file_help; /**< @brief Configuration file to read help description. */ char ** connector_arg; /**< @brief List of connectors to use. */ char ** connector_orig; /**< @brief List of connectors to use original value given at command line. */ unsigned int connector_min; /**< @brief List of connectors to use's minimum occurreces */ unsigned int connector_max; /**< @brief List of connectors to use's maximum occurreces */ const char *connector_help; /**< @brief List of connectors to use help description. */ int debug_flag; /**< @brief Enable pkcs11 debugging (default=off). */ const char *debug_help; /**< @brief Enable pkcs11 debugging help description. */ int dinout_flag; /**< @brief Enable pkcs11 function tracing (default=off). */ const char *dinout_help; /**< @brief Enable pkcs11 function tracing help description. */ int libdebug_flag; /**< @brief Enable libyubihsm debugging (default=off). */ const char *libdebug_help; /**< @brief Enable libyubihsm debugging help description. */ char * debug_file_arg; /**< @brief Output file for debugging (default='stderr'). */ char * debug_file_orig; /**< @brief Output file for debugging original value given at command line. */ const char *debug_file_help; /**< @brief Output file for debugging help description. */ char * cacert_arg; /**< @brief Cacert to use for HTTPS validation. */ char * cacert_orig; /**< @brief Cacert to use for HTTPS validation original value given at command line. */ const char *cacert_help; /**< @brief Cacert to use for HTTPS validation help description. */ char * cert_arg; /**< @brief HTTPS client certificate to authenticate with. */ char * cert_orig; /**< @brief HTTPS client certificate to authenticate with original value given at command line. */ const char *cert_help; /**< @brief HTTPS client certificate to authenticate with help description. */ char * key_arg; /**< @brief HTTPS client certificate key. */ char * key_orig; /**< @brief HTTPS client certificate key original value given at command line. */ const char *key_help; /**< @brief HTTPS client certificate key help description. */ char * proxy_arg; /**< @brief Proxy server to use for connector. */ char * proxy_orig; /**< @brief Proxy server to use for connector original value given at command line. */ const char *proxy_help; /**< @brief Proxy server to use for connector help description. */ char * noproxy_arg; /**< @brief Comma separated list of hosts ignore proxy for. */ char * noproxy_orig; /**< @brief Comma separated list of hosts ignore proxy for original value given at command line. */ const char *noproxy_help; /**< @brief Comma separated list of hosts ignore proxy for help description. */ int timeout_arg; /**< @brief Timeout to use for initial connection to connector (default='5'). */ char * timeout_orig; /**< @brief Timeout to use for initial connection to connector original value given at command line. */ const char *timeout_help; /**< @brief Timeout to use for initial connection to connector help description. */ char ** device_pubkey_arg; /**< @brief List of device public keys allowed for asymmetric authentication. */ char ** device_pubkey_orig; /**< @brief List of device public keys allowed for asymmetric authentication original value given at command line. */ unsigned int device_pubkey_min; /**< @brief List of device public keys allowed for asymmetric authentication's minimum occurreces */ unsigned int device_pubkey_max; /**< @brief List of device public keys allowed for asymmetric authentication's maximum occurreces */ const char *device_pubkey_help; /**< @brief List of device public keys allowed for asymmetric authentication help description. */ unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ unsigned int config_file_given ; /**< @brief Whether config-file was given. */ unsigned int connector_given ; /**< @brief Whether connector was given. */ unsigned int debug_given ; /**< @brief Whether debug was given. */ unsigned int dinout_given ; /**< @brief Whether dinout was given. */ unsigned int libdebug_given ; /**< @brief Whether libdebug was given. */ unsigned int debug_file_given ; /**< @brief Whether debug-file was given. */ unsigned int cacert_given ; /**< @brief Whether cacert was given. */ unsigned int cert_given ; /**< @brief Whether cert was given. */ unsigned int key_given ; /**< @brief Whether key was given. */ unsigned int proxy_given ; /**< @brief Whether proxy was given. */ unsigned int noproxy_given ; /**< @brief Whether noproxy was given. */ unsigned int timeout_given ; /**< @brief Whether timeout was given. */ unsigned int device_pubkey_given ; /**< @brief Whether device-pubkey was given. */ } ; /** @brief The additional parameters to pass to parser functions */ struct cmdline_parser_params { int override; /**< @brief whether to override possibly already present options (default 0) */ int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ int check_required; /**< @brief whether to check that all required options were provided (default 1) */ int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ } ; /** @brief the purpose string of the program */ extern const char *gengetopt_args_info_purpose; /** @brief the usage string of the program */ extern const char *gengetopt_args_info_usage; /** @brief the description string of the program */ extern const char *gengetopt_args_info_description; /** @brief all the lines making the help output */ extern const char *gengetopt_args_info_help[]; /** * The command line parser * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info); /** * The command line parser (version with additional parameters - deprecated) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_ext() instead */ int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required); /** * The command line parser (version with additional parameters) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params); /** * Save the contents of the option struct into an already open FILE stream. * @param outfile the stream where to dump options * @param args_info the option struct to dump * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info); /** * Save the contents of the option struct into a (text) file. * This file can be read by the config file parser (if generated by gengetopt) * @param filename the file where to save * @param args_info the option struct to save * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info); /** * Print the help */ void cmdline_parser_print_help(void); /** * Print the version */ void cmdline_parser_print_version(void); /** * Initializes all the fields a cmdline_parser_params structure * to their default values * @param params the structure to initialize */ void cmdline_parser_params_init(struct cmdline_parser_params *params); /** * Allocates dynamically a cmdline_parser_params structure and initializes * all its fields to their default values * @return the created and initialized cmdline_parser_params structure */ struct cmdline_parser_params *cmdline_parser_params_create(void); /** * Initializes the passed gengetopt_args_info structure's fields * (also set default values for options that have a default) * @param args_info the structure to initialize */ void cmdline_parser_init (struct gengetopt_args_info *args_info); /** * Deallocates the string fields of the gengetopt_args_info structure * (but does not deallocate the structure itself) * @param args_info the structure to deallocate */ void cmdline_parser_free (struct gengetopt_args_info *args_info); /** * The config file parser (deprecated version) * @param filename the name of the config file * @param args_info the structure where option information will be stored * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_config_file() instead */ int cmdline_parser_configfile (const char *filename, struct gengetopt_args_info *args_info, int override, int initialize, int check_required); /** * The config file parser * @param filename the name of the config file * @param args_info the structure where option information will be stored * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_config_file (const char *filename, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params); /** * The string parser (interprets the passed string as a command line) * @param cmdline the command line stirng * @param args_info the structure where option information will be stored * @param prog_name the name of the program that will be used to print * possible errors * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_string (const char *cmdline, struct gengetopt_args_info *args_info, const char *prog_name); /** * The string parser (version with additional parameters - deprecated) * @param cmdline the command line stirng * @param args_info the structure where option information will be stored * @param prog_name the name of the program that will be used to print * possible errors * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_string_ext() instead */ int cmdline_parser_string2 (const char *cmdline, struct gengetopt_args_info *args_info, const char *prog_name, int override, int initialize, int check_required); /** * The string parser (version with additional parameters) * @param cmdline the command line stirng * @param args_info the structure where option information will be stored * @param prog_name the name of the program that will be used to print * possible errors * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_string_ext (const char *cmdline, struct gengetopt_args_info *args_info, const char *prog_name, struct cmdline_parser_params *params); /** * Checks that all the required options were specified * @param args_info the structure to check * @param prog_name the name of the program that will be used to print * possible errors * @return */ int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* CMDLINE_H */ yubihsm-shell-2.7.3/pkcs11/util_pkcs11.h0000644000175000017500000002524415167357110016715 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef UTIL_PKCS11_H #define UTIL_PKCS11_H #include #include #include "yubihsm_pkcs11.h" CK_RV set_operation_part(yubihsm_pkcs11_op_info *op_info, yubihsm_pkcs11_part_type part); CK_RV get_mechanism_list(yubihsm_pkcs11_slot *slot, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR count); CK_RV get_mechanism_info(yubihsm_pkcs11_slot *slot, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo); void destroy_session(yubihsm_pkcs11_context *ctx, CK_SESSION_HANDLE hSession); yubihsm_pkcs11_object_desc *get_object_desc(yubihsm_pkcs11_slot *slot, CK_OBJECT_HANDLE objectHandle); yubihsm_pkcs11_object_desc *_get_object_desc(yubihsm_pkcs11_slot *slot, uint16_t id, uint8_t type, uint16_t sequence); CK_RV check_sign_mechanism(yubihsm_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism); CK_RV apply_sign_mechanism_init(yubihsm_pkcs11_op_info *op_info); CK_RV apply_sign_mechanism_update(yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR in, CK_ULONG in_len); CK_RV apply_sign_mechanism_finalize(yubihsm_pkcs11_op_info *op_info); CK_RV perform_signature(yh_session *session, yubihsm_pkcs11_op_info *op_info, uint8_t *signature, uint16_t *signature_len); void sign_mechanism_cleanup(yubihsm_pkcs11_op_info *op_info); CK_RV apply_verify_mechanism_init(yubihsm_pkcs11_op_info *op_info); CK_RV apply_verify_mechanism_update(yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR in, CK_ULONG in_len); CK_RV apply_verify_mechanism_finalize(yubihsm_pkcs11_op_info *op_info, CK_ULONG sig_len); CK_RV perform_verify(yh_session *session, yubihsm_pkcs11_op_info *op_info, uint8_t *signature, uint16_t signature_len); void verify_mechanism_cleanup(yubihsm_pkcs11_op_info *op_info); CK_RV check_decrypt_mechanism(yubihsm_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism); CK_RV apply_decrypt_mechanism_init(yubihsm_pkcs11_op_info *op_info); CK_RV apply_decrypt_mechanism_update(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen); CK_RV apply_decrypt_mechanism_finalize(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); void decrypt_mechanism_cleanup(yubihsm_pkcs11_op_info *op_info); CK_RV apply_encrypt_mechanism_init(yubihsm_pkcs11_session *session, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV apply_encrypt_mechanism_finalize(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen); CK_RV perform_wrap_encrypt(yh_session *session, yubihsm_pkcs11_op_info *op_info, uint8_t *plaintext, uint16_t *plaintext_len); CK_RV perform_rsa_encrypt(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR data, CK_ULONG data_len, CK_BYTE_PTR enc, CK_ULONG_PTR enc_len); CK_RV check_digest_mechanism(CK_MECHANISM_PTR pMechanism); CK_RV apply_digest_mechanism_init(yubihsm_pkcs11_op_info *op_info); CK_RV apply_digest_mechanism_update(yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR in, CK_ULONG in_len); CK_RV apply_digest_mechanism_finalize(yubihsm_pkcs11_op_info *op_info); CK_RV perform_digest(yubihsm_pkcs11_op_info *op_info, uint8_t *digest, uint16_t *digest_len); void digest_mechanism_cleanup(yubihsm_pkcs11_op_info *op_info); CK_ULONG get_digest_bytelength(CK_MECHANISM_TYPE m); CK_RV check_wrap_mechanism(yubihsm_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism); bool is_RSA_sign_mechanism(CK_MECHANISM_TYPE m); bool is_RSA_decrypt_mechanism(CK_MECHANISM_TYPE m); bool is_hashed_mechanism(CK_MECHANISM_TYPE m); bool is_PKCS1v1_5_sign_mechanism(CK_MECHANISM_TYPE m); bool is_ECDSA_sign_mechanism(CK_MECHANISM_TYPE m); bool is_EDDSA_sign_mechanism(CK_MECHANISM_TYPE m); bool is_PSS_sign_mechanism(CK_MECHANISM_TYPE m); bool is_HMAC_sign_mechanism(CK_MECHANISM_TYPE m); void set_native_locking(yubihsm_pkcs11_context *ctx); CK_RV add_connectors(yubihsm_pkcs11_context *ctx, int n_connectors, char **connector_names, yh_connector **connectors); bool delete_session(yubihsm_pkcs11_context *ctx, CK_SESSION_HANDLE_PTR phSession); CK_RV get_session(yubihsm_pkcs11_context *ctx, CK_SESSION_HANDLE hSession, yubihsm_pkcs11_session **session, int session_state); yubihsm_pkcs11_slot *get_slot(yubihsm_pkcs11_context *ctx, CK_ULONG id); void release_slot(yubihsm_pkcs11_context *ctx, yubihsm_pkcs11_slot *slot); bool create_session(yubihsm_pkcs11_slot *slot, CK_FLAGS flags, CK_SESSION_HANDLE_PTR phSession); void release_session(yubihsm_pkcs11_context *ctx, yubihsm_pkcs11_session *session); CK_RV set_object_type(uint8_t *type, uint8_t expected_type); CK_RV set_template_attribute(yubihsm_pkcs11_attribute *attribute, CK_BBOOL *value); CK_RV parse_rsa_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template); CK_RV parse_ec_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template); CK_RV parse_ed_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template); CK_RV parse_hmac_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template, bool generate); CK_RV parse_wrap_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template, yh_algorithm algorithm, bool generate); CK_RV parse_rsa_wrappedkey_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta, CK_BYTE *type); CK_RV parse_aes_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template, bool generate); CK_RV parse_rsa_generate_template(CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta); CK_RV parse_ec_generate_template(CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta); CK_RV parse_ed_generate_template(CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta); uint16_t parse_id_value(void *value, CK_ULONG len); CK_RV populate_template(int type, void *object, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_session *session); CK_RV validate_derive_key_attribute(CK_ATTRIBUTE_TYPE type, void *value); CK_RV check_bool_attribute(CK_BBOOL *value, bool check); CK_RV yrc_to_rv(yh_rc rc); CK_RV populate_cache_with_data_opaques(yubihsm_pkcs11_slot *slot); CK_RV write_meta_object(yubihsm_pkcs11_slot *slot, pkcs11_meta_object *meta_object, yh_capabilities *target_capabilities, uint16_t target_domains, bool replace); yubihsm_pkcs11_object_desc * find_meta_object_by_target(yubihsm_pkcs11_slot *slot, uint16_t target_id, uint8_t target_type, uint8_t target_sequence, uint16_t target_domains); bool match_meta_attributes(yubihsm_pkcs11_session *session, yh_object_descriptor *object, uint8_t *cka_id, uint16_t cka_id_len, uint8_t *cka_label, uint16_t cka_label_len); bool is_meta_object(yh_object_descriptor *object); CK_RV parse_meta_id_template(yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta, bool public, uint8_t *value, size_t value_len); CK_RV parse_meta_label_template(yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta, bool public, uint8_t *value, size_t value_len); bool match_byte_array(uint8_t *a, uint16_t a_len, uint8_t *b, uint16_t b_len); CK_RV ecdh_with_kdf(ecdh_session_key *shared_secret, uint8_t *fixed_info, size_t fixed_len, CK_ULONG kdf, size_t value_len); #endif yubihsm-shell-2.7.3/pkcs11/list.c0000644000175000017500000000737315167357110015527 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "list.h" #include #include #include "../common/insecure_memzero.h" void list_create(List *list, int item_size, FreeItemFn free_item_fn) { list->length = 0; list->item_size = item_size; list->head = NULL; list->tail = NULL; list->free_item_fn = free_item_fn; } void list_destroy(List *list) { ListItem *current; while (list->head != NULL) { current = list->head; list->head = current->next; if (list->free_item_fn) { list->free_item_fn(current->data); } insecure_memzero(current->data, list->item_size); free(current->data); free(current); } list->length = 0; list->item_size = 0; list->head = NULL; list->tail = NULL; list->free_item_fn = NULL; } bool list_prepend(List *list, void *item) { ListItem *node = calloc(1, sizeof(ListItem)); if (node == NULL) { return false; } node->data = calloc(1, list->item_size); if (node->data == NULL) { free(node); return false; } memcpy(node->data, item, list->item_size); node->next = list->head; list->head = node; if (list->tail == NULL) { list->tail = list->head; } list->length++; return true; } bool list_append(List *list, void *item) { ListItem *node = calloc(1, sizeof(ListItem)); if (node == NULL) { return false; } node->data = calloc(1, list->item_size); if (node->data == NULL) { free(node); return false; } memcpy(node->data, item, list->item_size); if (list->length == 0) { list->head = node; list->tail = node; } else { list->tail->next = node; list->tail = node; } list->length++; return true; } ListItem *list_get(List *list, void *data, CompareItemFn compare_item_fn) { for (ListItem *item = list->head; item != NULL; item = item->next) { if (compare_item_fn(data, item->data) == true) { return item; } } return NULL; } void list_delete(List *list, ListItem *item) { if (item == NULL) { return; } if (item == list->head) { if (list->head == list->tail) { list->head = NULL; list->tail = NULL; } else { list->head = list->head->next; } if (list->free_item_fn) { list->free_item_fn(item->data); } insecure_memzero(item->data, list->item_size); free(item->data); free(item); } else if (item == list->tail) { for (ListItem *i = list->head; i != NULL; i = i->next) { if (i->next == list->tail) { list->tail = i; i->next = NULL; if (list->free_item_fn) { list->free_item_fn(item->data); } insecure_memzero(item->data, list->item_size); free(item->data); free(item); } } } else { if (list->free_item_fn) { list->free_item_fn(item->data); } ListItem *tmp = item->next; insecure_memzero(item->data, list->item_size); free(item->data); item->data = item->next->data; item->next = item->next->next; if (tmp == list->tail) { list->tail = item; } free(tmp); } list->length--; } void list_iterate(List *list, IteratorFn iterator_fn) { for (ListItem *item = list->head; item != NULL; item = item->next) { iterator_fn(item->data); } } yubihsm-shell-2.7.3/pkcs11/fuzz/0000755000175000017500000000000015167357110015374 5ustar aveenaveenyubihsm-shell-2.7.3/pkcs11/fuzz/fuzz_get_attribute_value.cc0000644000175000017500000001465515167357110023032 0ustar aveenaveen#include #include #include #include "fuzzer/FuzzedDataProvider.h" #include #include #include #include "yubihsm_fuzz.h" extern "C" { #include "pkcs11y.h" #include "yubihsm_pkcs11.h" uint8_t *backend_data; size_t backend_data_len; } yh_connector *connector; CK_FUNCTION_LIST_PTR p11; CK_SESSION_HANDLE session; CK_OBJECT_HANDLE yh_pubkey, yh_privkey; #define ECDH_ATTRIBUTE_COUNT 2 static bool init_p11() { CK_C_INITIALIZE_ARGS initArgs; CK_RV rv; char config[] = "connector=yhfuzz://yubihsm_fuzz"; // char config[] = "connector=yhfuzz://yubihsm_fuzz debug libdebug"; C_GetFunctionList(&p11); memset(&initArgs, 0, sizeof(initArgs)); initArgs.pReserved = config; rv = p11->C_Initialize(&initArgs); assert(rv == CKR_OK); return true; } static void deinit_session() { CK_RV rv; rv = p11->C_Logout(session); rv = p11->C_CloseSession(session); } static void init_session() { CK_RV rv; char pin[20] = "0000"; strcat(pin, FUZZ_BACKEND_PASSWORD); memset(&session, 0, sizeof(session)); rv = p11->C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session); assert(rv == CKR_OK); rv = p11->C_Login(session, CKU_USER, (CK_UTF8CHAR_PTR) pin, (CK_ULONG) strlen(pin)); assert(rv == CKR_OK); // rv = generate_ecdh_keypair(); // assert(rv == CKR_OK); }; static EVP_PKEY *generate_keypair_openssl() { EVP_PKEY *pkey = NULL; EC_KEY *eckey = NULL; OpenSSL_add_all_algorithms(); int eccgrp = OBJ_txt2nid("secp224r1"); eckey = EC_KEY_new_by_curve_name(eccgrp); if (!(EC_KEY_generate_key(eckey))) { } else { pkey = EVP_PKEY_new(); if (!EVP_PKEY_assign_EC_KEY(pkey, eckey)) { } } return pkey; } void populate_attribute_template(CK_ATTRIBUTE_PTR *attribute_array, CK_ULONG attribute_count, FuzzedDataProvider *fdp) { CK_ATTRIBUTE_PTR new_array = new CK_ATTRIBUTE[attribute_count]; memset(new_array, 0, sizeof(CK_ATTRIBUTE) * attribute_count); for (int i = 0; i < attribute_count; i++) { uint8_t ulValueLen = fdp->ConsumeIntegral(); new_array[i].type = fdp->ConsumeIntegral(); new_array[i].pValue = new uint8_t[ulValueLen]; new_array[i].ulValueLen = ulValueLen; } *attribute_array = new_array; } void populate_derived_ecdh_key_template(CK_ATTRIBUTE_PTR *attribute_array, FuzzedDataProvider *fdp) { CK_ATTRIBUTE_PTR new_array = new CK_ATTRIBUTE[ECDH_ATTRIBUTE_COUNT]; memset(new_array, 0, sizeof(CK_ATTRIBUTE) * ECDH_ATTRIBUTE_COUNT); uint8_t value_len = fdp->ConsumeIntegral(); std::vector value = fdp->ConsumeBytes(value_len); new_array[0].type = CKA_VALUE_LEN; new_array[0].ulValueLen = value_len; new_array[0].pValue = new uint8_t[value_len]; memset(new_array[0].pValue, 0, value_len); memcpy(new_array[0].pValue, &value[0], std::min(value.size(), (size_t) value_len)); uint8_t label_len = fdp->ConsumeIntegral(); new_array[1].type = CKA_LABEL; new_array[1].ulValueLen = label_len; new_array[1].pValue = new uint8_t[label_len]; *attribute_array = new_array; } void derive_ecdh_session_keys(uint8_t derived_key_count, CK_ATTRIBUTE_PTR ecdh_attribute_array) { if (derived_key_count > 10) { // artificial limitation on the number of derived keys derived_key_count = 10; } for (int i = 0; i < derived_key_count; i++) { CK_OBJECT_HANDLE ecdh = {0}; CK_ECDH1_DERIVE_PARAMS params = {0}; params.kdf = CKD_NULL; params.pSharedData = NULL; params.ulSharedDataLen = 0; // TODO populate pPublicData and ulPublicDataLen from fuzzer generated data? params.pPublicData = new uint8_t[50]; memset(params.pPublicData, 0, 50); params.ulPublicDataLen = 50; CK_MECHANISM mechanism = {0}; mechanism.mechanism = CKM_ECDH1_DERIVE; mechanism.pParameter = (void *) ¶ms; mechanism.ulParameterLen = sizeof(params); p11->C_DeriveKey(session, &mechanism, yh_privkey, ecdh_attribute_array, ECDH_ATTRIBUTE_COUNT, &ecdh); delete[] params.pPublicData; } } void free_attribute_template(CK_ATTRIBUTE_PTR attribute_array, CK_ULONG attribute_count) { for (unsigned int i = 0; i < attribute_count; i++) { if (attribute_array[i].pValue != NULL) { delete[] (uint8_t *) attribute_array[i].pValue; } } delete[] attribute_array; } extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { typedef struct { CK_ULONG attribute_count; CK_OBJECT_HANDLE obj_handle; uint8_t derived_ecdh_key_count; } test_case_t; static bool p11_initialized = init_p11(); if (size < sizeof(test_case_t)) { return 0; } FuzzedDataProvider *fdp = new FuzzedDataProvider(data, size); test_case_t test_case = {0}; test_case.attribute_count = fdp->ConsumeIntegral(); test_case.obj_handle = fdp->ConsumeIntegral(); test_case.derived_ecdh_key_count = fdp->ConsumeIntegral(); /* limit the number of request attributes to 10 * this is an artificial limitation to make fuzzer iterations faster */ if (test_case.attribute_count > 10) { test_case.attribute_count = 10; } CK_ATTRIBUTE_PTR attribute_array = NULL; CK_ATTRIBUTE_PTR ecdh_attribute_array = NULL; populate_attribute_template(&attribute_array, test_case.attribute_count, fdp); populate_derived_ecdh_key_template(&ecdh_attribute_array, fdp); // the rest of the data is used for responses sent back by the backend std::vector backend_vector = fdp->ConsumeRemainingBytes(); backend_data = &backend_vector[0]; backend_data_len = backend_vector.size(); init_session(); /* objects of type ECDH_KEY_TYPE are treated differently by the * C_GetAttributeValue logic in order to improve coverage, we derive several * ECDH keys using C_DeriveKey */ derive_ecdh_session_keys(test_case.derived_ecdh_key_count, ecdh_attribute_array); p11->C_GetAttributeValue(session, test_case.obj_handle, attribute_array, test_case.attribute_count); deinit_session(); free_attribute_template(attribute_array, test_case.attribute_count); free_attribute_template(ecdh_attribute_array, ECDH_ATTRIBUTE_COUNT); delete fdp; fflush(stdout); return 0; } yubihsm-shell-2.7.3/pkcs11/yubihsm_pkcs11.c0000644000175000017500000061047415167357110017420 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include "debug_p11.h" #include "util_pkcs11.h" #include "yubihsm_pkcs11.h" #include "../common/insecure_memzero.h" #include "../common/parsing.h" #include "../common/util.h" #ifdef __WIN32 #include #else #include #endif #ifdef _MSVC #define strtok_r strtok_s #endif #define YUBIHSM_PKCS11_MANUFACTURER "Yubico (www.yubico.com)" #define YUBIHSM_PKCS11_LIBDESC "YubiHSM PKCS#11 Library" #define YUBIHSM_PKCS11_MIN_PIN_LEN 8 #define YUBIHSM_PKCS11_MAX_PIN_LEN 64 #define UNUSED(x) (void) (x) // TODO(adma): also in yubihsm-shell.h #define GLOBAL_LOCK_OR_RETURN \ do { \ if (g_ctx.mutex != NULL) { \ CK_RV lock_rv = g_ctx.lock_mutex(g_ctx.mutex); \ if (lock_rv != CKR_OK) { \ DBG_ERR("Unable to acquire global lock"); \ return lock_rv; \ } \ } \ } while (0) #define GLOBAL_UNLOCK_OR_RETURN \ do { \ if (g_ctx.mutex != NULL) { \ CK_RV lock_rv = g_ctx.unlock_mutex(g_ctx.mutex); \ if (lock_rv != CKR_OK) { \ DBG_ERR("Unable to release global lock"); \ return lock_rv; \ } \ } \ } while (0) static const CK_FUNCTION_LIST function_list; static const CK_FUNCTION_LIST_3_0 function_list_3; static const CK_INTERFACE interfaces_list[] = {{(CK_CHAR_PTR) "PKCS 11", (CK_VOID_PTR) &function_list_3, 0}, {(CK_CHAR_PTR) "PKCS 11", (CK_VOID_PTR) &function_list, 0}}; static bool g_yh_initialized = false; static yubihsm_pkcs11_context g_ctx; static void destroy_slot_mutex(void *data) { yubihsm_pkcs11_slot *slot = (yubihsm_pkcs11_slot *) data; if (slot->mutex != NULL) { g_ctx.destroy_mutex(slot->mutex); } slot->mutex = NULL; } static bool compare_ecdh_keys(void *data, void *item) { if (data == NULL || item == NULL) { return false; } CK_OBJECT_HANDLE *a = data; ListItem *itm = (ListItem *) item; ecdh_session_key *key = (ecdh_session_key *) &itm->data; CK_OBJECT_HANDLE b = key->id; return *a == b; } /* General Purpose */ CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) { DIN; if (g_yh_initialized == true) { return CKR_CRYPTOKI_ALREADY_INITIALIZED; } CK_C_INITIALIZE_ARGS_PTR init_args = pInitArgs; yh_dbg_init(false, false, 0, "stderr"); if (pInitArgs != NULL) { if ((init_args->flags & CKF_OS_LOCKING_OK) == 0 && init_args->CreateMutex == NULL && init_args->DestroyMutex == NULL && init_args->LockMutex == NULL && init_args->UnlockMutex == NULL) { // NOTE(adma): no threading required // all is good, do nothing g_ctx.create_mutex = NULL; g_ctx.destroy_mutex = NULL; g_ctx.lock_mutex = NULL; g_ctx.unlock_mutex = NULL; } else if ((init_args->flags & CKF_OS_LOCKING_OK) != 0 && init_args->CreateMutex == NULL && init_args->DestroyMutex == NULL && init_args->LockMutex == NULL && init_args->UnlockMutex == NULL) { // NOTE(adma): threading with native OS locks set_native_locking(&g_ctx); } else if ((init_args->flags & CKF_OS_LOCKING_OK) == 0 && init_args->CreateMutex != NULL && init_args->DestroyMutex != NULL && init_args->LockMutex != NULL && init_args->UnlockMutex != NULL) { // NOTE(adma): threading with supplied functions g_ctx.create_mutex = init_args->CreateMutex; g_ctx.destroy_mutex = init_args->DestroyMutex; g_ctx.lock_mutex = init_args->LockMutex; g_ctx.unlock_mutex = init_args->UnlockMutex; } else if ((init_args->flags & CKF_OS_LOCKING_OK) != 0 && init_args->CreateMutex != NULL && init_args->DestroyMutex != NULL && init_args->LockMutex != NULL && init_args->UnlockMutex != NULL) { // NOTE(adma): threading with native or supplied functions g_ctx.create_mutex = init_args->CreateMutex; g_ctx.destroy_mutex = init_args->DestroyMutex; g_ctx.lock_mutex = init_args->LockMutex; g_ctx.unlock_mutex = init_args->UnlockMutex; } else { DBG_ERR("Invalid locking specified"); return CKR_ARGUMENTS_BAD; } } CK_RV rv = CKR_OK; if (g_ctx.create_mutex != NULL) { rv = g_ctx.create_mutex(&g_ctx.mutex); if (rv != CKR_OK) { DBG_ERR("Unable to create global mutex"); return rv; } } else { g_ctx.mutex = NULL; } struct cmdline_parser_params params = {0}; struct gengetopt_args_info args_info = {0}; cmdline_parser_params_init(¶ms); params.initialize = 1; params.check_required = 1; char *tmp = ""; if (cmdline_parser(0, &tmp, &args_info) != 0) { DBG_ERR("Unable to initialize ggo structure"); return CKR_GENERAL_ERROR; } params.initialize = 0; params.override = 1; char *args = NULL; char *args_parsed = NULL; yh_connector **connector_list = NULL; if (init_args != NULL && init_args->pReserved != NULL) { args = strdup(init_args->pReserved); if (args == NULL) { DBG_ERR("Failed copying reserved string"); return CKR_HOST_MEMORY; } char *str = args; char *save = NULL; char *part; while ((part = strtok_r(str, " \r\n\t", &save))) { str = NULL; size_t len = args_parsed ? strlen(args_parsed) : 0; char *new_args = realloc(args_parsed, len + strlen(part) + 4); if (new_args) { args_parsed = new_args; snprintf(args_parsed + len, strlen(part) + 4, "--%s ", part); } else { DBG_ERR("Failed allocating memory for args"); rv = CKR_HOST_MEMORY; goto c_i_failure; } } DBG_INFO("Now parsing supplied init args as '%s'", args_parsed); if (cmdline_parser_string_ext(args_parsed, &args_info, "yubihsm_pkcs11 module", ¶ms) != 0) { DBG_ERR("Parsing of the reserved init args '%s' failed", args); rv = CKR_GENERAL_ERROR; goto c_i_failure; } free(args); args = NULL; free(args_parsed); args_parsed = NULL; } // NOTE(thorduri): #TOCTOU char *config_file = args_info.config_file_arg; struct stat sb = {0}; if (stat(config_file, &sb) == -1) { config_file = getenv("YUBIHSM_PKCS11_CONF"); } params.override = 0; if (config_file != NULL && cmdline_parser_config_file(config_file, &args_info, ¶ms) != 0) { DBG_ERR("Unable to parse configuration file"); rv = CKR_GENERAL_ERROR; goto c_i_failure; } yh_dbg_init(args_info.debug_flag, args_info.dinout_flag, args_info.libdebug_flag, args_info.debug_file_arg); // NOTE(adma): it's better to set the argument optional and check its presence // here if (args_info.connector_given == 0) { DBG_ERR("No connector defined"); rv = CKR_ARGUMENTS_BAD; goto c_i_failure; } yh_rc yrc = yh_init(); if (yrc != YHR_SUCCESS) { DBG_ERR("Unable to initialize libyubihsm: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_i_failure; } DBG_INFO("Found %u configured connector(s)", args_info.connector_given); connector_list = calloc(args_info.connector_given, sizeof(yh_connector *)); if (connector_list == NULL) { DBG_ERR("Failed allocating memory"); rv = CKR_HOST_MEMORY; goto c_i_failure; } size_t n_connectors = 0; for (unsigned int i = 0; i < args_info.connector_given; i++) { yrc = yh_init_connector(args_info.connector_arg[i], &connector_list[i]); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to init connector: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_i_failure; } if (args_info.cacert_given) { yrc = yh_set_connector_option(connector_list[i], YH_CONNECTOR_HTTPS_CA, args_info.cacert_arg); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to set HTTPS CA option: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_i_failure; } } if (args_info.cert_given) { yrc = yh_set_connector_option(connector_list[i], YH_CONNECTOR_HTTPS_CERT, args_info.cert_arg); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to set HTTPS cert option: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_i_failure; } } if (args_info.key_given) { yrc = yh_set_connector_option(connector_list[i], YH_CONNECTOR_HTTPS_KEY, args_info.key_arg); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to set HTTPS key option: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_i_failure; } } if (args_info.proxy_given) { yrc = yh_set_connector_option(connector_list[i], YH_CONNECTOR_PROXY_SERVER, args_info.proxy_arg); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to set proxy server option: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_i_failure; } } if (args_info.noproxy_given) { yrc = yh_set_connector_option(connector_list[i], YH_CONNECTOR_NOPROXY, args_info.noproxy_arg); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to set noproxy option: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_i_failure; } } yrc = yh_connect(connector_list[i], args_info.timeout_arg); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to connect to '%s': %s", args_info.connector_arg[i], yh_strerror(yrc)); continue; } else { n_connectors++; } } rv = add_connectors(&g_ctx, args_info.connector_given, args_info.connector_arg, connector_list); if (rv != CKR_OK) { DBG_ERR("Failed building connectors list"); goto c_i_failure; } list_create(&g_ctx.device_pubkeys, YH_EC_P256_PUBKEY_LEN, NULL); for (unsigned int i = 0; i < args_info.device_pubkey_given; i++) { uint8_t pk[80] = {0}; size_t pk_len = sizeof(pk); if (hex_decode(args_info.device_pubkey_arg[i], pk, &pk_len) == false || pk_len != YH_EC_P256_PUBKEY_LEN) { DBG_ERR("Invalid device public key configured"); rv = CKR_ARGUMENTS_BAD; goto c_i_failure; } list_append(&g_ctx.device_pubkeys, pk); } cmdline_parser_free(&args_info); free(connector_list); DBG_INFO("Found %zu usable connector(s)", n_connectors); DBG_INFO("Found %d configured device public key(s)", g_ctx.device_pubkeys.length); g_yh_initialized = true; DOUT; return CKR_OK; c_i_failure: free(args_parsed); free(args); list_iterate(&g_ctx.slots, destroy_slot_mutex); list_destroy(&g_ctx.slots); list_destroy(&g_ctx.device_pubkeys); if (connector_list) { for (unsigned int i = 0; i < args_info.connector_given; i++) { yh_disconnect(connector_list[i]); } } cmdline_parser_free(&args_info); free(connector_list); if (g_ctx.mutex != NULL) { g_ctx.destroy_mutex(g_ctx.mutex); g_ctx.mutex = NULL; } DOUT; return rv; } CK_DEFINE_FUNCTION(CK_RV, C_Finalize)(CK_VOID_PTR pReserved) { DIN; if (pReserved != NULL) { DBG_ERR("Finalized called with pReserved != NULL"); return CKR_ARGUMENTS_BAD; } if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } list_iterate(&g_ctx.slots, destroy_slot_mutex); list_destroy(&g_ctx.slots); list_destroy(&g_ctx.device_pubkeys); if (g_ctx.mutex != NULL) { g_ctx.destroy_mutex(g_ctx.mutex); g_ctx.mutex = NULL; } g_yh_initialized = false; yh_exit(); DOUT; if (_YHP11_OUTPUT != stdout && _YHP11_OUTPUT != stderr && _YHP11_OUTPUT != NULL) { fclose(_YHP11_OUTPUT); _YHP11_OUTPUT = stderr; } return CKR_OK; } static CK_RV C_GetInfo_Ex(CK_INFO_PTR pInfo, CK_VERSION cryptokiVersion) { if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pInfo == NULL) { return CKR_ARGUMENTS_BAD; } pInfo->cryptokiVersion = cryptokiVersion; memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); memcpy((char *) pInfo->manufacturerID, YUBIHSM_PKCS11_MANUFACTURER, strlen(YUBIHSM_PKCS11_MANUFACTURER)); pInfo->flags = 0; memset(pInfo->libraryDescription, ' ', sizeof(pInfo->libraryDescription)); memcpy((char *) pInfo->libraryDescription, YUBIHSM_PKCS11_LIBDESC, strlen(YUBIHSM_PKCS11_LIBDESC)); CK_VERSION libraryVersion = {VERSION_MAJOR, (VERSION_MINOR * 10) + VERSION_PATCH}; pInfo->libraryVersion = libraryVersion; return CKR_OK; } CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)(CK_INFO_PTR pInfo) { DIN; CK_RV rv = C_GetInfo_Ex(pInfo, function_list.version); DOUT; return rv; } static CK_RV C_GetInfo_3_0(CK_INFO_PTR pInfo) { DIN; CK_RV rv = C_GetInfo_Ex(pInfo, function_list_3.version); DOUT; return rv; } CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionList) (CK_FUNCTION_LIST_PTR_PTR ppFunctionList) { yh_dbg_init(false, false, 0, "stderr"); DIN; if (ppFunctionList == NULL) { DBG_ERR("GetFunctionList called with ppFunctionList = NULL"); return CKR_ARGUMENTS_BAD; } *ppFunctionList = (CK_FUNCTION_LIST_PTR) &function_list; DOUT; return CKR_OK; } /* Slot and token management */ CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList) (CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (!pulCount) { DBG_ERR("pulCount argument bad"); return CKR_ARGUMENTS_BAD; } GLOBAL_LOCK_OR_RETURN; if (pSlotList == NULL) { *pulCount = 0; // NOTE(adma) just return the number of slots if (tokenPresent == CK_TRUE) { for (ListItem *item = g_ctx.slots.head; item != NULL; item = item->next) { yubihsm_pkcs11_slot *slot = (yubihsm_pkcs11_slot *) item->data; if (yh_connector_has_device(slot->connector) == true) { *pulCount += 1; } } DBG_INFO("Number of slots with a token is %lu", *pulCount); } else { *pulCount = g_ctx.slots.length; DBG_INFO("Total number of slots is %lu", *pulCount); } // NOTE(adma): actually return the slot IDs DBG_INFO("Can return %lu slot(s)", *pulCount); GLOBAL_UNLOCK_OR_RETURN; DOUT; return CKR_OK; } uint16_t j = 0; bool full = false; bool overflow = false; for (ListItem *item = g_ctx.slots.head; item != NULL; item = item->next) { if (j == *pulCount) { full = true; } yubihsm_pkcs11_slot *slot = (yubihsm_pkcs11_slot *) item->data; if (tokenPresent == CK_TRUE) { if (yh_connector_has_device(slot->connector) != true) { continue; } } if (full == false) { pSlotList[j] = slot->id; DBG_INFO("Returning slot %lu", pSlotList[j]); } else { overflow = true; } j += 1; } *pulCount = j; if (overflow == true) { GLOBAL_UNLOCK_OR_RETURN; return CKR_BUFFER_TOO_SMALL; } GLOBAL_UNLOCK_OR_RETURN; DOUT; return CKR_OK; } CK_DEFINE_FUNCTION(CK_RV, C_GetSlotInfo) (CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (!pInfo) { DBG_ERR("Invalid pInfo"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_slot *slot = get_slot(&g_ctx, slotID); if (slot == NULL) { DBG_ERR("Invalid slot ID %lu", slotID); return CKR_SLOT_ID_INVALID; } char *s = "YubiHSM Connector "; size_t l = strlen(s); memset(pInfo->slotDescription, ' ', sizeof(pInfo->slotDescription)); memcpy((char *) pInfo->slotDescription, s, l); yh_get_connector_address(slot->connector, &s); memcpy((char *) pInfo->slotDescription + l, s, strlen(s)); s = "Yubico"; l = strlen(s); memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); memcpy((char *) pInfo->manufacturerID, s, l); pInfo->flags = CKF_REMOVABLE_DEVICE | CKF_HW_SLOT; if (yh_connector_has_device(slot->connector) == true) { pInfo->flags |= CKF_TOKEN_PRESENT; } uint8_t major = 0; uint8_t minor = 0; uint8_t patch = 0; yh_get_connector_version(slot->connector, &major, &minor, &patch); pInfo->hardwareVersion.major = major; pInfo->hardwareVersion.minor = (minor * 10) + patch; pInfo->firmwareVersion.major = major; pInfo->firmwareVersion.minor = (minor * 10) + patch; release_slot(&g_ctx, slot); DOUT; return CKR_OK; } CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo) (CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (!pInfo) { DBG_ERR("Invalid pInfo"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_slot *slot = get_slot(&g_ctx, slotID); if (slot == NULL) { DBG_ERR("Invalid slot ID %lu", slotID); return CKR_SLOT_ID_INVALID; } CK_RV rv = CKR_OK; if (yh_connector_has_device(slot->connector) == false) { DBG_ERR("Slot %lu has no token inserted", slotID); rv = CKR_TOKEN_NOT_PRESENT; goto c_gt_out; } char *s = "YubiHSM"; size_t l = strlen(s); memset(pInfo->label, ' ', sizeof(pInfo->label)); memcpy((char *) pInfo->label, s, l); s = YUBIHSM_PKCS11_MANUFACTURER; l = strlen(s); memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); memcpy((char *) pInfo->manufacturerID, s, l); s = "YubiHSM"; l = strlen(s); memset(pInfo->model, ' ', sizeof(pInfo->model)); memcpy((char *) pInfo->model, s, l); memset(pInfo->serialNumber, ' ', sizeof(pInfo->serialNumber)); l = snprintf((char *) pInfo->serialNumber, sizeof(pInfo->serialNumber), "%08u", slot->connector->device_info.serial); pInfo->serialNumber[l] = ' '; pInfo->flags = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED; pInfo->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE; // maximum number of sessions that can be opened // with the token at one time by a single // application pInfo->ulSessionCount = CK_UNAVAILABLE_INFORMATION; // number of sessions that this application // currently has open with the token pInfo->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE; // maximum number of read/write sessions that can // be opened with the token at one time by a single // application pInfo->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION; // number of read/write sessions that this // application currently has open with the token pInfo->ulMaxPinLen = YUBIHSM_PKCS11_MAX_PIN_LEN; // maximum length in bytes of the PIN pInfo->ulMinPinLen = YUBIHSM_PKCS11_MIN_PIN_LEN; // minimum length in bytes of the PIN pInfo->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION; pInfo->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION; pInfo->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION; pInfo->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION; CK_VERSION ver = {slot->connector->device_info.major, (slot->connector->device_info.minor * 10) + slot->connector->device_info.patch}; pInfo->hardwareVersion = ver; pInfo->firmwareVersion = ver; memset(pInfo->utcTime, ' ', sizeof(pInfo->utcTime)); DOUT; c_gt_out: release_slot(&g_ctx, slot); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_WaitForSlotEvent) (CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) { DIN; UNUSED(flags); UNUSED(pSlot); UNUSED(pReserved); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismList) (CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pulCount == NULL) { DBG_ERR("Wrong/missing parameter"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_slot *slot = get_slot(&g_ctx, slotID); if (slot == NULL) { DBG_ERR("Invalid slot ID %lu", slotID); return CKR_SLOT_ID_INVALID; } CK_RV rv = get_mechanism_list(slot, pMechanismList, pulCount); if (rv != CKR_OK) { DBG_ERR("Failed getting device info"); goto c_gml_out; } DBG_INFO("Found %lu mechanisms", *pulCount); DOUT; c_gml_out: release_slot(&g_ctx, slot); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismInfo) (CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pInfo == NULL) { DBG_ERR("Wrong/missing parameter"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_slot *slot = get_slot(&g_ctx, slotID); if (slot == NULL) { DBG_ERR("Invalid slot ID %lu", slotID); return CKR_SLOT_ID_INVALID; } CK_RV rv = get_mechanism_info(slot, type, pInfo); release_slot(&g_ctx, slot); DOUT; return rv; } CK_DEFINE_FUNCTION(CK_RV, C_InitToken) (CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel) { DIN; UNUSED(slotID); UNUSED(pPin); UNUSED(ulPinLen); UNUSED(pLabel); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_InitPIN) (CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { DIN; UNUSED(hSession); UNUSED(pPin); UNUSED(ulPinLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_SetPIN) (CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen) { DIN; UNUSED(hSession); UNUSED(pOldPin); UNUSED(ulOldLen); UNUSED(pNewPin); UNUSED(ulNewLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_OpenSession) (CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) { DIN; // TODO(adma): check pApplication and Notify UNUSED(Notify); UNUSED(pApplication); if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (phSession == NULL) { DBG_ERR("Wrong/Missing parameter"); return CKR_ARGUMENTS_BAD; } if ((flags & CKF_SERIAL_SESSION) == 0) { // NOTE(adma): required by specs DBG_ERR("Open session called without CKF_SERIAL_SESSION set"); return CKR_SESSION_PARALLEL_NOT_SUPPORTED; } yubihsm_pkcs11_slot *slot = get_slot(&g_ctx, slotID); if (slot == NULL) { DBG_ERR("Invalid slot ID %lu", slotID); return CKR_SLOT_ID_INVALID; } CK_RV rv = CKR_OK; if (yh_connector_has_device(slot->connector) == false) { DBG_ERR("Slot %lu has no token inserted", slotID); rv = CKR_TOKEN_NOT_PRESENT; goto c_os_out; } // NOTE(adma): we have already checked that the connector is // connectable at this point. This function should only "allocate" a // session pointer if (create_session(slot, flags, phSession) == false) { DBG_ERR("Connector %lu has too many open sessions", slotID); rv = CKR_SESSION_COUNT; goto c_os_out; } DBG_INFO("Allocated session %lu", *phSession); DOUT; c_os_out: release_slot(&g_ctx, slot); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_CloseSession)(CK_SESSION_HANDLE hSession) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv == CKR_OK) { if (session->slot->pkcs11_sessions.length == 1) { // NOTE: if this is the last session and is authenticated we need to // de-auth yh_rc yrc = yh_util_close_session(session->slot->device_session); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed closing device session: %s, continuing", yh_strerror(yrc)); } yrc = yh_destroy_session(&session->slot->device_session); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed destroying session: %s", yh_strerror(yrc)); // TODO: should we handle the error cases here better? } session->slot->device_session = NULL; } release_session(&g_ctx, session); } else if (rv == CKR_SESSION_HANDLE_INVALID) { // BUG(thorduri): piggybacking off of the validation in get_session() // above, which might not hold forever. DBG_ERR("Trying to close invalid session"); return CKR_SESSION_HANDLE_INVALID; } if (session) { list_destroy(&session->ecdh_session_keys); } if (delete_session(&g_ctx, &hSession) == false) { DBG_ERR("Trying to close invalid session"); return CKR_SESSION_HANDLE_INVALID; } DBG_INFO("Closing session %lu", hSession); DOUT; return CKR_OK; } CK_DEFINE_FUNCTION(CK_RV, C_CloseAllSessions)(CK_SLOT_ID slotID) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } yubihsm_pkcs11_slot *slot = get_slot(&g_ctx, slotID); if (slot == NULL) { DBG_ERR("Invalid slot"); return CKR_SLOT_ID_INVALID; } DBG_INFO("Closing all sessions for slot %lu", slotID); if (slot->device_session) { yh_rc yrc = yh_util_close_session(slot->device_session); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed closing device session: %s, continuing", yh_strerror(yrc)); } yrc = yh_destroy_session(&slot->device_session); if (yrc != YHR_SUCCESS) { // TODO: handle or ignore these errrors? DBG_ERR("Failed destroying device session: %s", yh_strerror(yrc)); } slot->device_session = NULL; } list_destroy(&slot->pkcs11_sessions); list_create(&slot->pkcs11_sessions, sizeof(yubihsm_pkcs11_session), NULL); release_slot(&g_ctx, slot); DOUT; return CKR_OK; } CK_DEFINE_FUNCTION(CK_RV, C_GetSessionInfo) (CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pInfo == NULL) { DBG_ERR("Wrong/Missing parameter"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV ret = get_session(&g_ctx, hSession, &session, 0); if (ret != CKR_OK) { return ret; } pInfo->slotID = session->slot->id; pInfo->flags = 0; CK_RV rv = CKR_OK; switch (session->session_state) { case SESSION_RESERVED_RO: pInfo->state = CKS_RO_PUBLIC_SESSION; break; case SESSION_RESERVED_RW: pInfo->state = CKS_RW_PUBLIC_SESSION; pInfo->flags |= CKF_RW_SESSION; break; case SESSION_AUTHENTICATED_RO: pInfo->state = CKS_RO_USER_FUNCTIONS; break; case SESSION_AUTHENTICATED_RW: pInfo->state = CKS_RW_USER_FUNCTIONS; pInfo->flags |= CKF_RW_SESSION; break; default: DBG_ERR("Invalid session state %d for session %lu", session->session_state, hSession); rv = CKR_SESSION_HANDLE_INVALID; } pInfo->flags |= CKF_SERIAL_SESSION; pInfo->ulDeviceError = 0; if (rv == CKR_OK) { DOUT; } release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_GetOperationState) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) { DIN; UNUSED(hSession); UNUSED(pOperationState); UNUSED(pulOperationStateLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_SetOperationState) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) { DIN; UNUSED(hSession); UNUSED(pOperationState); UNUSED(ulOperationStateLen); UNUSED(hEncryptionKey); UNUSED(hAuthenticationKey); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } static void login_sessions(void *data) { yubihsm_pkcs11_session *session = (yubihsm_pkcs11_session *) data; switch (session->session_state) { case SESSION_RESERVED_RO: session->session_state = SESSION_AUTHENTICATED_RO; break; case SESSION_RESERVED_RW: session->session_state = SESSION_AUTHENTICATED_RW; break; case SESSION_AUTHENTICATED_RO: case SESSION_AUTHENTICATED_RW: break; } } static void logout_sessions(void *data) { yubihsm_pkcs11_session *session = (yubihsm_pkcs11_session *) data; switch (session->session_state) { case SESSION_AUTHENTICATED_RO: session->session_state = SESSION_RESERVED_RO; break; case SESSION_AUTHENTICATED_RW: session->session_state = SESSION_RESERVED_RW; break; case SESSION_RESERVED_RO: case SESSION_RESERVED_RW: break; } } CK_DEFINE_FUNCTION(CK_RV, C_Login) (CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { DIN; if (pPin == NULL) { DBG_ERR("Wrong/Missing parameter"); return CKR_ARGUMENTS_BAD; } CK_ULONG ulUsernameLen = *pPin == '@' ? 5 : 4; if (ulUsernameLen > ulPinLen) { ulUsernameLen = ulPinLen; } CK_RV rv = C_LoginUser(hSession, userType, pPin + ulUsernameLen, ulPinLen - ulUsernameLen, pPin, ulUsernameLen); DOUT; return rv; } CK_DEFINE_FUNCTION(CK_RV, C_Logout)(CK_SESSION_HANDLE hSession) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } yh_rc yrc = yh_util_close_session(session->slot->device_session); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed closing session: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_l_out; } yrc = yh_destroy_session(&session->slot->device_session); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed destroying session: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_l_out; } session->slot->device_session = NULL; list_iterate(&session->slot->pkcs11_sessions, logout_sessions); DOUT; c_l_out: release_session(&g_ctx, session); return rv; } static yh_rc set_wrapkey_capabilities(yubihsm_pkcs11_object_template *template, yh_capabilities *capabilities) { yh_rc rc; if (template->wrap == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("export-wrapped", capabilities); if (rc != YHR_SUCCESS) { return rc; } } if (template->unwrap == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("import-wrapped", capabilities); if (rc != YHR_SUCCESS) { return rc; } } if (template->encrypt == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("wrap-data", capabilities); if (rc != YHR_SUCCESS) { return rc; } } if (template->decrypt == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("unwrap-data", capabilities); if (rc != YHR_SUCCESS) { return rc; } } return YHR_SUCCESS; } CK_DEFINE_FUNCTION(CK_RV, C_CreateObject) (CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pTemplate == NULL || ulCount == 0 || phObject == NULL) { DBG_ERR("Called with invalid parameters: pTemplate=%p ulCount=%lu " "phObject=%p", (void *) pTemplate, ulCount, (void *) phObject); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED_RW); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("A different operation is already active"); rv = CKR_OPERATION_ACTIVE; goto c_co_out; } struct { bool set; CK_ULONG d; } class = {0}, key_type = {0}; yubihsm_pkcs11_object_template template = {0}; pkcs11_meta_object meta_object = {0}; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_CLASS: if (class.set == false) { class.d = *((CK_ULONG_PTR) pTemplate[i].pValue); class.set = true; } else { rv = CKR_TEMPLATE_INCONSISTENT; goto c_co_out; } break; case CKA_KEY_TYPE: if (key_type.set == false) { key_type.d = *((CK_ULONG_PTR) pTemplate[i].pValue); key_type.set = true; } else { rv = CKR_TEMPLATE_INCONSISTENT; goto c_co_out; } break; case CKA_ID: rv = parse_meta_id_template(&template, &meta_object, false, pTemplate[i].pValue, pTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_LABEL: rv = parse_meta_label_template(&template, &meta_object, false, pTemplate[i].pValue, pTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_EXTRACTABLE: if ((rv = set_template_attribute(&template.exportable, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_EXTRACTABLE inconsistent in template"); goto c_co_out; } } } if (class.set == false) { rv = CKR_TEMPLATE_INCOMPLETE; goto c_co_out; } yh_capabilities capabilities = {{0}}; yh_capabilities delegated_capabilities = {{0}}; uint8_t type = 0; yh_rc rc = YHR_SUCCESS; if (template.exportable == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("exportable-under-wrap", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } } if (class.d == CKO_PRIVATE_KEY) { if (key_type.set == false) { rv = CKR_TEMPLATE_INCOMPLETE; goto c_co_out; } type = YH_ASYMMETRIC_KEY; if (key_type.d == CKK_RSA) { rv = parse_rsa_template(pTemplate, ulCount, &template); if (rv != CKR_OK) { goto c_co_out; } DBG_INFO("parsed RSA key, algorithm: %d, objlen: %d", template.algorithm, template.objlen); uint8_t p[512] = {0}, q[512] = {0}; set_component(p, template.obj.rsa.p, template.objlen); set_component(q, template.obj.rsa.q, template.objlen); BN_free(template.obj.rsa.p); BN_free(template.obj.rsa.q); if (template.unwrap == ATTRIBUTE_TRUE) { type = YH_WRAP_KEY; rc = set_wrapkey_capabilities(&template, &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } rc = yh_string_to_capabilities("all", &delegated_capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } uint8_t key[1024] = {0}; memcpy(key, p, template.objlen); memcpy(key + template.objlen, q, template.objlen); rc = yh_util_import_wrap_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm, &delegated_capabilities, key, template.objlen * 2); } else { if (template.sign == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("sign-pkcs,sign-pss", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } } if (template.decrypt == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } } rc = yh_util_import_rsa_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm, p, q); } if (rc != YHR_SUCCESS) { DBG_ERR("Failed importing RSA key to device: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_co_out; } } else if (key_type.d == CKK_EC) { rv = parse_ec_template(pTemplate, ulCount, &template); if (rv != CKR_OK) { goto c_co_out; } DBG_INFO("parsed EC key, algorithm: %d, objlen: %d", template.algorithm, template.objlen); if (template.sign == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("sign-ecdsa", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } } if (template.derive == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("derive-ecdh", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } } uint8_t d[128] = {0}; set_component(d, template.obj.ec.d, template.objlen); BN_free(template.obj.ec.d); rc = yh_util_import_ec_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm, d); if (rc != YHR_SUCCESS) { DBG_ERR("Failed importing EC key to device: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_co_out; } } else if (key_type.d == CKK_EC_EDWARDS) { rv = parse_ed_template(pTemplate, ulCount, &template); if (rv != CKR_OK) { goto c_co_out; } DBG_INFO("parsed ED key, algorithm: %d, objlen: %d", template.algorithm, template.objlen); if (template.sign == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("sign-eddsa", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } } rc = yh_util_import_ed_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm, template.obj.buf); if (rc != YHR_SUCCESS) { DBG_ERR("Failed importing ED key to device"); rv = yrc_to_rv(rc); goto c_co_out; } } else { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto c_co_out; } if (meta_object.cka_id.len > 0 || meta_object.cka_label.len > 0) { meta_object.target_id = template.id; } } else if (class.d == CKO_SECRET_KEY) { if (key_type.set == false) { rv = CKR_TEMPLATE_INCOMPLETE; goto c_co_out; } if (key_type.d == CKK_SHA_1_HMAC || key_type.d == CKK_SHA256_HMAC || key_type.d == CKK_SHA384_HMAC || key_type.d == CKK_SHA512_HMAC) { type = YH_HMAC_KEY; rv = parse_hmac_template(pTemplate, ulCount, &template, false); if (rv != CKR_OK) { goto c_co_out; } DBG_INFO("parsed HMAC key, algorithm: %d, objlen: %d", template.algorithm, template.objlen); if (template.sign == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("sign-hmac", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } } if (template.verify == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("verify-hmac", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } } rc = yh_util_import_hmac_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm, template.obj.buf, template.objlen); if (rc != YHR_SUCCESS) { DBG_ERR("Failed writing HMAC key to device: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_co_out; } } else if (key_type.d == CKK_YUBICO_AES128_CCM_WRAP || key_type.d == CKK_YUBICO_AES192_CCM_WRAP || key_type.d == CKK_YUBICO_AES256_CCM_WRAP) { yh_algorithm algo = key_type.d & 0xff; rv = parse_wrap_template(pTemplate, ulCount, &template, algo, false); if (rv != CKR_OK) { goto c_co_out; } DBG_INFO("parsed WRAP key, objlen: %d", template.objlen); rc = set_wrapkey_capabilities(&template, &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } rc = yh_string_to_capabilities("all", &delegated_capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } type = YH_WRAP_KEY; rc = yh_util_import_wrap_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, algo, &delegated_capabilities, template.obj.buf, template.objlen); if (rc != YHR_SUCCESS) { DBG_ERR("Failed writing WRAP key to device: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_co_out; } } else if (key_type.d == CKK_AES) { type = YH_SYMMETRIC_KEY; rv = parse_aes_template(pTemplate, ulCount, &template, false); if (rv != CKR_OK) { goto c_co_out; } if (template.encrypt == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("encrypt-ecb,encrypt-cbc", &capabilities); if (rc != YHR_SUCCESS) { rv = CKR_FUNCTION_FAILED; goto c_co_out; } } if (template.decrypt == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("decrypt-ecb,decrypt-cbc", &capabilities); if (rc != YHR_SUCCESS) { rv = CKR_FUNCTION_FAILED; goto c_co_out; } } if (yh_util_import_aes_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm, template.obj.buf) != YHR_SUCCESS) { DBG_ERR("Failed writing symmetric key to device"); rv = CKR_FUNCTION_FAILED; goto c_co_out; } } else { DBG_ERR("Unknown key_type: %lx", key_type.d); rv = CKR_ATTRIBUTE_VALUE_INVALID; goto c_co_out; } if (meta_object.cka_id.len > 0 || meta_object.cka_label.len > 0) { meta_object.target_id = template.id; } } else if (class.d == CKO_CERTIFICATE || class.d == CKO_DATA) { yh_algorithm algo = YH_ALGO_OPAQUE_DATA; type = YH_OPAQUE; if (class.d == CKO_CERTIFICATE) { algo = YH_ALGO_OPAQUE_X509_CERTIFICATE; } else { algo = YH_ALGO_OPAQUE_DATA; } for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_VALUE: if (template.obj.buf == NULL) { template.obj.buf = (CK_BYTE_PTR) pTemplate[i].pValue; template.objlen = pTemplate[i].ulValueLen; DBG_INFO("Object will be stored with length %d", template.objlen); } else { DBG_ERR("Object buffer already set"); rv = CKR_TEMPLATE_INCONSISTENT; goto c_co_out; } break; case CKA_CERTIFICATE_TYPE: if (algo != YH_ALGO_OPAQUE_X509_CERTIFICATE || *(CK_CERTIFICATE_TYPE *) pTemplate[i].pValue != CKC_X_509) { DBG_ERR("Certificate type invalid"); rv = CKR_ATTRIBUTE_VALUE_INVALID; goto c_co_out; } break; case CKA_PRIVATE: case CKA_SENSITIVE: case CKA_COPYABLE: if ((rv = check_bool_attribute(pTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx", pTemplate[i].type); return rv; } break; case CKA_DESTROYABLE: if ((rv = check_bool_attribute(pTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pTemplate[i].type); return rv; } break; case CKA_TOKEN: // pkcs11test sets this to false case CKA_CLASS: case CKA_ID: case CKA_LABEL: case CKA_APPLICATION: case CKA_OBJECT_ID: case CKA_SUBJECT: case CKA_ISSUER: case CKA_SERIAL_NUMBER: case CKA_EXTRACTABLE: break; default: DBG_ERR("Invalid attribute type in key template: 0x%lx", pTemplate[i].type); rv = CKR_ATTRIBUTE_TYPE_INVALID; goto c_co_out; } } rc = yh_util_import_opaque_ex(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, algo, template.obj.buf, template.objlen, algo == YH_ALGO_OPAQUE_X509_CERTIFICATE ? COMPRESS_IF_TOO_BIG : NO_COMPRESS, NULL); if (rc != YHR_SUCCESS) { DBG_ERR("Failed writing Opaque object to device: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_co_out; } if (algo == YH_ALGO_OPAQUE_X509_CERTIFICATE && (meta_object.cka_id.len > 0 || meta_object.cka_label.len > 0)) { meta_object.target_id = template.id; } } else if (class.d == CKO_PUBLIC_KEY) { // Read the value of the public key for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_VALUE: if (template.obj.buf == NULL) { template.obj.buf = (CK_BYTE_PTR) pTemplate[i].pValue; template.objlen = pTemplate[i].ulValueLen; DBG_INFO("Object will be stored with length %d", template.objlen); } else { DBG_ERR("Object buffer already set"); rv = CKR_TEMPLATE_INCONSISTENT; goto c_co_out; } break; case CKA_WRAP: if ((rv = set_template_attribute(&template.wrap, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_WRAP inconsistent in template"); return rv; } break; case CKA_ENCRYPT: if ((rv = set_template_attribute(&template.encrypt, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_ENCRYPT inconsistent in template"); return rv; } break; } } if (template.wrap == ATTRIBUTE_TRUE && key_type.d == CKK_RSA) { switch (template.objlen) { case 256: template.algorithm = YH_ALGO_RSA_2048; break; case 384: template.algorithm = YH_ALGO_RSA_3072; break; case 512: template.algorithm = YH_ALGO_RSA_4096; break; default: DBG_ERR("Unsupported key length"); rv = CKR_DATA_INVALID; goto c_co_out; } if (template.algorithm == 0) { DBG_ERR("Missing CKA_KEY_TYPE in attribute template"); rv = CKR_TEMPLATE_INCOMPLETE; goto c_co_out; } rc = set_wrapkey_capabilities(&template, &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } rc = yh_string_to_capabilities("all", &delegated_capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_co_out; } rc = yh_util_import_public_wrap_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm, &delegated_capabilities, template.obj.buf, template.objlen); if (rc != YHR_SUCCESS) { DBG_ERR("Failed writing Public Wrap key to device: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_co_out; } type = YH_PUBLIC_WRAP_KEY; } else { // Treat it as asymmetric public key. List all asymmetric keys and // check whether this public key matches any of them. If not, // import operation fails bool pubkey_found = false; // Get a list of all asym objects in the YubiHSM yh_object_descriptor asym_keys[YH_MAX_ITEMS_COUNT] = {0}; size_t asym_keys_len = sizeof(asym_keys); rc = yh_util_list_objects(session->slot->device_session, 0, YH_ASYMMETRIC_KEY, 0, &capabilities, 0, NULL, asym_keys, &asym_keys_len); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to get object list"); rv = yrc_to_rv(rc); goto c_co_out; } // Check which asym public key matches the one in the request for (size_t i = 0; i < asym_keys_len; i++) { uint8_t pubkey[2048] = {0}; size_t pubkey_len = sizeof(pubkey); rc = yh_util_get_public_key_ex(session->slot->device_session, asym_keys[i].type, asym_keys[i].id, pubkey, &pubkey_len, NULL); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to get public key of object 0x%x", asym_keys[i].id); rv = yrc_to_rv(rc); goto c_co_out; } if (match_byte_array(pubkey, pubkey_len, template.obj.buf, template.objlen)) { template.id = asym_keys[i].id; pubkey_found = true; // If there's need, update or create meta_object yubihsm_pkcs11_object_desc *asym_key_desc = _get_object_desc(session->slot, asym_keys[i].id, YH_ASYMMETRIC_KEY, asym_keys[i].sequence); if (asym_key_desc == NULL) { continue; } if (meta_object.cka_id.len > 0 || meta_object.cka_label.len > 0) { yubihsm_pkcs11_object_desc *pMeta_object = find_meta_object_by_target(session->slot, asym_keys[i].id, YH_ASYMMETRIC_KEY, asym_keys[i].sequence, asym_key_desc->object.domains); if (pMeta_object != NULL) { // meta object already exists. Update it. if (meta_object.cka_id.len > 0) { pMeta_object->meta_object.cka_id_pubkey.len = meta_object.cka_id.len; memcpy(pMeta_object->meta_object.cka_id_pubkey.value, meta_object.cka_id.value, meta_object.cka_id.len); } if (meta_object.cka_label.len > 0) { pMeta_object->meta_object.cka_label_pubkey.len = meta_object.cka_label.len; memcpy(pMeta_object->meta_object.cka_label_pubkey.value, meta_object.cka_label.value, meta_object.cka_label.len); } rv = write_meta_object(session->slot, &pMeta_object->meta_object, &capabilities, asym_key_desc->object.domains, true); if (rv != CKR_OK) { goto c_co_out; } } else { // meta object does not exist. Create it meta_object.target_id = asym_keys[i].id; // No need to write this meta object now becase we will do it // later } } break; } } if (pubkey_found == false) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto c_co_out; } type = YH_ASYMMETRIC_KEY; } } else { rv = CKR_TEMPLATE_INCONSISTENT; goto c_co_out; } yubihsm_pkcs11_object_desc *object_desc = _get_object_desc(session->slot, template.id, type, 0xffff); if (object_desc == NULL) { DBG_ERR("Failed executing get object info after creating: id 0x%x", template.id); rv = CKR_OBJECT_HANDLE_INVALID; goto c_co_out; } yh_object_descriptor *object = &object_desc->object; if (meta_object.target_id != 0) { meta_object.target_type = object->type; meta_object.target_sequence = object->sequence; rv = write_meta_object(session->slot, &meta_object, &capabilities, object->domains, false); if (rv != CKR_OK) { DBG_ERR("Failed writing meta opaque object to device. Note that the " "original object has been successfully imported into the device " "but without the expected CKA_ID and/or CKA_LABEL"); goto c_co_out; } } if (class.d == CKO_PUBLIC_KEY && type != YH_PUBLIC_WRAP_KEY) { *phObject = object->sequence << 24 | (object->type | 0x80) << 16 | object->id; } else { *phObject = object->sequence << 24 | object->type << 16 | object->id; } DBG_INFO("Created object %08lx", *phObject); DOUT; c_co_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_CopyObject) (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) { DIN; UNUSED(hSession); UNUSED(hObject); UNUSED(pTemplate); UNUSED(ulCount); UNUSED(phNewObject); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_DestroyObject) (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("Other operation in progress"); rv = CKR_OPERATION_ACTIVE; goto c_do_out; } int type = hObject >> 16; if (type == ECDH_KEY_TYPE) { ListItem *item = list_get(&session->ecdh_session_keys, &hObject, compare_ecdh_keys); if (item) { list_delete(&session->ecdh_session_keys, item); DBG_INFO("Deleted ECDH session key %08lx", hObject); } else { DBG_INFO("No ECDH session key with ID %08lx was found", hObject); } } else { if (type == YH_PUBLIC_KEY || type == YH_WRAP_KEY_PUBLIC) { DBG_INFO("Trying to delete public key, returning success with noop"); goto c_do_out; } yubihsm_pkcs11_object_desc *object = get_object_desc(session->slot, hObject); if (object == NULL) { DBG_ERR("Object not found"); rv = CKR_OBJECT_HANDLE_INVALID; goto c_do_out; } yh_rc yrc; yubihsm_pkcs11_object_desc *meta_desc = find_meta_object_by_target(session->slot, object->object.id, object->object.type, object->object.sequence, object->object.domains); yrc = yh_util_delete_object(session->slot->device_session, object->object.id, object->object.type); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to delete object: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_do_out; } DBG_INFO("Deleted object %08lx", hObject); memset(object, 0, sizeof(yubihsm_pkcs11_object_desc)); if (meta_desc != NULL) { yrc = yh_util_delete_object(session->slot->device_session, meta_desc->object.id, meta_desc->object.type); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to delete meta opaque object: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_do_out; } DBG_INFO("Deleted meta object 0x%x", meta_desc->object.id); memset(meta_desc, 0, sizeof(yubihsm_pkcs11_object_desc)); } } DOUT; c_do_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_GetObjectSize) (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pulSize == NULL) { return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } int type = hObject >> 16; if (type == ECDH_KEY_TYPE) { ListItem *item = list_get(&session->ecdh_session_keys, &hObject, compare_ecdh_keys); if (item) { ecdh_session_key *key = (ecdh_session_key *) item->data; *pulSize = key->len; DOUT; } else { rv = CKR_OBJECT_HANDLE_INVALID; } } else { yubihsm_pkcs11_object_desc *object = get_object_desc(session->slot, hObject); if (object == NULL) { rv = CKR_OBJECT_HANDLE_INVALID; } else { *pulSize = object->object.len; DOUT; } } release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_GetAttributeValue) (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pTemplate == NULL || ulCount == 0) { return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } DBG_INFO("For object %08lx", hObject); int type = hObject >> 16; if (type == ECDH_KEY_TYPE) { bool object_found = false; ListItem *item = list_get(&session->ecdh_session_keys, &hObject, compare_ecdh_keys); if (item) { object_found = true; DBG_INFO("Object is an ECDH key available only in the current session. " "Key id: 0x%lx", hObject); ecdh_session_key *key = (ecdh_session_key *) item->data; rv = populate_template(type, key, pTemplate, ulCount, session); } if ((rv == CKR_OK) && !object_found) { DBG_ERR("Unable to retrieve session ECDH key with ID: %08lx", hObject); rv = CKR_OBJECT_HANDLE_INVALID; goto c_gav_out; } else if (rv != CKR_OK) { goto c_gav_out; } } else { yubihsm_pkcs11_object_desc *object = get_object_desc(session->slot, hObject); if (object == NULL) { DBG_ERR("Unable to retrieve object"); rv = CKR_OBJECT_HANDLE_INVALID; goto c_gav_out; } rv = populate_template(type, object, pTemplate, ulCount, session); if (rv != CKR_OK) { goto c_gav_out; } } DOUT; c_gav_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_SetAttributeValue) (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pTemplate == NULL || ulCount == 0) { DBG_ERR("Called with invalid parameters: pTemplate=%p ulCount=%lu", (void *) pTemplate, ulCount); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, 0); if (rv != CKR_OK) { return rv; } int type = hObject >> 16; if (type == ECDH_KEY_TYPE) { DBG_INFO("Refusing to change attributes of an ECDH session key"); rv = CKR_FUNCTION_NOT_SUPPORTED; goto c_sav_out; } yubihsm_pkcs11_object_desc *object = get_object_desc(session->slot, hObject); if (object == NULL) { DBG_ERR("Unable to retrieve object"); rv = CKR_OBJECT_HANDLE_INVALID; goto c_sav_out; } yubihsm_pkcs11_object_desc *meta_desc = find_meta_object_by_target(session->slot, object->object.id, (object->object.type & 0x7f), object->object.sequence, object->object.domains); bool changed = false; pkcs11_meta_object new_meta_object = {0}; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_ID: { if (meta_desc) { if (object->object.type == YH_PUBLIC_KEY) { if (!match_byte_array(meta_desc->meta_object.cka_id_pubkey.value, meta_desc->meta_object.cka_id_pubkey.len, pTemplate[i].pValue, pTemplate[i].ulValueLen)) { changed = true; memset(&meta_desc->meta_object.cka_id_pubkey.value, 0, meta_desc->meta_object.cka_id_pubkey.len); meta_desc->meta_object.cka_id_pubkey.len = pTemplate[i].ulValueLen; memcpy(meta_desc->meta_object.cka_id_pubkey.value, pTemplate[i].pValue, pTemplate[i].ulValueLen); } } else { if (!match_byte_array(meta_desc->meta_object.cka_id.value, meta_desc->meta_object.cka_id.len, pTemplate[i].pValue, pTemplate[i].ulValueLen)) { changed = true; memset(&meta_desc->meta_object.cka_id.value, 0, meta_desc->meta_object.cka_id.len); meta_desc->meta_object.cka_id.len = pTemplate[i].ulValueLen; memcpy(meta_desc->meta_object.cka_id.value, pTemplate[i].pValue, pTemplate[i].ulValueLen); } } } else { uint16_t new_id = parse_id_value(pTemplate[i].pValue, pTemplate[i].ulValueLen); if (pTemplate[i].ulValueLen != 2 || new_id != object->object.id) { if (object->object.type == YH_PUBLIC_KEY) { new_meta_object.cka_id_pubkey.len = pTemplate[i].ulValueLen; memcpy(new_meta_object.cka_id_pubkey.value, pTemplate[i].pValue, pTemplate[i].ulValueLen); } else { new_meta_object.cka_id.len = pTemplate[i].ulValueLen; memcpy(new_meta_object.cka_id.value, pTemplate[i].pValue, pTemplate[i].ulValueLen); } } } } break; case CKA_LABEL: if (meta_desc) { if (object->object.type == YH_PUBLIC_KEY) { if (!match_byte_array(meta_desc->meta_object.cka_label_pubkey.value, meta_desc->meta_object.cka_label_pubkey.len, pTemplate[i].pValue, pTemplate[i].ulValueLen)) { changed = true; memset(&meta_desc->meta_object.cka_label_pubkey.value, 0, meta_desc->meta_object.cka_label_pubkey.len); meta_desc->meta_object.cka_label_pubkey.len = pTemplate[i].ulValueLen; memcpy(meta_desc->meta_object.cka_label_pubkey.value, pTemplate[i].pValue, pTemplate[i].ulValueLen); } } else { if (!match_byte_array(meta_desc->meta_object.cka_label.value, meta_desc->meta_object.cka_label.len, pTemplate[i].pValue, pTemplate[i].ulValueLen)) { changed = true; memset(&meta_desc->meta_object.cka_label.value, 0, meta_desc->meta_object.cka_label.len); meta_desc->meta_object.cka_label.len = pTemplate[i].ulValueLen; memcpy(meta_desc->meta_object.cka_label.value, pTemplate[i].pValue, pTemplate[i].ulValueLen); } } } else { if (pTemplate[i].ulValueLen != strlen(object->object.label)) { if (object->object.type == YH_PUBLIC_KEY) { new_meta_object.cka_label_pubkey.len = pTemplate[i].ulValueLen; memcpy(new_meta_object.cka_label_pubkey.value, pTemplate[i].pValue, pTemplate[i].ulValueLen); } else { new_meta_object.cka_label.len = pTemplate[i].ulValueLen; memcpy(new_meta_object.cka_label.value, pTemplate[i].pValue, pTemplate[i].ulValueLen); } } } break; case CKA_SUBJECT: DBG_WARN("Setting value of attribute CKA_SUBJECT is ignored"); break; default: DBG_INFO("Refusing to change attribute %lx of object", pTemplate[i].type); rv = CKR_FUNCTION_NOT_SUPPORTED; goto c_sav_out; } } if (changed) { rv = write_meta_object(session->slot, &meta_desc->meta_object, &object->object.capabilities, object->object.domains, true); if (rv != CKR_OK) { goto c_sav_out; } } else if (new_meta_object.cka_id.len > 0 || new_meta_object.cka_label.len > 0 || new_meta_object.cka_id_pubkey.len > 0 || new_meta_object.cka_label_pubkey.len > 0) { new_meta_object.target_id = object->object.id; new_meta_object.target_type = object->object.type & 0x7f; new_meta_object.target_sequence = object->object.sequence; rv = write_meta_object(session->slot, &new_meta_object, &object->object.capabilities, object->object.domains, false); if (rv != CKR_OK) { goto c_sav_out; } } DOUT; c_sav_out: release_session(&g_ctx, session); return rv; } static bool should_include_sessionkeys(bool is_secret_key, bool extractable_set, bool is_extractable, int object_id) { if (object_id != 0) { // Searching for a specific keys return false; } if (!is_secret_key) { return false; } if (extractable_set && !is_extractable) { return false; } return true; } CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit) (CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (ulCount != 0 && pTemplate == NULL) { DBG_ERR("Asking for specific objects but no template given"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, 0); if (rv != CKR_OK) { return rv; } char *label = NULL; uint8_t *template_value = NULL; if (session->operation.type != OPERATION_NOOP) { DBG_ERR("Another operation is already active %d", session->operation.type); rv = CKR_OPERATION_ACTIVE; goto c_foi_out; } session->operation.op.find.only_private = false; session->operation.op.find.n_objects = 0; if (session->session_state & SESSION_NOT_AUTHENTICATED) { rv = CKR_OK; // NOTE: we need to take extra care here, we're lying about the operation // being succesful, so we need to setup the internal state correctly as // well. session->operation.type = OPERATION_FIND; session->operation.op.find.current_object = 0; DOUT; goto c_foi_out; } yh_rc rc = YHR_SUCCESS; uint8_t type = 0; uint16_t domains = 0; yh_capabilities capabilities = {{0}}; bool pub = false; yh_algorithm algorithm = 0; bool unknown = false; bool secret_key = false; bool rsa_key = false; bool wrap_key = false; bool extractable_set = false; size_t template_value_len = 0; uint8_t template_id[CKA_ATTRIBUTE_VALUE_SIZE] = {0}; size_t template_id_len = 0; uint8_t template_label[CKA_ATTRIBUTE_VALUE_SIZE] = {0}; size_t template_label_len = 0; DBG_INFO("find with %lu attributes", ulCount); if (ulCount != 0) { for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_ID: template_id_len = pTemplate[i].ulValueLen; memcpy(template_id, pTemplate[i].pValue, template_id_len); break; case CKA_CLASS: { uint32_t value = *((CK_ULONG_PTR) (pTemplate[i].pValue)); uint8_t class_type = 0; switch (value) { case CKO_CERTIFICATE: DBG_INFO("filtering for certificates"); algorithm = YH_ALGO_OPAQUE_X509_CERTIFICATE; // TODO: handle other certs? class_type = YH_OPAQUE; break; case CKO_DATA: class_type = YH_OPAQUE; break; case CKO_PUBLIC_KEY: DBG_INFO("filtering for public keys"); pub = true; class_type = YH_ASYMMETRIC_KEY; break; case CKO_PRIVATE_KEY: DBG_INFO("filtering for private keys"); session->operation.op.find.only_private = true; class_type = YH_ASYMMETRIC_KEY; break; case CKO_SECRET_KEY: DBG_INFO("filtering for secret keys"); secret_key = true; break; default: unknown = true; DBG_INFO("Asking for unknown class %x, returning empty set. %x", (uint32_t) pTemplate[i].type, value); } rv = set_object_type(&type, class_type); if (rv != CKR_OK) { goto c_foi_out; } } break; case CKA_LABEL: template_label_len = pTemplate[i].ulValueLen; memcpy(template_label, pTemplate[i].pValue, template_label_len); break; case CKA_SIGN: if (*((CK_BBOOL *) pTemplate[i].pValue) == CK_TRUE) { session->operation.op.find.only_private = true; rc = yh_string_to_capabilities( "sign-pkcs,sign-pss,sign-ecdsa,sign-hmac", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_foi_out; } } break; case CKA_DECRYPT: if (*((CK_BBOOL *) pTemplate[i].pValue) == CK_TRUE) { session->operation.op.find.only_private = true; rc = yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep,derive-ecdh," "unwrap-data,decrypt-ecb,decrypt-cbc", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_foi_out; } } break; case CKA_ENCRYPT: if (*((CK_BBOOL *) pTemplate[i].pValue) == CK_TRUE) { rc = yh_string_to_capabilities("wrap-data,encrypt-ecb,encrypt-cbc", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_foi_out; } } break; case CKA_WRAP: if (*((CK_BBOOL *) pTemplate[i].pValue) == CK_TRUE) { wrap_key = true; rc = yh_string_to_capabilities("export-wrapped", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_foi_out; } } break; case CKA_UNWRAP: if (*((CK_BBOOL *) pTemplate[i].pValue) == CK_TRUE) { wrap_key = true; rc = yh_string_to_capabilities("import-wrapped", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_foi_out; } } break; case CKA_EXTRACTABLE: extractable_set = true; if (*((CK_BBOOL *) pTemplate[i].pValue) == CK_TRUE) { session->operation.op.find.only_private = true; rc = yh_string_to_capabilities("exportable-under-wrap", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_foi_out; } } break; case CKA_VALUE: template_value_len = pTemplate[i].ulValueLen; template_value = malloc(template_value_len * sizeof(uint8_t)); memcpy(template_value, pTemplate[i].pValue, template_value_len); break; case CKA_KEY_TYPE: { uint32_t value = *((CK_ULONG_PTR) (pTemplate[i].pValue)); uint8_t key_type = 0; switch (value) { case CKK_YUBICO_AES128_CCM_WRAP: case CKK_YUBICO_AES192_CCM_WRAP: case CKK_YUBICO_AES256_CCM_WRAP: key_type = YH_WRAP_KEY; break; case CKK_SHA_1_HMAC: case CKK_SHA256_HMAC: case CKK_SHA384_HMAC: case CKK_SHA512_HMAC: key_type = YH_HMAC_KEY; break; case CKK_AES: key_type = YH_SYMMETRIC_KEY; break; case CKK_RSA: rsa_key = true; case CKK_EC: key_type = YH_ASYMMETRIC_KEY; break; default: unknown = true; DBG_INFO("Asking for unknown key type %x, returning empty set. " "%x", (uint32_t) pTemplate[i].type, value); } rv = set_object_type(&type, key_type); if (rv != CKR_OK) { goto c_foi_out; } } break; case CKA_TOKEN: case CKA_PRIVATE: case CKA_SENSITIVE: case CKA_ALWAYS_SENSITIVE: case CKA_DESTROYABLE: case CKA_APPLICATION: case CKA_CERTIFICATE_TYPE: DBG_INFO("Got type %x, ignoring it for results", (uint32_t) pTemplate[i].type); break; default: unknown = true; DBG_INFO("Got type %x, returning empty set", (uint32_t) pTemplate[i].type); break; } } } if(wrap_key && rsa_key) { if (pub) { type = YH_PUBLIC_WRAP_KEY; } else { type = YH_WRAP_KEY; } } if (unknown == false) { uint16_t found_objects = 0; if (secret_key == true) { // NOTE(adma): looking for a secret key. Get items of all types and filter // manually yh_object_descriptor tmp_objects[YH_MAX_ITEMS_COUNT + MAX_ECDH_SESSION_KEYS] = {0}; size_t tmp_n_objects = YH_MAX_ITEMS_COUNT + MAX_ECDH_SESSION_KEYS; rc = yh_util_list_objects(session->slot->device_session, 0, type, domains, &capabilities, algorithm, label, tmp_objects, &tmp_n_objects); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to get object list: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_foi_out; } for (size_t i = 0; i < tmp_n_objects; i++) { if (tmp_objects[i].type == YH_WRAP_KEY || tmp_objects[i].type == YH_HMAC_KEY || tmp_objects[i].type == YH_SYMMETRIC_KEY) { yubihsm_pkcs11_object_desc *object_desc = _get_object_desc(session->slot, tmp_objects[i].id, tmp_objects[i].type, tmp_objects[i].sequence); if (object_desc != NULL && match_meta_attributes(session, &object_desc->object, template_id, template_id_len, template_label, template_label_len)) { memcpy(session->operation.op.find.objects + found_objects, tmp_objects + i, sizeof(yh_object_descriptor)); found_objects++; } } } } else { if (template_value != NULL) { // Find by certificate if (algorithm != 0 && algorithm != YH_ALGO_OPAQUE_X509_CERTIFICATE) { DBG_ERR( "Value in template not an X509Certificate. Cannot perform search."); rv = CKR_ATTRIBUTE_VALUE_INVALID; goto c_foi_out; } yh_object_descriptor tmp_objects[YH_MAX_ITEMS_COUNT] = {0}; size_t tmp_n_objects = sizeof(tmp_objects); rc = yh_util_list_objects(session->slot->device_session, 0, YH_OPAQUE, domains, &capabilities, YH_ALGO_OPAQUE_X509_CERTIFICATE, label, tmp_objects, &tmp_n_objects); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to get object list"); rv = yrc_to_rv(rc); goto c_foi_out; } for (size_t i = 0; i < tmp_n_objects; i++) { uint8_t cert[16384] = {0}; size_t cert_len = sizeof(cert); rc = yh_util_get_opaque_ex(session->slot->device_session, tmp_objects[i].id, cert, &cert_len, NULL, true); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to get opaque object 0x%x", tmp_objects[i].id); rv = yrc_to_rv(rc); goto c_foi_out; } if (match_byte_array(template_value, template_value_len, cert, cert_len)) { session->operation.op.find.objects[0].id = tmp_objects[i].id; session->operation.op.find.objects[0].type = tmp_objects[i].type; session->operation.op.find.objects[0].sequence = tmp_objects[i].sequence; found_objects = 1; break; } } } else { yh_object_descriptor tmp_objects[YH_MAX_ITEMS_COUNT + MAX_ECDH_SESSION_KEYS] = {0}; size_t tmp_n_objects = YH_MAX_ITEMS_COUNT + MAX_ECDH_SESSION_KEYS; rc = yh_util_list_objects(session->slot->device_session, 0, type, domains, &capabilities, algorithm, label, tmp_objects, &tmp_n_objects); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to get object list"); rv = yrc_to_rv(rc); goto c_foi_out; } for (size_t i = 0; i < tmp_n_objects; i++) { yubihsm_pkcs11_object_desc *object_desc = _get_object_desc(session->slot, tmp_objects[i].id, tmp_objects[i].type, tmp_objects[i].sequence); if (object_desc && is_meta_object(&object_desc->object)) { continue; } if (match_meta_attributes(session, &object_desc->object, template_id, template_id_len, template_label, template_label_len)) { memcpy(session->operation.op.find.objects + found_objects, tmp_objects + i, sizeof(yh_object_descriptor)); found_objects++; } } if (pub) { for (size_t i = 0; i < found_objects; i++) { if (session->operation.op.find.objects[i].type == YH_ASYMMETRIC_KEY) { session->operation.op.find.objects[i].type |= 0x80; } } } } } uint16_t id = parse_id_value(template_id, template_id_len); DBG_INFO("id parsed as %x", id); if (ulCount == 0 || should_include_sessionkeys(secret_key, extractable_set, session->operation.op.find.only_private, id)) { ListItem *item = NULL; for (item = session->ecdh_session_keys.head; item != NULL; item = item->next) { ecdh_session_key *key = (ecdh_session_key *) item->data; if (template_label_len == 0 || strcmp((const char *) template_label, key->label) == 0) { yh_object_descriptor desc = {0}; desc.id = key->id & 0xffff; desc.len = key->len; desc.type = ECDH_KEY_TYPE; memcpy(desc.label, key->label, strlen(key->label) + 1); // Add this item/key to the list of found objects memcpy(session->operation.op.find.objects + found_objects, &desc, sizeof(yh_object_descriptor)); found_objects++; } } } session->operation.op.find.n_objects = found_objects; } // NOTE: it's important to set the operation type as late as possible so we // don't leave it set after erroring out. session->operation.type = OPERATION_FIND; session->operation.op.find.current_object = 0; DOUT; c_foi_out: if (template_value != NULL) { free(template_value); template_value = NULL; } if (label != NULL) { free(label); label = NULL; } release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_FindObjects) (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, 0); if (rv != CKR_OK) { return rv; } if (phObject == NULL || ulMaxObjectCount == 0 || pulObjectCount == NULL) { rv = CKR_ARGUMENTS_BAD; goto c_fo_out; } if (session->operation.type != OPERATION_FIND) { rv = CKR_OPERATION_NOT_INITIALIZED; goto c_fo_out; } DBG_INFO("Can return %lu object(s)", ulMaxObjectCount); *pulObjectCount = 0; for (CK_ULONG i = 0; i < ulMaxObjectCount && session->operation.op.find.current_object < session->operation.op.find.n_objects; session->operation.op.find.current_object++) { yh_object_descriptor *object = &session->operation.op.find .objects[session->operation.op.find.current_object]; uint32_t id; switch (object->type) { case YH_ASYMMETRIC_KEY: case YH_OPAQUE: case YH_WRAP_KEY: case YH_PUBLIC_WRAP_KEY: case YH_HMAC_KEY: case YH_PUBLIC_KEY: case YH_WRAP_KEY_PUBLIC: case YH_SYMMETRIC_KEY: id = object->sequence << 24; id |= object->type << 16; id |= object->id; break; default: if (object->type == ECDH_KEY_TYPE) { id = ECDH_KEY_TYPE << 16; id |= object->id; } else { DBG_INFO("Found unknown object type %x, skipping over", object->type); continue; } } phObject[i++] = id; *pulObjectCount += 1; if (!session->operation.op.find.only_private && object->type == YH_ASYMMETRIC_KEY) { object->type |= 0x80; session->operation.op.find.current_object--; DBG_INFO("stepping back"); } DBG_INFO("Returning object %zu as %08x", session->operation.op.find.current_object, id); } DBG_INFO("Returning %lu object(s)", *pulObjectCount); DOUT; c_fo_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsFinal)(CK_SESSION_HANDLE hSession) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, 0); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_FIND) { rv = CKR_OPERATION_NOT_INITIALIZED; goto c_fof_out; } session->operation.op.find.current_object = 0; session->operation.op.find.n_objects = 0; session->operation.type = OPERATION_NOOP; DOUT; c_fof_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_EncryptInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pMechanism == NULL) { DBG_ERR("Invalid Mechanism"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("Other operation in progress"); rv = CKR_OPERATION_ACTIVE; goto c_ei_out; } rv = check_decrypt_mechanism(session->slot, pMechanism); if (rv != CKR_OK) { DBG_ERR("Encryption mechanism 0x%lx not supported", pMechanism->mechanism); goto c_ei_out; } DBG_INFO("Trying to encrypt data with mechanism 0x%04lx and key %08lx", pMechanism->mechanism, hKey); rv = apply_encrypt_mechanism_init(session, pMechanism, hKey); if (rv != CKR_OK) { DBG_ERR("Failed to initialize encryption operation"); goto c_ei_out; } session->operation.mechanism.mechanism = pMechanism->mechanism; session->operation.op.encrypt.key_id = hKey; session->operation.type = OPERATION_ENCRYPT; session->operation.buffer_length = 0; set_operation_part(&session->operation, PART_INIT); DOUT; c_ei_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_Encrypt) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { DIN; CK_RV rv = CKR_OK; bool terminate = true; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_e_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_e_out; } if (session->operation.type != OPERATION_ENCRYPT) { DBG_ERR("Encryption operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_e_out; } rv = set_operation_part(&session->operation, PART_SINGLE); if (rv != CKR_OK) { DBG_ERR("Another encrypt operation is already active"); goto c_e_out; } if (pData == NULL || pulEncryptedDataLen == NULL) { DBG_ERR("Invalid argument"); rv = CKR_ARGUMENTS_BAD; goto c_e_out; } // Calculate exact output size CK_ULONG datalen = 0; switch (session->operation.mechanism.mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: datalen = (session->operation.op.encrypt.key_len + 7) / 8; break; case CKM_YUBICO_AES_CCM_WRAP: if (ULONG_MAX - YH_CCM_WRAP_OVERHEAD < ulDataLen) { rv = CKR_DATA_LEN_RANGE; goto c_e_out; } datalen = YH_CCM_WRAP_OVERHEAD + ulDataLen; break; case CKM_AES_ECB: case CKM_AES_CBC: datalen = ulDataLen; break; case CKM_AES_CBC_PAD: datalen = ulDataLen / 16 * 16; if (ULONG_MAX - 16 < datalen) { rv = CKR_DATA_LEN_RANGE; goto c_e_out; } datalen += 16; break; default: DBG_ERR("Mechanism %lu not supported", session->operation.mechanism.mechanism); rv = CKR_MECHANISM_INVALID; goto c_e_out; } DBG_INFO("Approximated output size is %lu", datalen); if (pEncryptedData == NULL) { // NOTE: if data is NULL just return size we'll need *pulEncryptedDataLen = datalen; rv = CKR_OK; terminate = false; goto c_e_out; } // Output size is accurately calculated above, we can stop here. if (*pulEncryptedDataLen < datalen) { DBG_ERR("pulEncryptedDataLen too small, expected = %lu, got %lu", datalen, *pulEncryptedDataLen); rv = CKR_BUFFER_TOO_SMALL; *pulEncryptedDataLen = datalen; terminate = false; goto c_e_out; } // Both update and finalize may modify the output. We'll have to calculate // the completed size ourselves by summarizing the two operations. CK_ULONG ulRemainingSize = *pulEncryptedDataLen; CK_BYTE_PTR pPtr = pEncryptedData; rv = apply_decrypt_mechanism_update(session->slot->device_session, &session->operation, pData, ulDataLen, pPtr, pulEncryptedDataLen); if (rv != CKR_OK) { // Buffer too small should have been handled above. // Translate into a non-recoverable error. rv = rv == CKR_BUFFER_TOO_SMALL ? CKR_FUNCTION_FAILED : rv; DBG_ERR("Unable to perform encrypt operation step"); goto c_e_out; } ulRemainingSize -= *pulEncryptedDataLen; pPtr += *pulEncryptedDataLen; rv = apply_encrypt_mechanism_finalize(session->slot->device_session, &session->operation, pPtr, &ulRemainingSize); if (rv != CKR_OK) { // Buffer too small should have been handled above. // Translate into a non-recoverable error. rv = rv == CKR_BUFFER_TOO_SMALL ? CKR_FUNCTION_FAILED : rv; DBG_ERR("Unable to perform encrypt operation step"); goto c_e_out; } // Calculate final size. *pulEncryptedDataLen += ulRemainingSize; DBG_INFO("Got %lu butes back", *pulEncryptedDataLen); rv = CKR_OK; DOUT; c_e_out: if (session != NULL) { release_session(&g_ctx, session); if (terminate == true) { session->operation.type = OPERATION_NOOP; } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_EncryptUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { DIN; CK_RV rv = CKR_OK; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_eu_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_eu_out; } if (session->operation.type != OPERATION_ENCRYPT) { DBG_ERR("Decrypt operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_eu_out; } rv = set_operation_part(&session->operation, PART_MULTIPLE); if (rv != CKR_OK) { DBG_ERR("Another encrypt operation is already active"); goto c_eu_out; } if (pPart == NULL || pulEncryptedPartLen == NULL) { DBG_ERR("Invalid argument"); rv = CKR_ARGUMENTS_BAD; goto c_eu_out; } DBG_INFO("Encrypt update with %lu bytes", ulPartLen); rv = apply_decrypt_mechanism_update(session->slot->device_session, &session->operation, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen); if (rv != CKR_OK) { DBG_ERR("Unable to perform encryption operation step"); goto c_eu_out; } DOUT; c_eu_out: if (session != NULL) { release_session(&g_ctx, session); if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL) { session->operation.type = OPERATION_NOOP; decrypt_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_EncryptFinal) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen) { DIN; CK_RV rv = CKR_OK; bool terminate = true; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_ef_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_ef_out; } if (session->operation.type != OPERATION_ENCRYPT) { DBG_ERR("Encrypt operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_ef_out; } rv = set_operation_part(&session->operation, PART_MULTIPLE); if (rv != CKR_OK) { DBG_ERR("Another encrypt operation is already active"); goto c_ef_out; } if (pulLastEncryptedPartLen == NULL) { DBG_ERR("Invalid argument"); rv = CKR_ARGUMENTS_BAD; goto c_ef_out; } if (session->operation.mechanism.mechanism == CKM_YUBICO_AES_CCM_WRAP) { CK_ULONG datalen = session->operation.buffer_length + YH_CCM_WRAP_OVERHEAD; if (*pulLastEncryptedPartLen < datalen) { DBG_ERR("pulLastEncryptedPartLen too small, data will not fit, expected " "= " "%lu, got %lu", datalen, *pulLastEncryptedPartLen); rv = CKR_BUFFER_TOO_SMALL; *pulLastEncryptedPartLen = datalen; terminate = false; goto c_ef_out; } if (pLastEncryptedPart == NULL) { // NOTE: should this rather return length and ok? DBG_ERR("No buffer provided"); rv = CKR_ARGUMENTS_BAD; goto c_ef_out; } } rv = apply_encrypt_mechanism_finalize(session->slot->device_session, &session->operation, pLastEncryptedPart, pulLastEncryptedPartLen); if (rv == CKR_BUFFER_TOO_SMALL || (rv == CKR_OK && pLastEncryptedPart == NULL)) { terminate = false; goto c_ef_out; } else if (rv != CKR_OK) { DBG_ERR("Unable to perform encrypt operation step"); goto c_ef_out; } DBG_INFO("Got %lu bytes back", *pulLastEncryptedPartLen); DOUT; c_ef_out: if (session != NULL) { release_session(&g_ctx, session); if (terminate == true) { session->operation.type = OPERATION_NOOP; decrypt_mechanism_cleanup(&session->operation); } } return rv; } typedef struct rsa_pkcs_oaep_params { yh_algorithm mgf_algo; yh_algorithm oaep_algo; uint8_t oaep_label[64]; u_int oaep_label_len; } rsa_pkcs_oaep_params_t; static CK_RV parse_rsa_pkcs_oaep_params(CK_RSA_PKCS_OAEP_PARAMS *p, rsa_pkcs_oaep_params_t *r) { const EVP_MD *md = NULL; switch (p->mgf) { case CKG_MGF1_SHA1: r->mgf_algo = YH_ALGO_MGF1_SHA1; break; case CKG_MGF1_SHA256: r->mgf_algo = YH_ALGO_MGF1_SHA256; break; case CKG_MGF1_SHA384: r->mgf_algo = YH_ALGO_MGF1_SHA384; break; case CKG_MGF1_SHA512: r->mgf_algo = YH_ALGO_MGF1_SHA512; break; default: DBG_ERR("Invalid mgf parameter (%lx)", p->mgf); return CKR_MECHANISM_PARAM_INVALID; } switch (p->hashAlg) { case CKM_SHA_1: r->oaep_algo = YH_ALGO_RSA_OAEP_SHA1; md = EVP_sha1(); break; case CKM_SHA256: r->oaep_algo = YH_ALGO_RSA_OAEP_SHA256; md = EVP_sha256(); break; case CKM_SHA384: r->oaep_algo = YH_ALGO_RSA_OAEP_SHA384; md = EVP_sha384(); break; case CKM_SHA512: r->oaep_algo = YH_ALGO_RSA_OAEP_SHA512; md = EVP_sha512(); break; default: DBG_ERR("Invalid hashAlg parameter (%lx)", p->hashAlg); return CKR_MECHANISM_PARAM_INVALID; } switch (p->source) { case 0: if (p->ulSourceDataLen) { DBG_ERR("Invalid ulSourceDataLen (%lu) parameter for source == 0", p->ulSourceDataLen); return CKR_MECHANISM_PARAM_INVALID; } case CKZ_DATA_SPECIFIED: if (p->ulSourceDataLen && p->pSourceData == NULL) { DBG_ERR( "Invalid pSourceData parameter (NULL) for ulSourceDataLen != 0"); return CKR_MECHANISM_PARAM_INVALID; } break; default: DBG_ERR("Invalid source parameter (%lx)", p->source); return CKR_MECHANISM_PARAM_INVALID; } EVP_MD_CTX *mdctx = EVP_MD_CTX_create(); if (mdctx == NULL) { DBG_ERR("Failed to digest source"); return CKR_FUNCTION_FAILED; } r->oaep_label_len = sizeof(r->oaep_label); EVP_DigestInit_ex(mdctx, md, NULL); EVP_DigestUpdate(mdctx, p->pSourceData, p->ulSourceDataLen); EVP_DigestFinal_ex(mdctx, r->oaep_label, &r->oaep_label_len); EVP_MD_CTX_destroy(mdctx); return CKR_OK; } typedef struct rsa_aes_key_wrap_params { yh_algorithm aes_algo; rsa_pkcs_oaep_params_t oaep_params; } rsa_aes_key_wrap_params_t; static CK_RV parse_rsa_aes_key_wrap_params(CK_RSA_AES_KEY_WRAP_PARAMS *p, rsa_aes_key_wrap_params_t *r) { switch (p->ulAESKeyBits) { case 128: r->aes_algo = YH_ALGO_AES128; break; case 192: r->aes_algo = YH_ALGO_AES192; break; case 256: r->aes_algo = YH_ALGO_AES256; break; default: DBG_ERR("Invalid ulAESKeyBits parameter"); return CKR_MECHANISM_PARAM_INVALID; } return parse_rsa_pkcs_oaep_params(p->pOAEPParams, &r->oaep_params); } CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pMechanism == NULL) { DBG_ERR("Invalid Mechanism"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } EVP_MD_CTX *mdctx = NULL; if (session->operation.type != OPERATION_NOOP) { DBG_ERR("Other operation in progress"); rv = CKR_OPERATION_ACTIVE; goto c_di_out; } DBG_INFO("Trying to decrypt data with mechanism 0x%04lx and key %08lx", pMechanism->mechanism, hKey); int type = hKey >> 16; if (type == ECDH_KEY_TYPE) { DBG_ERR("Wrong key type"); rv = CKR_KEY_TYPE_INCONSISTENT; goto c_di_out; } yubihsm_pkcs11_object_desc *object = get_object_desc(session->slot, hKey); if (object == NULL) { DBG_ERR("Unable to retrieve object"); rv = CKR_KEY_HANDLE_INVALID; goto c_di_out; } rv = check_decrypt_mechanism(session->slot, pMechanism); if (rv != CKR_OK) { DBG_ERR("Decryption mechanism 0x%lx not supported", pMechanism->mechanism); goto c_di_out; } session->operation.mechanism.mechanism = pMechanism->mechanism; if (object->object.type == YH_ASYMMETRIC_KEY && yh_is_rsa(object->object.algorithm)) { DBG_INFO("RSA decryption requested"); size_t key_length = 0; yh_rc yrc = yh_get_key_bitlength(object->object.algorithm, &key_length); if (yrc != YHR_SUCCESS) { DBG_ERR("Unable to get key length: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_di_out; } session->operation.op.decrypt.key_len = key_length; if (pMechanism->mechanism == CKM_RSA_PKCS_OAEP) { if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) { DBG_ERR("Length of mechanism parameters does not match expected value: " "found %lu, expected %zu", pMechanism->ulParameterLen, sizeof(CK_RSA_PKCS_OAEP_PARAMS)); rv = CKR_MECHANISM_PARAM_INVALID; goto c_di_out; } CK_RSA_PKCS_OAEP_PARAMS *params = pMechanism->pParameter; if (params->source == 0 && params->ulSourceDataLen != 0) { DBG_ERR("Source parameter empty but sourceDataLen != 0"); rv = CKR_MECHANISM_PARAM_INVALID; goto c_di_out; } else if (params->source != 0 && params->source != CKZ_DATA_SPECIFIED) { DBG_ERR("Unknown value in parameter source"); rv = CKR_MECHANISM_PARAM_INVALID; goto c_di_out; } rsa_pkcs_oaep_params_t oaep_params; rv = parse_rsa_pkcs_oaep_params(params, &oaep_params); if (rv != CKR_OK) { goto c_di_out; } session->operation.mechanism.oaep.mgf1Algo = oaep_params.mgf_algo; session->operation.mechanism.oaep.label_len = oaep_params.oaep_label_len; memcpy(session->operation.mechanism.oaep.label, oaep_params.oaep_label, oaep_params.oaep_label_len); } else if (pMechanism->mechanism != CKM_RSA_PKCS) { DBG_ERR("Mechanism %lu not supported", pMechanism->mechanism); rv = CKR_MECHANISM_INVALID; goto c_di_out; } } else if (object->object.type == YH_WRAP_KEY && pMechanism->mechanism == CKM_YUBICO_AES_CCM_WRAP) { // NOTE: is setup done for the data unwrap? rv = CKR_OK; } else if (object->object.type == YH_SYMMETRIC_KEY && pMechanism->mechanism == CKM_AES_ECB) { rv = CKR_OK; } else if (pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) { if (object->object.type != YH_SYMMETRIC_KEY || !yh_is_aes(object->object.algorithm)) { DBG_ERR("Wrong key type for algorithm"); return CKR_KEY_TYPE_INCONSISTENT; } if (pMechanism->pParameter == NULL || pMechanism->ulParameterLen != sizeof(session->operation.mechanism.cbc.iv)) { return CKR_MECHANISM_PARAM_INVALID; } // We need to save two copies to be able to reset the padding // mechanisms in case of a CKR_BUFFER_TOO_SMALL return. memcpy(session->operation.mechanism.cbc.iv, pMechanism->pParameter, sizeof(session->operation.mechanism.cbc.iv)); memcpy(session->operation.mechanism.cbc.orig, pMechanism->pParameter, sizeof(session->operation.mechanism.cbc.orig)); } else { rv = CKR_KEY_TYPE_INCONSISTENT; goto c_di_out; } session->operation.op.decrypt.key_id = hKey; // TODO(adma): check mechanism parameters and key length and key supported // parameters rv = apply_decrypt_mechanism_init(&session->operation); if (rv != CKR_OK) { DBG_ERR("Unable to initialize decryption operation"); goto c_di_out; } session->operation.type = OPERATION_DECRYPT; set_operation_part(&session->operation, PART_INIT); DOUT; c_di_out: if (mdctx != NULL) { EVP_MD_CTX_destroy(mdctx); } release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_Decrypt) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { DIN; CK_RV rv = CKR_OK; bool terminate = true; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_d_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_d_out; } if (session->operation.type != OPERATION_DECRYPT) { DBG_ERR("Decryption operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_d_out; } rv = set_operation_part(&session->operation, PART_SINGLE); if (rv != CKR_OK) { DBG_ERR("Another decrypt operation is already active"); goto c_d_out; } if (pEncryptedData == NULL || pulDataLen == NULL) { DBG_ERR("Invalid argument"); rv = CKR_ARGUMENTS_BAD; goto c_d_out; } // Approximate output size CK_ULONG datalen = 0; switch (session->operation.mechanism.mechanism) { case CKM_RSA_PKCS: datalen = (session->operation.op.decrypt.key_len + 7) / 8 - 11; break; case CKM_RSA_PKCS_OAEP: datalen = (session->operation.op.decrypt.key_len + 7) / 8 - session->operation.mechanism.oaep.label_len * 2 - 2; break; case CKM_YUBICO_AES_CCM_WRAP: if (ulEncryptedDataLen <= YH_CCM_WRAP_OVERHEAD) { DBG_ERR("Encrypted data is too short for AES-CCM-WRAP"); rv = CKR_ENCRYPTED_DATA_INVALID; goto c_d_out; } datalen = ulEncryptedDataLen - YH_CCM_WRAP_OVERHEAD; break; case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: datalen = ulEncryptedDataLen; break; default: DBG_ERR("Mechanism %lu not supported", session->operation.mechanism.mechanism); rv = CKR_MECHANISM_INVALID; goto c_d_out; } DBG_INFO("Approximated output size is %lu", datalen); if (pData == NULL) { // NOTE(adma): Just return the size of the data *pulDataLen = datalen; rv = CKR_OK; terminate = false; DOUT; goto c_d_out; } // NOTE: if pData is set we'll go on with decryption no matter what pulDataLen // is, the user might know more than us about the real data length DBG_INFO("Sending %lu bytes to decrypt using key %04x", ulEncryptedDataLen, session->operation.op.decrypt.key_id); CK_ULONG ulRemainingSize = *pulDataLen; CK_BYTE_PTR pPtr = pData; rv = apply_decrypt_mechanism_update(session->slot->device_session, &session->operation, pEncryptedData, ulEncryptedDataLen, pPtr, pulDataLen); if (rv != CKR_OK) { if (rv == CKR_BUFFER_TOO_SMALL) { // PKCS11 specifications wants this to be the _exact_ size; which we // cannot know until we call apply_decrypt_mechanism_finalize(). We'll // have to use our best guess for what the final length will be. DBG_ERR("Update failed, use best guess for actual output size"); *pulDataLen = datalen; terminate = false; } else { DBG_ERR("Unable to perform decrypt update"); } goto c_d_out; } ulRemainingSize -= *pulDataLen; pPtr += *pulDataLen; rv = apply_decrypt_mechanism_finalize(session->slot->device_session, &session->operation, pPtr, &ulRemainingSize); if (rv != CKR_OK) { DBG_ERR("Unable to decrypt data"); if (rv == CKR_BUFFER_TOO_SMALL) { *pulDataLen += ulRemainingSize; terminate = false; } goto c_d_out; } *pulDataLen += ulRemainingSize; DBG_INFO("Got %lu bytes back", *pulDataLen); rv = CKR_OK; DOUT; c_d_out: if (session != NULL) { release_session(&g_ctx, session); if (terminate == true) { session->operation.type = OPERATION_NOOP; decrypt_mechanism_cleanup(&session->operation); } // Reset the internal buffer. session->operation.buffer_length = 0; } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_DecryptUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { DIN; CK_RV rv = CKR_OK; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_du_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_du_out; } if (session->operation.type != OPERATION_DECRYPT) { DBG_ERR("Decrypt operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_du_out; } rv = set_operation_part(&session->operation, PART_MULTIPLE); if (rv != CKR_OK) { DBG_ERR("Another decrypt operation is already active"); goto c_du_out; } if (pEncryptedPart == NULL || pulPartLen == NULL) { DBG_ERR("Invalid argument"); rv = CKR_ARGUMENTS_BAD; goto c_du_out; } DBG_INFO("Decrypt update with %lu bytes", ulEncryptedPartLen); rv = apply_decrypt_mechanism_update(session->slot->device_session, &session->operation, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); if (rv != CKR_OK) { DBG_ERR("Unable to perform decryption operation step"); goto c_du_out; } DOUT; c_du_out: if (session != NULL) { release_session(&g_ctx, session); if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL) { session->operation.type = OPERATION_NOOP; decrypt_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_DecryptFinal) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) { DIN; CK_RV rv = CKR_OK; bool terminate = true; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_df_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_df_out; } if (session->operation.type != OPERATION_DECRYPT) { DBG_ERR("Decrypt operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_df_out; } rv = set_operation_part(&session->operation, PART_MULTIPLE); if (rv != CKR_OK) { DBG_ERR("Another decrypt operation is already active"); goto c_df_out; } if (pulLastPartLen == NULL) { DBG_ERR("Invalid argument"); rv = CKR_ARGUMENTS_BAD; goto c_df_out; } CK_ULONG datalen = 0; if (session->operation.mechanism.mechanism == CKM_RSA_PKCS) { datalen = (session->operation.op.decrypt.key_len + 7) / 8 - 11; } else if (session->operation.mechanism.mechanism == CKM_RSA_PKCS_OAEP) { datalen = (session->operation.op.decrypt.key_len + 7) / 8 - session->operation.mechanism.oaep.label_len * 2 - 2; } else if (session->operation.mechanism.mechanism == CKM_YUBICO_AES_CCM_WRAP) { if (session->operation.buffer_length <= YH_CCM_WRAP_OVERHEAD) { DBG_ERR("Encrypted data is to short to possibly come from aes-ccm-wrap"); rv = CKR_ENCRYPTED_DATA_INVALID; goto c_df_out; } datalen = session->operation.buffer_length - YH_CCM_WRAP_OVERHEAD; } else if (session->operation.mechanism.mechanism == CKM_AES_ECB || session->operation.mechanism.mechanism == CKM_AES_CBC) { datalen = 0; } else if (session->operation.mechanism.mechanism == CKM_AES_CBC_PAD) { datalen = 16; } else { DBG_ERR("Mechanism %lu not supported", session->operation.mechanism.mechanism); rv = CKR_MECHANISM_INVALID; goto c_df_out; } if (pLastPart == NULL) { DBG_ERR("No buffer provided, length check only"); *pulLastPartLen = datalen; rv = CKR_OK; terminate = false; goto c_df_out; } rv = apply_decrypt_mechanism_finalize(session->slot->device_session, &session->operation, pLastPart, pulLastPartLen); if (rv != CKR_OK) { DBG_ERR("Unable to decrypt data"); if (rv == CKR_BUFFER_TOO_SMALL) { terminate = false; } goto c_df_out; } DBG_INFO("Got %lu bytes back", *pulLastPartLen); DOUT; c_df_out: if (session != NULL) { release_session(&g_ctx, session); if (terminate == true) { session->operation.type = OPERATION_NOOP; decrypt_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_DigestInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pMechanism == NULL) { DBG_ERR("Invalid Mechanism"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, 0); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("Other operation in progress"); rv = CKR_OPERATION_ACTIVE; goto c_di_out; } DBG_INFO("Trying to digest data with mechanism 0x%04lx", pMechanism->mechanism); rv = check_digest_mechanism(pMechanism); if (rv != CKR_OK) { DBG_ERR("Digest mechanism %lu not supported", pMechanism->mechanism); goto c_di_out; } session->operation.mechanism.mechanism = pMechanism->mechanism; CK_ULONG digest_length = get_digest_bytelength(pMechanism->mechanism); session->operation.op.digest.digest_len = digest_length; rv = apply_digest_mechanism_init(&session->operation); if (rv != CKR_OK) { DBG_ERR("Unable to initialize digest operation"); goto c_di_out; } session->operation.type = OPERATION_DIGEST; DOUT; c_di_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_Digest) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { DIN; CK_RV rv = CKR_OK; bool terminate = true; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_d_out; } rv = get_session(&g_ctx, hSession, &session, 0); if (rv != CKR_OK) { goto c_d_out; } if (session->operation.type != OPERATION_DIGEST) { DBG_ERR("Digest operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_d_out; } rv = set_operation_part(&session->operation, PART_SINGLE); if (rv != CKR_OK) { DBG_ERR("Another digest operation is already active"); goto c_d_out; } if (pulDigestLen == NULL) { DBG_ERR("Wrong/missing parameter"); rv = CKR_ARGUMENTS_BAD; goto c_d_out; } if (pDigest == NULL) { // NOTE(adma): Just return the size of the digest DBG_INFO("The size of the digest will be %lu", session->operation.op.digest.digest_len); *pulDigestLen = session->operation.op.digest.digest_len; rv = CKR_OK; terminate = false; DOUT; goto c_d_out; } if (*pulDigestLen < session->operation.op.digest.digest_len) { DBG_ERR("pulDigestLen too small, data will not fit, expected = %lu, got " "%lu", session->operation.op.digest.digest_len, *pulDigestLen); *pulDigestLen = session->operation.op.digest.digest_len; rv = CKR_BUFFER_TOO_SMALL; terminate = false; goto c_d_out; } DBG_INFO("Sending %lu bytes to digest", ulDataLen); rv = apply_digest_mechanism_update(&session->operation, pData, ulDataLen); if (rv != CKR_OK) { DBG_ERR("Unable to perform digest operation step"); goto c_d_out; } rv = apply_digest_mechanism_finalize(&session->operation); if (rv != CKR_OK) { DBG_ERR("Unable to finalize digest operation"); goto c_d_out; } rv = perform_digest(&session->operation, pDigest, (uint16_t *) pulDigestLen); // TODO(adma): too zealous? // just us a memcpy? if (rv != CKR_OK) { DBG_ERR("Unable to digest data"); goto c_d_out; } DBG_INFO("Got %lu bytes back", *pulDigestLen); DOUT; c_d_out: if (session != NULL) { release_session(&g_ctx, session); if (terminate == true) { session->operation.type = OPERATION_NOOP; digest_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_DigestUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { DIN; CK_RV rv = CKR_OK; // TODO(adma): somebody should check that this is a proper mult-part // mechanism/operation yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_du_out; } rv = get_session(&g_ctx, hSession, &session, 0); if (rv != CKR_OK) { goto c_du_out; } if (session->operation.type != OPERATION_DIGEST) { DBG_ERR("Digest operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_du_out; } rv = set_operation_part(&session->operation, PART_MULTIPLE); if (rv != CKR_OK) { DBG_ERR("Another digest operation is already active"); goto c_du_out; } if (pPart == NULL) { DBG_ERR("No data provided"); rv = CKR_ARGUMENTS_BAD; goto c_du_out; } DBG_INFO("Digest update with %lu bytes", ulPartLen); rv = apply_digest_mechanism_update(&session->operation, pPart, ulPartLen); if (rv != CKR_OK) { DBG_ERR("Unable to perform digest operation step"); goto c_du_out; } DOUT; c_du_out: if (session != NULL) { release_session(&g_ctx, session); if (rv != CKR_OK) { session->operation.type = OPERATION_NOOP; digest_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_DigestKey) (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) { DIN; UNUSED(hSession); UNUSED(hKey); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_DigestFinal) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { DIN; CK_RV rv = CKR_OK; bool terminate = true; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_df_out; } rv = get_session(&g_ctx, hSession, &session, 0); if (rv != CKR_OK) { goto c_df_out; } if (pulDigestLen == NULL) { DBG_ERR("Wrong/missing parameter"); rv = CKR_ARGUMENTS_BAD; goto c_df_out; } if (session->operation.type != OPERATION_DIGEST) { DBG_ERR("Digest operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_df_out; } rv = set_operation_part(&session->operation, PART_MULTIPLE); if (rv != CKR_OK) { DBG_ERR("Another digest operation is already active"); goto c_df_out; } if (pDigest == NULL) { // NOTE(adma): Just return the size of the digest DBG_INFO("The size of the digest will be %lu", session->operation.op.digest.digest_len); *pulDigestLen = session->operation.op.digest.digest_len; rv = CKR_OK; terminate = false; DOUT; goto c_df_out; } if (*pulDigestLen < session->operation.op.digest.digest_len) { DBG_ERR("pulDigestLen too small, data will not fit, expected = %lu, got " "%lu", session->operation.op.digest.digest_len, *pulDigestLen); *pulDigestLen = session->operation.op.digest.digest_len; terminate = false; rv = CKR_BUFFER_TOO_SMALL; goto c_df_out; } rv = apply_digest_mechanism_finalize(&session->operation); if (rv != CKR_OK) { DBG_ERR("Unable to finalize digest operation"); goto c_df_out; } rv = perform_digest(&session->operation, pDigest, (uint16_t *) pulDigestLen); if (rv != CKR_OK) { DBG_ERR("Unable to digest data"); goto c_df_out; } DBG_INFO("Got %lu bytes back", *pulDigestLen); DOUT; c_df_out: if (session != NULL) { release_session(&g_ctx, session); if (terminate == true) { session->operation.type = OPERATION_NOOP; digest_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_SignInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pMechanism == NULL) { DBG_ERR("Invalid Mechanism"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("Other operation in progress"); rv = CKR_OPERATION_ACTIVE; goto c_si_out; } DBG_INFO("Trying to sign data with mechanism 0x%04lx and key %08lx", pMechanism->mechanism, hKey); int type = hKey >> 16; if (type == ECDH_KEY_TYPE) { DBG_ERR("Signing using an ECDH session key is not supported"); rv = CKR_FUNCTION_NOT_SUPPORTED; goto c_si_out; } yubihsm_pkcs11_object_desc *object = get_object_desc(session->slot, hKey); if (object == NULL) { DBG_ERR("Unable to retrieve object"); rv = CKR_KEY_HANDLE_INVALID; goto c_si_out; } size_t key_length = 0; yh_rc yrc = yh_get_key_bitlength(object->object.algorithm, &key_length); if (yrc != YHR_SUCCESS) { DBG_ERR("Unable to get key length: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_si_out; } session->operation.op.sign.key_len = key_length; rv = check_sign_mechanism(session->slot, pMechanism); if (rv != CKR_OK) { DBG_ERR("Signing mechanism 0x%lx not supported", pMechanism->mechanism); goto c_si_out; } session->operation.mechanism.mechanism = pMechanism->mechanism; // TODO(adma): also need to check/copy the // mechanism's parameter, if any if (object->object.type == YH_ASYMMETRIC_KEY) { if (yh_is_rsa(object->object.algorithm)) { if (is_RSA_sign_mechanism(session->operation.mechanism.mechanism)) { DBG_INFO("RSA signature requested"); session->operation.op.sign.sig_len = (session->operation.op.sign.key_len + 7) / 8; if (is_PSS_sign_mechanism(session->operation.mechanism.mechanism)) { if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { DBG_ERR("Length of mechanism parameters does not match expected " "value, " "%lu != %zu", pMechanism->ulParameterLen, sizeof(CK_RSA_PKCS_PSS_PARAMS)); rv = CKR_MECHANISM_PARAM_INVALID; goto c_si_out; } CK_RSA_PKCS_PSS_PARAMS *params = pMechanism->pParameter; // TODO: validate that params->hashAlg matches mechanism if (params->sLen > 0xffff) { DBG_ERR("Salt is too big for device"); rv = CKR_MECHANISM_PARAM_INVALID; goto c_si_out; } session->operation.mechanism.pss.salt_len = params->sLen; switch (params->mgf) { case CKG_MGF1_SHA1: session->operation.mechanism.pss.mgf1Algo = YH_ALGO_MGF1_SHA1; break; case CKG_MGF1_SHA256: session->operation.mechanism.pss.mgf1Algo = YH_ALGO_MGF1_SHA256; break; case CKG_MGF1_SHA384: session->operation.mechanism.pss.mgf1Algo = YH_ALGO_MGF1_SHA384; break; case CKG_MGF1_SHA512: session->operation.mechanism.pss.mgf1Algo = YH_ALGO_MGF1_SHA512; break; default: rv = CKR_MECHANISM_PARAM_INVALID; goto c_si_out; }; } } else { DBG_ERR("Mechanism %lu not supported", session->operation.mechanism.mechanism); rv = CKR_MECHANISM_INVALID; goto c_si_out; } } else if (yh_is_ed(object->object.algorithm)) { if (is_EDDSA_sign_mechanism(session->operation.mechanism.mechanism)) { DBG_INFO("EDDSA signature requested"); session->operation.op.sign.sig_len = ((session->operation.op.sign.key_len + 7) / 8) * 2; } else { DBG_ERR("Mechanism %lu not supported", session->operation.mechanism.mechanism); rv = CKR_MECHANISM_INVALID; goto c_si_out; } } else { if (is_ECDSA_sign_mechanism(session->operation.mechanism.mechanism)) { DBG_INFO("ECDSA signature requested"); session->operation.op.sign.sig_len = ((session->operation.op.sign.key_len + 7) / 8) * 2; } else { DBG_ERR("Mechanism %lu not supported", session->operation.mechanism.mechanism); rv = CKR_MECHANISM_INVALID; goto c_si_out; } } } else if (object->object.type == YH_HMAC_KEY) { if (is_HMAC_sign_mechanism(session->operation.mechanism.mechanism) == true) { DBG_INFO("HMAC signature requested (len %lu)", (unsigned long) (key_length / 8)); session->operation.op.sign.sig_len = (session->operation.op.sign.key_len + 7) / 8; } else { DBG_ERR("Mechanism %lu not supported", session->operation.mechanism.mechanism); rv = CKR_MECHANISM_INVALID; goto c_si_out; } } else { rv = CKR_KEY_TYPE_INCONSISTENT; goto c_si_out; } session->operation.op.sign.key_id = hKey; // TODO(adma): should we store something else rather than the key ID? // TODO(adma): check mechanism parameters and key length and key supported // parameters rv = apply_sign_mechanism_init(&session->operation); if (rv != CKR_OK) { DBG_ERR("Unable to initialize signing operation"); goto c_si_out; } session->operation.type = OPERATION_SIGN; DOUT; c_si_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_Sign) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { DIN; CK_RV rv = CKR_OK; bool terminate = true; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_s_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_s_out; } if (session->operation.type != OPERATION_SIGN) { DBG_ERR("Signature operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_s_out; } DBG_INFO("The size of the signature will be %u", session->operation.op.sign.sig_len); if (pSignature == NULL) { // NOTE(adma): Just return the size of the signature *pulSignatureLen = session->operation.op.sign.sig_len; rv = CKR_OK; terminate = false; DOUT; goto c_s_out; } if (*pulSignatureLen < session->operation.op.sign.sig_len) { DBG_ERR("pulSignatureLen too small, signature will not fit, expected %u, " "got %lu", session->operation.op.sign.sig_len, *pulSignatureLen); *pulSignatureLen = session->operation.op.sign.sig_len; rv = CKR_BUFFER_TOO_SMALL; terminate = false; goto c_s_out; } DBG_INFO("Sending %lu bytes to sign", ulDataLen); rv = apply_sign_mechanism_update(&session->operation, pData, ulDataLen); if (rv != CKR_OK) { DBG_ERR("Unable to perform signing operation step"); goto c_s_out; } rv = apply_sign_mechanism_finalize(&session->operation); if (rv != CKR_OK) { DBG_ERR("Unable to finalize signing operation"); goto c_s_out; } DBG_INFO("Using key %04x", session->operation.op.sign.key_id); DBG_INFO("After padding and transformation there are %u bytes", session->operation.buffer_length); rv = perform_signature(session->slot->device_session, &session->operation, pSignature, (uint16_t *) pulSignatureLen); if (rv != CKR_OK) { DBG_ERR("Unable to sign data"); goto c_s_out; } DBG_INFO("Got %lu bytes back", *pulSignatureLen); DOUT; c_s_out: if (session != NULL) { release_session(&g_ctx, session); if (terminate == true) { session->operation.type = OPERATION_NOOP; sign_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_SignUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { DIN; CK_RV rv = CKR_OK; // TODO(adma): somebody should check that this is a proper mult-part // mechanism/operation yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_su_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_su_out; } if (session->operation.type != OPERATION_SIGN) { DBG_ERR("Signature operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_su_out; } if (pPart == NULL) { DBG_ERR("No data provided"); rv = CKR_ARGUMENTS_BAD; goto c_su_out; } DBG_INFO("Signature update with %lu bytes", ulPartLen); rv = apply_sign_mechanism_update(&session->operation, pPart, ulPartLen); if (rv != CKR_OK) { DBG_ERR("Unable to perform signing operation step"); goto c_su_out; } DOUT; c_su_out: if (session != NULL) { release_session(&g_ctx, session); if (rv != CKR_OK) { session->operation.type = OPERATION_NOOP; sign_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_SignFinal) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { DIN; CK_RV rv = CKR_OK; bool terminate = false; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_sf_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_sf_out; } if (session->operation.type != OPERATION_SIGN) { DBG_ERR("Signature operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_sf_out; } if (pSignature == NULL) { DBG_ERR("No buffer provided, length check only"); *pulSignatureLen = session->operation.op.sign.sig_len; rv = CKR_OK; DOUT; goto c_sf_out; } terminate = true; rv = apply_sign_mechanism_finalize(&session->operation); if (rv != CKR_OK) { DBG_ERR("Unable to finalize signing operation"); goto c_sf_out; } rv = perform_signature(session->slot->device_session, &session->operation, pSignature, (uint16_t *) pulSignatureLen); if (rv != CKR_OK) { DBG_ERR("Unable to sign data"); goto c_sf_out; } DBG_INFO("Got %lu bytes back", *pulSignatureLen); DOUT; c_sf_out: if (session != NULL) { release_session(&g_ctx, session); if (terminate == true) { session->operation.type = OPERATION_NOOP; sign_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_SignRecoverInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { DIN; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_SignRecover) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { DIN; UNUSED(hSession); UNUSED(pData); UNUSED(ulDataLen); UNUSED(pSignature); UNUSED(pulSignatureLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_VerifyInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pMechanism == NULL) { DBG_ERR("Invalid Mechanism"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("Other operation in progress"); rv = CKR_OPERATION_ACTIVE; goto c_vi_out; } DBG_INFO("Trying to verify data with mechanism 0x%04lx and key %lx", pMechanism->mechanism, hKey); int type = hKey >> 16; if (type == ECDH_KEY_TYPE) { DBG_ERR("Wrong key type"); rv = CKR_KEY_TYPE_INCONSISTENT; goto c_vi_out; } yubihsm_pkcs11_object_desc *object = get_object_desc(session->slot, hKey); if (object == NULL) { DBG_ERR("Unable to retrieve object"); rv = CKR_KEY_HANDLE_INVALID; goto c_vi_out; } size_t key_length = 0; yh_rc yrc = yh_get_key_bitlength(object->object.algorithm, &key_length); if (yrc != YHR_SUCCESS) { DBG_ERR("Unable to get key length: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_vi_out; } session->operation.op.verify.key_len = key_length; rv = check_sign_mechanism(session->slot, pMechanism); if (rv != CKR_OK) { DBG_ERR("Verification mechanism 0x%lx not supported", pMechanism->mechanism); goto c_vi_out; } session->operation.mechanism.mechanism = pMechanism->mechanism; // TODO(adma): also need to check/copy the // mechanism's parameter, if any if (object->object.type == YH_HMAC_KEY) { DBG_INFO("HMAC verification requested"); } else if (object->object.type == YH_PUBLIC_KEY) { DBG_INFO("Asymmetric verification requested"); } else { rv = CKR_KEY_TYPE_INCONSISTENT; goto c_vi_out; } session->operation.op.verify.key_id = hKey; rv = apply_verify_mechanism_init(&session->operation); if (rv != CKR_OK) { DBG_ERR("Unable to initialize verification operation"); goto c_vi_out; } if (yh_is_rsa(object->object.algorithm)) { if (is_PSS_sign_mechanism(session->operation.mechanism.mechanism)) { if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { DBG_ERR("Length of mechanism parameters does not match expected value, " "%lu != %zu", pMechanism->ulParameterLen, sizeof(CK_RSA_PKCS_PSS_PARAMS)); rv = CKR_MECHANISM_PARAM_INVALID; goto c_vi_out; } // TODO: validate that params->hashAlg matches mechanism CK_RSA_PKCS_PSS_PARAMS *params = pMechanism->pParameter; session->operation.op.verify.padding = RSA_PKCS1_PSS_PADDING; session->operation.op.verify.saltLen = params->sLen; switch (params->mgf) { case CKG_MGF1_SHA1: session->operation.op.verify.mgf1md = EVP_sha1(); break; case CKG_MGF1_SHA256: session->operation.op.verify.mgf1md = EVP_sha256(); break; case CKG_MGF1_SHA384: session->operation.op.verify.mgf1md = EVP_sha384(); break; case CKG_MGF1_SHA512: session->operation.op.verify.mgf1md = EVP_sha512(); break; default: DBG_ERR("Unsupported mgf algorithm: %lu", params->mgf); rv = CKR_MECHANISM_PARAM_INVALID; goto c_vi_out; } switch (params->hashAlg) { case CKM_SHA_1: session->operation.op.verify.md = EVP_sha1(); break; case CKM_SHA256: session->operation.op.verify.md = EVP_sha256(); break; case CKM_SHA384: session->operation.op.verify.md = EVP_sha384(); break; case CKM_SHA512: session->operation.op.verify.md = EVP_sha512(); break; default: DBG_ERR("Unsupported pss hash algorithm: %lu", params->hashAlg); rv = CKR_MECHANISM_PARAM_INVALID; goto c_vi_out; } } else if (is_PKCS1v1_5_sign_mechanism( session->operation.mechanism.mechanism)) { session->operation.op.verify.padding = RSA_PKCS1_PADDING; } else if (!is_RSA_sign_mechanism(session->operation.mechanism.mechanism)) { DBG_ERR("Unsupported mechanism for RSA key"); rv = CKR_KEY_TYPE_INCONSISTENT; goto c_vi_out; } } else if (yh_is_ec(object->object.algorithm)) { if (!is_ECDSA_sign_mechanism(session->operation.mechanism.mechanism)) { DBG_ERR("Unsupported mechanism for EC key"); rv = CKR_KEY_TYPE_INCONSISTENT; goto c_vi_out; } } else if (yh_is_ed(object->object.algorithm)) { if (!is_EDDSA_sign_mechanism(session->operation.mechanism.mechanism)) { DBG_ERR("Unsupported mechanism for ED key"); rv = CKR_KEY_TYPE_INCONSISTENT; goto c_vi_out; } } else if (yh_is_hmac(object->object.algorithm)) { if (!is_HMAC_sign_mechanism(session->operation.mechanism.mechanism)) { DBG_ERR("Unsupported mechanism for HMAC key"); rv = CKR_KEY_TYPE_INCONSISTENT; goto c_vi_out; } } else { DBG_ERR("Unsupported key type"); rv = CKR_KEY_TYPE_INCONSISTENT; goto c_vi_out; } session->operation.type = OPERATION_VERIFY; DOUT; c_vi_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_Verify) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { DIN; CK_RV rv = CKR_OK; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_v_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_v_out; } if (pData == NULL || pSignature == NULL) { DBG_ERR("Invalid parameters"); rv = CKR_ARGUMENTS_BAD; goto c_v_out; } if (session->operation.type != OPERATION_VERIFY) { DBG_ERR("Verification operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_v_out; } rv = apply_verify_mechanism_update(&session->operation, pData, ulDataLen); if (rv != CKR_OK) { DBG_ERR("Unable to perform verification operation step"); goto c_v_out; } rv = apply_verify_mechanism_finalize(&session->operation, ulSignatureLen); if (rv != CKR_OK) { DBG_ERR("Unable to finalize verification operation"); goto c_v_out; } DBG_INFO("Using key %04x", session->operation.op.verify.key_id); rv = perform_verify(session->slot->device_session, &session->operation, pSignature, ulSignatureLen); if (rv != CKR_OK) { DBG_ERR("Unable to verify signature"); goto c_v_out; } DBG_INFO("Signature successfully verified"); DOUT; c_v_out: if (session != NULL) { release_session(&g_ctx, session); session->operation.type = OPERATION_NOOP; verify_mechanism_cleanup(&session->operation); } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_VerifyUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { DIN; CK_RV rv = CKR_OK; // TODO(adma): somebody should check that this is a proper mult-part // mechanism/operation yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_vu_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_vu_out; } if (session->operation.type != OPERATION_VERIFY) { DBG_ERR("Verification operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_vu_out; } if (pPart == NULL) { DBG_ERR("No data provided"); rv = CKR_ARGUMENTS_BAD; goto c_vu_out; } DBG_INFO("Verification update with %lu bytes", ulPartLen); rv = apply_verify_mechanism_update(&session->operation, pPart, ulPartLen); if (rv != CKR_OK) { DBG_ERR("Unable to perform verification operation step"); goto c_vu_out; } DOUT; c_vu_out: if (session != NULL) { release_session(&g_ctx, session); if (rv != CKR_OK) { session->operation.type = OPERATION_NOOP; verify_mechanism_cleanup(&session->operation); } } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_VerifyFinal) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { DIN; CK_RV rv = CKR_OK; yubihsm_pkcs11_session *session = NULL; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); rv = CKR_CRYPTOKI_NOT_INITIALIZED; goto c_vf_out; } rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { goto c_vf_out; } if (session->operation.type != OPERATION_VERIFY) { DBG_ERR("Verification operation not initialized"); rv = CKR_OPERATION_NOT_INITIALIZED; goto c_vf_out; } if (pSignature == NULL) { DBG_ERR("No buffer provided"); rv = CKR_ARGUMENTS_BAD; goto c_vf_out; } rv = apply_verify_mechanism_finalize(&session->operation, ulSignatureLen); if (rv != CKR_OK) { DBG_ERR("Unable to finalize verification operation"); goto c_vf_out; } rv = perform_verify(session->slot->device_session, &session->operation, pSignature, ulSignatureLen); if (rv != CKR_OK) { DBG_ERR("Unable to verify data"); goto c_vf_out; } DOUT; c_vf_out: if (session != NULL) { release_session(&g_ctx, session); session->operation.type = OPERATION_NOOP; verify_mechanism_cleanup(&session->operation); } return rv; } CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecoverInit) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { DIN; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecover) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { DIN; UNUSED(hSession); UNUSED(pSignature); UNUSED(ulSignatureLen); UNUSED(pData); UNUSED(pulDataLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_DigestEncryptUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { DIN; UNUSED(hSession); UNUSED(pPart); UNUSED(ulPartLen); UNUSED(pEncryptedPart); UNUSED(pulEncryptedPartLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_DecryptDigestUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { DIN; UNUSED(hSession); UNUSED(pEncryptedPart); UNUSED(ulEncryptedPartLen); UNUSED(pPart); UNUSED(pulPartLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_SignEncryptUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { DIN; UNUSED(hSession); UNUSED(pPart); UNUSED(ulPartLen); UNUSED(pEncryptedPart); UNUSED(pulEncryptedPartLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_DecryptVerifyUpdate) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { DIN; UNUSED(hSession); UNUSED(pEncryptedPart); UNUSED(ulEncryptedPartLen); UNUSED(pPart); UNUSED(pulPartLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_GenerateKey) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pMechanism == NULL || pTemplate == NULL || phKey == NULL) { DBG_ERR("Invalid argument"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED_RW); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("A different operation is already active"); rv = CKR_OPERATION_ACTIVE; goto c_gk_out; } if (pMechanism->mechanism != CKM_GENERIC_SECRET_KEY_GEN && pMechanism->mechanism != CKM_AES_KEY_GEN) { DBG_ERR("Invalid mechanism %lu", pMechanism->mechanism); rv = CKR_MECHANISM_INVALID; goto c_gk_out; } yubihsm_pkcs11_object_template template = {0}; pkcs11_meta_object meta_object = {0}; struct { bool set; CK_ULONG d; } class = {0}, key_type = {0}; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_CLASS: if (class.set == false) { class.d = *((CK_ULONG_PTR) pTemplate[i].pValue); class.set = true; } else { rv = CKR_TEMPLATE_INCONSISTENT; goto c_gk_out; } break; case CKA_KEY_TYPE: if (key_type.set == false) { key_type.d = *((CK_ULONG_PTR) pTemplate[i].pValue); key_type.set = true; } else { rv = CKR_TEMPLATE_INCONSISTENT; goto c_gk_out; } break; case CKA_ID: rv = parse_meta_id_template(&template, &meta_object, false, pTemplate[i].pValue, pTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_LABEL: rv = parse_meta_label_template(&template, &meta_object, false, pTemplate[i].pValue, pTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_EXTRACTABLE: if ((rv = set_template_attribute(&template.exportable, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_EXTRACTABLE inconsistent in template"); return rv; } } } if (key_type.set == false || class.set == false) { if (pMechanism->mechanism == CKM_AES_KEY_GEN) { /* attributes given implicitly */ if (!key_type.set) { key_type.d = CKK_AES; key_type.set = true; } if (!class.set) { class.d = CKO_SECRET_KEY; class.set = true; } } else { rv = CKR_TEMPLATE_INCOMPLETE; goto c_gk_out; } } yh_capabilities capabilities = {{0}}; yh_capabilities delegated_capabilities = {{0}}; uint8_t type = 0; yh_rc rc = YHR_SUCCESS; if (template.exportable == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("exportable-under-wrap", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gk_out; } } if (class.d == CKO_SECRET_KEY) { if (key_type.d == CKK_SHA_1_HMAC || key_type.d == CKK_SHA256_HMAC || key_type.d == CKK_SHA384_HMAC || key_type.d == CKK_SHA512_HMAC) { type = YH_HMAC_KEY; rv = parse_hmac_template(pTemplate, ulCount, &template, true); if (rv != CKR_OK) { goto c_gk_out; } if (template.sign == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("sign-hmac", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gk_out; } } if (template.verify == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("verify-hmac", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gk_out; } } rc = yh_util_generate_hmac_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm); if (rc != YHR_SUCCESS) { DBG_ERR("Failed generating HMAC key: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_gk_out; } } else if (key_type.d == CKK_YUBICO_AES128_CCM_WRAP || key_type.d == CKK_YUBICO_AES192_CCM_WRAP || key_type.d == CKK_YUBICO_AES256_CCM_WRAP) { yh_algorithm algo = key_type.d & 0xff; type = YH_WRAP_KEY; rv = parse_wrap_template(pTemplate, ulCount, &template, algo, true); if (rv != CKR_OK) { goto c_gk_out; } DBG_INFO("parsed WRAP key, objlen: %d", template.objlen); rc = set_wrapkey_capabilities(&template, &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gk_out; } rc = yh_string_to_capabilities("all", &delegated_capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gk_out; } rc = yh_util_generate_wrap_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, algo, &delegated_capabilities); if (rc != YHR_SUCCESS) { DBG_ERR("Failed generating wrap key: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_gk_out; } } else if (key_type.d == CKK_AES) { type = YH_SYMMETRIC_KEY; rv = parse_aes_template(pTemplate, ulCount, &template, true); if (rv != CKR_OK) { goto c_gk_out; } if (template.encrypt == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("encrypt-ecb,encrypt-cbc", &capabilities); if (rc != YHR_SUCCESS) { rv = CKR_FUNCTION_FAILED; goto c_gk_out; } } if (template.decrypt == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("decrypt-ecb,decrypt-cbc", &capabilities); if (rc != YHR_SUCCESS) { rv = CKR_FUNCTION_FAILED; goto c_gk_out; } } if (yh_util_generate_aes_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm) != YHR_SUCCESS) { DBG_ERR("Failed generating symmetric key"); rv = CKR_FUNCTION_FAILED; goto c_gk_out; } } else { DBG_ERR("Unknown key_type: %lx", class.d); rv = CKR_ATTRIBUTE_VALUE_INVALID; goto c_gk_out; } } else { rv = CKR_TEMPLATE_INCONSISTENT; goto c_gk_out; } yubihsm_pkcs11_object_desc *object_desc = _get_object_desc(session->slot, template.id, type, 0xffff); if (object_desc == NULL) { DBG_ERR("Failed getting new object %04x: %s", template.id, yh_strerror(rc)); rv = CKR_OBJECT_HANDLE_INVALID; goto c_gk_out; } yh_object_descriptor *object = &object_desc->object; *phKey = object->sequence << 24 | object->type << 16 | object->id; if (meta_object.cka_id.len > 0 || meta_object.cka_label.len > 0) { meta_object.target_id = object->id; meta_object.target_type = object->type; meta_object.target_sequence = object->sequence; rv = write_meta_object(session->slot, &meta_object, &capabilities, object->domains, false); if (rv != CKR_OK) { DBG_ERR("Failed writing meta opaque object to device 0x%lx. Note that " "the original object has been successfully generated in the " "device but without the expected CKA_ID and/or CKA_LABEL.", rv); goto c_gk_out; } } DBG_INFO("Created object %08lx", *phKey); DOUT; c_gk_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pMechanism == NULL || pPublicKeyTemplate == NULL || pPrivateKeyTemplate == NULL || phPublicKey == NULL || phPrivateKey == NULL) { DBG_ERR("Invalid argument"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED_RW); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("A different operation is already active"); rv = CKR_OPERATION_ACTIVE; goto c_gkp_out; } yubihsm_pkcs11_object_template template = {0}; pkcs11_meta_object meta_object = {0}; if (pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN) { rv = parse_rsa_generate_template(pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, &template, &meta_object); } else if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN) { rv = parse_ec_generate_template(pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, &template, &meta_object); } else if (pMechanism->mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN) { rv = parse_ed_generate_template(pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, &template, &meta_object); } else { DBG_ERR("Invalid mechanism for key generation: %lu", pMechanism->mechanism); rv = CKR_MECHANISM_INVALID; goto c_gkp_out; } if (rv != CKR_OK) { DBG_ERR("Unable to parse generation template"); goto c_gkp_out; } yh_capabilities capabilities = {{0}}; yh_rc rc = YHR_SUCCESS; if (template.exportable == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("exportable-under-wrap", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gkp_out; } } // TODO(adma): check more return values if (yh_is_rsa(template.algorithm)) { if (template.unwrap == ATTRIBUTE_TRUE) { // This is a wrap key DBG_INFO("CKA_UNWRAP was set. Generating RSA wrap key..."); rc = set_wrapkey_capabilities(&template, &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gkp_out; } yh_capabilities delegated_capabilities = {{0}}; rc = yh_string_to_capabilities("all", &delegated_capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gkp_out; } rc = yh_util_generate_wrap_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm, &delegated_capabilities); } else { DBG_INFO("Generating RSA asymmetric key..."); if (template.sign == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("sign-pkcs,sign-pss", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gkp_out; } } if (template.decrypt == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gkp_out; } } rc = yh_util_generate_rsa_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm); } if (rc != YHR_SUCCESS) { DBG_ERR("Failed generating RSA key on device: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_gkp_out; } } else if (yh_is_ed(template.algorithm)) { if (template.sign == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("sign-eddsa", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gkp_out; } } rc = yh_util_generate_ed_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm); if (rc != YHR_SUCCESS) { DBG_ERR("Failed generating ED key on device"); rv = yrc_to_rv(rc); goto c_gkp_out; } } else { if (template.sign == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("sign-ecdsa", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gkp_out; } } if (template.derive == ATTRIBUTE_TRUE) { rc = yh_string_to_capabilities("derive-ecdh", &capabilities); if (rc != YHR_SUCCESS) { rv = yrc_to_rv(rc); goto c_gkp_out; } } rc = yh_util_generate_ec_key(session->slot->device_session, &template.id, template.label, 0xffff, &capabilities, template.algorithm); if (rc != YHR_SUCCESS) { DBG_ERR("Failed generating EC key on device: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_gkp_out; } } yubihsm_pkcs11_object_desc *object_desc = NULL; if (template.unwrap == ATTRIBUTE_TRUE) { object_desc = _get_object_desc(session->slot, template.id, YH_WRAP_KEY, 0xffff); } else { object_desc = _get_object_desc(session->slot, template.id, YH_ASYMMETRIC_KEY, 0xffff); } if (object_desc == NULL) { rv = CKR_OBJECT_HANDLE_INVALID; goto c_gkp_out; } yh_object_descriptor *object = &object_desc->object; if (meta_object.cka_id.len > 0 || meta_object.cka_label.len > 0 || meta_object.cka_id_pubkey.len > 0 || meta_object.cka_label_pubkey.len > 0) { meta_object.target_id = object->id; meta_object.target_type = object->type; meta_object.target_sequence = object->sequence; rv = write_meta_object(session->slot, &meta_object, &capabilities, object->domains, false); if (rv != CKR_OK) { DBG_ERR("Failed writing meta opaque object to device 0x%lx. Note that " "the original object has been successfully generated in the " "device but without the expected CKA_ID and/or CKA_LABEL.", rv); goto c_gkp_out; } } *phPublicKey = object->sequence << 24 | (object->type | 0x80) << 16 | object->id; *phPrivateKey = object->sequence << 24 | object->type << 16 | object->id; DOUT; c_gkp_out: insecure_memzero(&template, sizeof(template)); release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_WrapKey) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pMechanism == NULL || pulWrappedKeyLen == NULL) { DBG_ERR("Invalid argument"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } int wrapped_key_type = hKey >> 16; int wrapping_key_type = hWrappingKey >> 16; if (wrapped_key_type == ECDH_KEY_TYPE || wrapping_key_type == ECDH_KEY_TYPE) { DBG_ERR("Wrapping involving ECDH session keys is not supported"); rv = CKR_FUNCTION_NOT_SUPPORTED; goto c_wk_out; } yubihsm_pkcs11_object_desc *object = get_object_desc(session->slot, hKey); if (object == NULL) { DBG_ERR("Wrapped key not found"); rv = CKR_KEY_HANDLE_INVALID; goto c_wk_out; } // NOTE: pWrappedKey is NULL so we just return the length we need if (pWrappedKey == NULL) { *pulWrappedKeyLen = YH_MSG_BUF_SIZE; // CKM_YUBICO_AES_CCM_WRAP len = sizeof(yh_object_descriptor) + // object->object.len + YH_CCM_WRAP_OVERHEAD; DBG_INFO("Wrapping will need maximum of %lu bytes", *pulWrappedKeyLen); rv = CKR_OK; goto c_wk_out; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("A different operation is already active"); rv = CKR_OPERATION_ACTIVE; goto c_wk_out; } rv = check_wrap_mechanism(session->slot, pMechanism); if (rv != CKR_OK) { DBG_ERR("Wrapping mechanism 0x%lx not supported", pMechanism->mechanism); goto c_wk_out; } yubihsm_pkcs11_object_desc *key = get_object_desc(session->slot, hWrappingKey); if (key == NULL) { DBG_ERR("No wrap key found"); rv = CKR_WRAPPING_KEY_HANDLE_INVALID; goto c_wk_out; } if (yh_check_capability(&key->object.capabilities, "export-wrapped") == false) { DBG_ERR("Wrap key does not have \"export-wrapped\" set"); rv = CKR_WRAPPING_KEY_TYPE_INCONSISTENT; // TODO: say something better? goto c_wk_out; } if (yh_check_capability(&object->object.capabilities, "exportable-under-wrap") == false) { DBG_ERR("Key to be wrapped does not have \"exportable-under-wrap\" set"); rv = CKR_KEY_UNEXTRACTABLE; goto c_wk_out; } size_t len = *pulWrappedKeyLen; yh_rc yrc = YHR_SUCCESS; if (pMechanism->mechanism == CKM_YUBICO_AES_CCM_WRAP) { if (pMechanism->pParameter && pMechanism->ulParameterLen != sizeof(CKM_YUBICO_AES_CCM_WRAP_PARAMS)) { DBG_ERR("Wrong mechanism parameter length"); rv = CKR_MECHANISM_PARAM_INVALID; goto c_wk_out; } CKM_YUBICO_AES_CCM_WRAP_PARAMS *params = pMechanism->pParameter; CK_ULONG format = 0; // None = Do not include seed if (params != NULL) { format = params->format; } yrc = yh_util_export_wrapped_ex(session->slot->device_session, key->object.id, object->object.type, object->object.id, format, pWrappedKey, &len); } else { // CKM_RSA_AES_KEY_WRAP or CKM_YUBICO_RSA_WRAP if (pMechanism->pParameter == NULL || pMechanism->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS)) { DBG_ERR("Wrong mechanism parameter length"); rv = CKR_MECHANISM_PARAM_INVALID; goto c_wk_out; } rsa_aes_key_wrap_params_t params = {0}; rv = parse_rsa_aes_key_wrap_params(pMechanism->pParameter, ¶ms); if (rv != CKR_OK) { goto c_wk_out; } if (pMechanism->mechanism == CKM_RSA_AES_KEY_WRAP) { yrc = yh_util_get_rsa_wrapped_key(session->slot->device_session, key->object.id, object->object.type, object->object.id, params.aes_algo, params.oaep_params.oaep_algo, params.oaep_params.mgf_algo, params.oaep_params.oaep_label, params.oaep_params.oaep_label_len, pWrappedKey, &len); } else { // CKM_YUBICO_RSA_WRAP yrc = yh_util_export_rsa_wrapped(session->slot->device_session, key->object.id, object->object.type, object->object.id, params.aes_algo, params.oaep_params.oaep_algo, params.oaep_params.mgf_algo, params.oaep_params.oaep_label, params.oaep_params.oaep_label_len, pWrappedKey, &len); } } if (yrc != YHR_SUCCESS) { DBG_ERR("Wrapping failed: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_wk_out; } *pulWrappedKeyLen = len; DOUT; c_wk_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_UnwrapKey) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) { DBG_ERR("Invalid argument"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } if (session->operation.type != OPERATION_NOOP) { DBG_ERR("A different operation is already active"); rv = CKR_OPERATION_ACTIVE; goto c_uk_out; } int unwrapping_key_type = hUnwrappingKey >> 16; if (unwrapping_key_type == ECDH_KEY_TYPE) { DBG_ERR("Unwrapping using ECDH session key is not supported"); rv = CKR_FUNCTION_NOT_SUPPORTED; goto c_uk_out; } rv = check_wrap_mechanism(session->slot, pMechanism); if (rv != CKR_OK) { DBG_ERR("Wrapping mechanism 0x%lx not supported", pMechanism->mechanism); goto c_uk_out; } yubihsm_pkcs11_object_desc *key = get_object_desc(session->slot, hUnwrappingKey); if (key == NULL) { DBG_ERR("No wrap key found"); rv = CKR_UNWRAPPING_KEY_HANDLE_INVALID; goto c_uk_out; } if (yh_check_capability(&key->object.capabilities, "import-wrapped") == false) { DBG_ERR("Wrap key can't unwrap"); rv = CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; // TODO: say something better? goto c_uk_out; } uint16_t target_id = 0; yh_object_type target_type = 0; yh_rc yrc = YHR_SUCCESS; if (pMechanism->mechanism == CKM_YUBICO_AES_CCM_WRAP) { yrc = yh_util_import_wrapped(session->slot->device_session, key->object.id, pWrappedKey, ulWrappedKeyLen, &target_type, &target_id); } else { // CKM_RSA_AES_KEY_WRAP or CKM_YUBICO_RSA_WRAP if (pMechanism->pParameter == NULL || pMechanism->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS)) { DBG_ERR("Wrong mechanism parameter length"); rv = CKR_MECHANISM_PARAM_INVALID; goto c_uk_out; } rsa_aes_key_wrap_params_t params = {0}; rv = parse_rsa_aes_key_wrap_params(pMechanism->pParameter, ¶ms); if (rv != CKR_OK) { goto c_uk_out; } if (pMechanism->mechanism == CKM_YUBICO_RSA_WRAP) { yrc = yh_util_import_rsa_wrapped(session->slot->device_session, key->object.id, params.oaep_params.oaep_algo, params.oaep_params.mgf_algo, params.oaep_params.oaep_label, params.oaep_params.oaep_label_len, pWrappedKey, ulWrappedKeyLen, &target_type, &target_id); } else { // CKM_RSA_AES_KEY_WRAP pkcs11_meta_object pkcs11meta; yubihsm_pkcs11_object_template object_template = {0}; rv = parse_rsa_wrappedkey_template(pTemplate, ulAttributeCount, &object_template, &pkcs11meta, (CK_BYTE *) &target_type); if (rv != CKR_OK) { DBG_ERR("Failed to parse wrapped key template"); goto c_uk_out; } yh_capabilities capabilities = {{0}}; if (object_template.exportable == ATTRIBUTE_TRUE) { yrc = yh_string_to_capabilities("exportable-under-wrap", &capabilities); if (yrc != YHR_SUCCESS) { rv = yrc_to_rv(yrc); goto c_uk_out; } } if (object_template.sign == ATTRIBUTE_TRUE) { if (yh_is_rsa(object_template.algorithm)) { yrc = yh_string_to_capabilities("sign-pkcs,sign-pss", &capabilities); if (yrc != YHR_SUCCESS) { rv = yrc_to_rv(yrc); goto c_uk_out; } } else if (yh_is_ec(object_template.algorithm)) { yrc = yh_string_to_capabilities("sign-ecdsa", &capabilities); if (yrc != YHR_SUCCESS) { rv = yrc_to_rv(yrc); goto c_uk_out; } } else if (yh_is_ed(object_template.algorithm)) { yrc = yh_string_to_capabilities("sign-eddsa", &capabilities); if (yrc != YHR_SUCCESS) { rv = yrc_to_rv(yrc); goto c_uk_out; } } else { DBG_ERR( "Key type unsupported for unwrap or for signing capabilities"); rv = CKR_TEMPLATE_INCONSISTENT; goto c_uk_out; } } if (object_template.decrypt == ATTRIBUTE_TRUE) { if (yh_is_rsa(object_template.algorithm)) { yrc = yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep", &capabilities); if (yrc != YHR_SUCCESS) { rv = yrc_to_rv(yrc); goto c_uk_out; } } else if (yh_is_aes(object_template.algorithm)) { if (object_template.decrypt == ATTRIBUTE_TRUE) { yrc = yh_string_to_capabilities("decrypt-ecb,decrypt-cbc", &capabilities); if (yrc != YHR_SUCCESS) { rv = CKR_FUNCTION_FAILED; goto c_uk_out; } } } else { DBG_ERR( "Key type unsupported for unwrap or for decryptions capabilities"); rv = CKR_TEMPLATE_INCONSISTENT; goto c_uk_out; } } if (object_template.encrypt == ATTRIBUTE_TRUE) { if (!yh_is_aes(object_template.algorithm)) { DBG_ERR( "Key type unsupported for unwrap or for encryption capabilities"); rv = CKR_TEMPLATE_INCONSISTENT; goto c_uk_out; } yrc = yh_string_to_capabilities("encrypt-ecb,encrypt-cbc", &capabilities); if (yrc != YHR_SUCCESS) { rv = CKR_FUNCTION_FAILED; goto c_uk_out; } } if (object_template.derive == ATTRIBUTE_TRUE) { if (!yh_is_ec(object_template.algorithm)) { DBG_ERR("Key type unsupported for unwrap or for ECDH derivation " "capabilities"); rv = CKR_TEMPLATE_INCONSISTENT; goto c_uk_out; } yrc = yh_string_to_capabilities("derive-ecdh", &capabilities); if (yrc != YHR_SUCCESS) { rv = yrc_to_rv(yrc); goto c_uk_out; } } yrc = yh_util_put_rsa_wrapped_key(session->slot->device_session, key->object.id, target_type, &target_id, object_template.algorithm, object_template.label, 0xffff, &capabilities, params.oaep_params.oaep_algo, params.oaep_params.mgf_algo, params.oaep_params.oaep_label, params.oaep_params.oaep_label_len, pWrappedKey, ulWrappedKeyLen); } } if (yrc != YHR_SUCCESS) { DBG_ERR("Unwrapping failed: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_uk_out; } yubihsm_pkcs11_object_desc *object_desc = _get_object_desc(session->slot, target_id, target_type, 0xffff); if (object_desc == NULL) { DBG_ERR("Failed executing get object info after creating: id 0x%x", target_id); rv = CKR_OBJECT_HANDLE_INVALID; goto c_uk_out; } yh_object_descriptor *object = &object_desc->object; *phKey = object->sequence << 24 | object->type << 16 | object->id; DBG_INFO("Unwrapped object %08lx", *phKey); DOUT; c_uk_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_DeriveKey) (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } if (pMechanism == NULL || phKey == NULL) { DBG_ERR("Invalid argument"); rv = CKR_ARGUMENTS_BAD; goto c_drv_out; } if (pMechanism->mechanism != CKM_ECDH1_DERIVE || pMechanism->pParameter == NULL) { DBG_ERR("Invalid mechanism for key generation: %lu", pMechanism->mechanism); rv = CKR_MECHANISM_INVALID; goto c_drv_out; } CK_ULONG basekey_type = hBaseKey >> 16; if (basekey_type == ECDH_KEY_TYPE) { DBG_ERR("Cannot derive a session key from another session key"); rv = CKR_ARGUMENTS_BAD; goto c_drv_out; } char *label = NULL; size_t label_len = 0; size_t value_len = 0; for (CK_ULONG i = 0; i < ulAttributeCount; i++) { switch (pTemplate[i].type) { case CKA_VALUE_LEN: if (pTemplate[i].ulValueLen < sizeof(CK_ULONG)) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto c_drv_out; } value_len = *((CK_ULONG *) pTemplate[i].pValue); break; case CKA_LABEL: if (pTemplate[i].ulValueLen > YH_OBJ_LABEL_LEN) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto c_drv_out; } label = pTemplate[i].pValue; label_len = pTemplate[i].ulValueLen; break; default: rv = validate_derive_key_attribute(pTemplate[i].type, pTemplate[i].pValue); if (rv != CKR_OK) { goto c_drv_out; } break; } } CK_ECDH1_DERIVE_PARAMS *params = pMechanism->pParameter; if (params->kdf == CKD_NULL && ((params->pSharedData != NULL) || (params->ulSharedDataLen != 0))) { DBG_ERR("Mechanism parameters incompatible with key derivation function"); rv = CKR_MECHANISM_PARAM_INVALID; goto c_drv_out; } int seq = session->ecdh_session_keys.length + 1; if (seq > MAX_ECDH_SESSION_KEYS) { DBG_ERR("There are already %d ECDH keys available for this session. " "Cannot derive more", MAX_ECDH_SESSION_KEYS); rv = CKR_FUNCTION_REJECTED; goto c_drv_out; } ecdh_session_key ecdh_key = {0}; ecdh_key.id = ECDH_KEY_TYPE << 16 | seq; ecdh_key.len = sizeof(ecdh_key.ecdh_key); DBG_INFO("ecdh_key.id = %lu", ecdh_key.id); if (value_len > ecdh_key.len) { DBG_ERR("Requested derived key is too long"); rv = CKR_ATTRIBUTE_VALUE_INVALID; goto c_drv_out; } // Read the base key as the private keyID uint16_t privkey_id = hBaseKey & 0xffff; yh_rc rc = yh_util_derive_ecdh(session->slot->device_session, privkey_id, params->pPublicData, params->ulPublicDataLen, ecdh_key.ecdh_key, &ecdh_key.len); if (rc != YHR_SUCCESS) { DBG_ERR("Unable to derive raw ECDH key: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_drv_out; } DBG_INFO("ECDH ecdh_key.len = %zu", ecdh_key.len); rv = ecdh_with_kdf(&ecdh_key, params->pSharedData, params->ulSharedDataLen, params->kdf, value_len); if (rv != CKR_OK) { DBG_ERR("Failed to derive ECDH key with KDF %lu", params->kdf); goto c_drv_out; } DBG_INFO("KDF ecdh_key.len = %zu", ecdh_key.len); if (value_len > 0) { if (ecdh_key.len < value_len) { DBG_ERR("Failed to derive a key with the requested length"); rv = CKR_DATA_LEN_RANGE; goto c_drv_out; } if (ecdh_key.len > value_len) { // Truncate from the left size_t offset = ecdh_key.len - value_len; memmove(ecdh_key.ecdh_key, ecdh_key.ecdh_key + offset, value_len); memset(ecdh_key.ecdh_key + value_len, 0, offset); ecdh_key.len = value_len; DBG_INFO("Truncated ecdh_key.len = %zu", ecdh_key.len); } } memcpy(ecdh_key.label, label, label_len); // Copy the derived key as a session object list_append(&session->ecdh_session_keys, &ecdh_key); // Clear the derived key insecure_memzero(ecdh_key.ecdh_key, sizeof(ecdh_key.ecdh_key)); *phKey = ecdh_key.id; DBG_INFO("Created object %04lx", *phKey); DOUT; c_drv_out: release_session(&g_ctx, session); return rv; } /* Random number generation functions */ CK_DEFINE_FUNCTION(CK_RV, C_SeedRandom) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) { DIN; UNUSED(hSession); UNUSED(pSeed); UNUSED(ulSeedLen); DOUT; return CKR_RANDOM_SEED_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_GenerateRandom) (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } size_t len = ulRandomLen; if (len != ulRandomLen || pRandomData == NULL) { DBG_ERR("Invalid parameter"); return CKR_ARGUMENTS_BAD; } yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_AUTHENTICATED); if (rv != CKR_OK) { return rv; } // the OpenSC pkcs11 test calls with 0 and expects CKR_OK, do that.. if (len != 0) { yh_rc rc = yh_util_get_pseudo_random(session->slot->device_session, ulRandomLen, pRandomData, &len); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to get random data: %s", yh_strerror(rc)); rv = yrc_to_rv(rc); goto c_gr_out; } } if (len != ulRandomLen) { DBG_ERR("Incorrect amount of data returned"); rv = CKR_DATA_LEN_RANGE; goto c_gr_out; } DOUT; c_gr_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionStatus) (CK_SESSION_HANDLE hSession) { DIN; UNUSED(hSession); DOUT; return CKR_FUNCTION_NOT_PARALLEL; } CK_DEFINE_FUNCTION(CK_RV, C_CancelFunction)(CK_SESSION_HANDLE hSession) { DIN; UNUSED(hSession); DOUT; return CKR_FUNCTION_NOT_PARALLEL; } /* C_GetInterfaceList returns all the interfaces supported by the module*/ CK_DEFINE_FUNCTION(CK_RV, C_GetInterfaceList) (CK_INTERFACE_PTR pInterfacesList, /* returned interfaces */ CK_ULONG_PTR pulCount /* number of interfaces returned */ ) { yh_dbg_init(false, false, 0, "stderr"); DIN; CK_RV rv = CKR_OK; if (!pulCount) { DBG_ERR("C_GetInterfaceList called with pulCount = NULL"); rv = CKR_ARGUMENTS_BAD; goto out; } if (pInterfacesList) { if (*pulCount < sizeof(interfaces_list) / sizeof(interfaces_list[0])) { DBG_ERR("C_GetInterfaceList called with *pulCount = %lu", *pulCount); *pulCount = sizeof(interfaces_list) / sizeof(interfaces_list[0]); rv = CKR_BUFFER_TOO_SMALL; goto out; } memcpy(pInterfacesList, interfaces_list, sizeof(interfaces_list)); } *pulCount = sizeof(interfaces_list) / sizeof(interfaces_list[0]); out: DOUT; return rv; } /* C_GetInterface returns a specific interface from the module. */ CK_DEFINE_FUNCTION(CK_RV, C_GetInterface) (CK_UTF8CHAR_PTR pInterfaceName, /* name of the interface */ CK_VERSION_PTR pVersion, /* version of the interface */ CK_INTERFACE_PTR_PTR ppInterface, /* returned interface */ CK_FLAGS flags /* flags controlling the semantics * of the interface */ ) { yh_dbg_init(false, false, 0, "stderr"); DIN; CK_RV rv = CKR_FUNCTION_FAILED; if (!ppInterface) { DBG_ERR("C_GetInterface called with ppInterface = NULL"); rv = CKR_ARGUMENTS_BAD; goto out; } size_t i; for (i = 0; i < sizeof(interfaces_list) / sizeof(interfaces_list[0]); i++) { CK_FUNCTION_LIST_PTR func_list = (CK_FUNCTION_LIST_PTR) interfaces_list[i].pFunctionList; if ((flags & interfaces_list[i].flags) != flags) { DBG_INFO("C_GetInterface skipped interface %zu (%s %u.%u) because flags " "was %lu", i, interfaces_list[i].pInterfaceName, func_list->version.major, func_list->version.minor, flags); continue; } if (pVersion && (pVersion->major != func_list->version.major || pVersion->minor != func_list->version.minor)) { DBG_INFO("C_GetInterface skipped interface %zu (%s %u.%u) because " "pVersion was %u.%u", i, interfaces_list[i].pInterfaceName, func_list->version.major, func_list->version.minor, pVersion->major, pVersion->minor); continue; } if (pInterfaceName && strcmp((char *) pInterfaceName, (char *) interfaces_list[i].pInterfaceName)) { DBG_INFO("C_GetInterface skipped interface %zu (%s %u.%u) because " "pInterfacename was %s", i, interfaces_list[i].pInterfaceName, func_list->version.major, func_list->version.minor, pInterfaceName); continue; } DBG_INFO("C_GetInterface selected interface %zu (%s %u.%u)", i, interfaces_list[i].pInterfaceName, func_list->version.major, func_list->version.minor); *ppInterface = (CK_INTERFACE_PTR) &interfaces_list[i]; rv = CKR_OK; break; } out: DOUT; return rv; } CK_DEFINE_FUNCTION(CK_RV, C_LoginUser) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_USER_TYPE userType, /* the user type */ CK_UTF8CHAR_PTR pPin, /* the user's PIN */ CK_ULONG ulPinLen, /* the length of the PIN */ CK_UTF8CHAR_PTR pUsername, /* the user's name */ CK_ULONG ulUsernameLen /*the length of the user's name */ ) { DIN; if (g_yh_initialized == false) { DBG_ERR("libyubihsm is not initialized or already finalized"); return CKR_CRYPTOKI_NOT_INITIALIZED; } if (userType != CKU_USER) { DBG_ERR("Inalid user type, only regular user allowed"); return CKR_USER_TYPE_INVALID; } if (pPin == NULL) { DBG_ERR("Invalid argument pPin"); return CKR_ARGUMENTS_BAD; } if (pUsername == NULL) { DBG_ERR("Invalid argument pUsername"); return CKR_ARGUMENTS_BAD; } if (ulPinLen < YUBIHSM_PKCS11_MIN_PIN_LEN || ulPinLen > YUBIHSM_PKCS11_MAX_PIN_LEN) { DBG_ERR("Wrong PIN length, must be [%u, %u] got %lu", YUBIHSM_PKCS11_MIN_PIN_LEN, YUBIHSM_PKCS11_MAX_PIN_LEN, ulPinLen); return CKR_ARGUMENTS_BAD; } CK_UTF8CHAR prefix = *pUsername; if (prefix == '@') { pUsername++; ulUsernameLen--; } if (ulUsernameLen != 4) { DBG_ERR("Wrong username length, must be 4 got %lu", ulUsernameLen); return CKR_ARGUMENTS_BAD; } uint16_t key_id = 0; size_t key_id_len = sizeof(key_id); char tmpUser[5] = {0}; memcpy(tmpUser, pUsername, 4); if (hex_decode((const char *) tmpUser, (uint8_t *) &key_id, &key_id_len) == false || key_id_len != sizeof(key_id)) { DBG_ERR( "PIN contains invalid characters, first four digits must be [0-9A-Fa-f]"); return CKR_PIN_INCORRECT; } key_id = ntohs(key_id); yubihsm_pkcs11_session *session = 0; CK_RV rv = get_session(&g_ctx, hSession, &session, SESSION_NOT_AUTHENTICATED); if (rv != CKR_OK) { return rv; } yh_rc yrc = YHR_SUCCESS; if (prefix == '@') { // Asymmetric authentication uint8_t sk_oce[YH_EC_P256_PRIVKEY_LEN], pk_oce[YH_EC_P256_PUBKEY_LEN], pk_sd[YH_EC_P256_PUBKEY_LEN]; size_t pk_sd_len = sizeof(pk_sd); yrc = yh_util_derive_ec_p256_key(pPin, ulPinLen, sk_oce, sizeof(sk_oce), pk_oce, sizeof(pk_oce)); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to derive asymmetric key: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_l_out; } yrc = yh_util_get_device_pubkey(session->slot->connector, pk_sd, &pk_sd_len, NULL); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to get device public key: %s", yh_strerror(yrc)); rv = yrc_to_rv(yrc); goto c_l_out; } if (pk_sd_len != YH_EC_P256_PUBKEY_LEN) { DBG_ERR("Invalid device public key"); rv = CKR_DATA_LEN_RANGE; goto c_l_out; } int hits = 0; for (ListItem *item = g_ctx.device_pubkeys.head; item != NULL; item = item->next) { if (!memcmp(item->data, pk_sd, YH_EC_P256_PUBKEY_LEN)) { hits++; } } if (g_ctx.device_pubkeys.length > 0 && hits == 0) { DBG_ERR("Failed to validate device public key"); rv = CKR_DATA_LEN_RANGE; goto c_l_out; } yrc = yh_create_session_asym(session->slot->connector, key_id, sk_oce, sizeof(sk_oce), pk_sd, pk_sd_len, &session->slot->device_session); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to create asymmetric session: %s", yh_strerror(yrc)); if (yrc == YHR_SESSION_AUTHENTICATION_FAILED) { rv = CKR_PIN_INCORRECT; } else { rv = yrc_to_rv(yrc); } goto c_l_out; } } else { // Symmetric authentication yrc = yh_create_session_derived(session->slot->connector, key_id, pPin, ulPinLen, true, &session->slot->device_session); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to create session: %s", yh_strerror(yrc)); if (yrc == YHR_CRYPTOGRAM_MISMATCH || yrc == YHR_DEVICE_AUTHENTICATION_FAILED) { rv = CKR_PIN_INCORRECT; } else { rv = yrc_to_rv(yrc); } goto c_l_out; } yrc = yh_authenticate_session(session->slot->device_session); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to authenticate session: %s", yh_strerror(yrc)); if (yrc == YHR_CRYPTOGRAM_MISMATCH) { rv = CKR_PIN_INCORRECT; } else { rv = yrc_to_rv(yrc); } goto c_l_out; } } list_iterate(&session->slot->pkcs11_sessions, login_sessions); populate_cache_with_data_opaques(session->slot); #ifndef FUZZING yubihsm_pkcs11_object_desc *authkey_desc = _get_object_desc(session->slot, key_id, YH_AUTHENTICATION_KEY, 0xffff); if (authkey_desc == NULL) { DBG_ERR("Failed to read authentication key info."); goto c_l_out; } session->slot->authkey_domains = authkey_desc->object.domains; #else session->slot->authkey_domains = 0xffff; #endif DOUT; c_l_out: release_session(&g_ctx, session); return rv; } CK_DEFINE_FUNCTION(CK_RV, C_SessionCancel) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_FLAGS flags /* flags control which sessions are cancelled */ ) { DIN; UNUSED(hSession); UNUSED(flags); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_MessageEncryptInit) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */ CK_OBJECT_HANDLE hKey /* handle of encryption key */ ) { DIN; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_EncryptMessage) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ CK_ULONG ulAssociatedDataLen, /* AEAD Associated data length */ CK_BYTE_PTR pPlaintext, /* plain text */ CK_ULONG ulPlaintextLen, /* plain text length */ CK_BYTE_PTR pCiphertext, /* gets cipher text */ CK_ULONG_PTR pulCiphertextLen /* gets cipher text length */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); UNUSED(pPlaintext); UNUSED(ulPlaintextLen); UNUSED(pCiphertext); UNUSED(pulCiphertextLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_EncryptMessageBegin) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ CK_ULONG ulAssociatedDataLen /* AEAD Associated data length */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_EncryptMessageNext) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pPlaintextPart, /* plain text */ CK_ULONG ulPlaintextPartLen, /* plain text length */ CK_BYTE_PTR pCiphertextPart, /* gets cipher text */ CK_ULONG_PTR pulCiphertextPartLen, /* gets cipher text length */ CK_FLAGS flags /* multi mode flag */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pPlaintextPart); UNUSED(ulPlaintextPartLen); UNUSED(pCiphertextPart); UNUSED(pulCiphertextPartLen); UNUSED(flags); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_MessageEncryptFinal) (CK_SESSION_HANDLE hSession /* the session's handle */ ) { DIN; UNUSED(hSession); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_MessageDecryptInit) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */ CK_OBJECT_HANDLE hKey /* handle of decryption key */ ) { DIN; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_DecryptMessage) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ CK_ULONG ulAssociatedDataLen, /* AEAD Associated data length */ CK_BYTE_PTR pCiphertext, /* cipher text */ CK_ULONG ulCiphertextLen, /* cipher text length */ CK_BYTE_PTR pPlaintext, /* gets plain text */ CK_ULONG_PTR pulPlaintextLen /* gets plain text length */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); UNUSED(pCiphertext); UNUSED(ulCiphertextLen); UNUSED(pPlaintext); UNUSED(pulPlaintextLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_DecryptMessageBegin) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ CK_ULONG ulAssociatedDataLen /* AEAD Associated data length */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pAssociatedData); UNUSED(ulAssociatedDataLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_DecryptMessageNext) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pCiphertext, /* cipher text */ CK_ULONG ulCiphertextLen, /* cipher text length */ CK_BYTE_PTR pPlaintext, /* gets plain text */ CK_ULONG_PTR pulPlaintextLen, /* gets plain text length */ CK_FLAGS flags /* multi mode flag */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pCiphertext); UNUSED(ulCiphertextLen); UNUSED(pPlaintext); UNUSED(pulPlaintextLen); UNUSED(flags); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_MessageDecryptFinal) (CK_SESSION_HANDLE hSession /* the session's handle */ ) { DIN; UNUSED(hSession); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_MessageSignInit) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the signing mechanism */ CK_OBJECT_HANDLE hKey /* handle of signing key */ ) { DIN; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_SignMessage) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pData, /* data to sign */ CK_ULONG ulDataLen, /* data to sign length */ CK_BYTE_PTR pSignature, /* gets signature */ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pData); UNUSED(ulDataLen); UNUSED(pSignature); UNUSED(pulSignatureLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_SignMessageBegin) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen /* length of message specific parameter */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_SignMessageNext) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pData, /* data to sign */ CK_ULONG ulDataLen, /* data to sign length */ CK_BYTE_PTR pSignature, /* gets signature */ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pData); UNUSED(ulDataLen); UNUSED(pSignature); UNUSED(pulSignatureLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_MessageSignFinal) (CK_SESSION_HANDLE hSession /* the session's handle */ ) { DIN; UNUSED(hSession); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_MessageVerifyInit) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the signing mechanism */ CK_OBJECT_HANDLE hKey /* handle of signing key */ ) { DIN; UNUSED(hSession); UNUSED(pMechanism); UNUSED(hKey); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_VerifyMessage) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pData, /* data to sign */ CK_ULONG ulDataLen, /* data to sign length */ CK_BYTE_PTR pSignature, /* signature */ CK_ULONG ulSignatureLen /* signature length */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pData); UNUSED(ulDataLen); UNUSED(pSignature); UNUSED(ulSignatureLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_VerifyMessageBegin) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen /* length of message specific parameter */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_VerifyMessageNext) (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pData, /* data to sign */ CK_ULONG ulDataLen, /* data to sign length */ CK_BYTE_PTR pSignature, /* signature */ CK_ULONG ulSignatureLen /* signature length */ ) { DIN; UNUSED(hSession); UNUSED(pParameter); UNUSED(ulParameterLen); UNUSED(pData); UNUSED(ulDataLen); UNUSED(pSignature); UNUSED(ulSignatureLen); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } CK_DEFINE_FUNCTION(CK_RV, C_MessageVerifyFinal) (CK_SESSION_HANDLE hSession /* the session's handle */ ) { DIN; UNUSED(hSession); DOUT; return CKR_FUNCTION_NOT_SUPPORTED; } static const CK_FUNCTION_LIST function_list = { {CRYPTOKI_LEGACY_VERSION_MAJOR, CRYPTOKI_LEGACY_VERSION_MINOR}, C_Initialize, C_Finalize, C_GetInfo, C_GetFunctionList, C_GetSlotList, C_GetSlotInfo, C_GetTokenInfo, C_GetMechanismList, C_GetMechanismInfo, C_InitToken, C_InitPIN, C_SetPIN, C_OpenSession, C_CloseSession, C_CloseAllSessions, C_GetSessionInfo, C_GetOperationState, C_SetOperationState, C_Login, C_Logout, C_CreateObject, C_CopyObject, C_DestroyObject, C_GetObjectSize, C_GetAttributeValue, C_SetAttributeValue, C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal, C_EncryptInit, C_Encrypt, C_EncryptUpdate, C_EncryptFinal, C_DecryptInit, C_Decrypt, C_DecryptUpdate, C_DecryptFinal, C_DigestInit, C_Digest, C_DigestUpdate, C_DigestKey, C_DigestFinal, C_SignInit, C_Sign, C_SignUpdate, C_SignFinal, C_SignRecoverInit, C_SignRecover, C_VerifyInit, C_Verify, C_VerifyUpdate, C_VerifyFinal, C_VerifyRecoverInit, C_VerifyRecover, C_DigestEncryptUpdate, C_DecryptDigestUpdate, C_SignEncryptUpdate, C_DecryptVerifyUpdate, C_GenerateKey, C_GenerateKeyPair, C_WrapKey, C_UnwrapKey, C_DeriveKey, C_SeedRandom, C_GenerateRandom, C_GetFunctionStatus, C_CancelFunction, C_WaitForSlotEvent, }; static const CK_FUNCTION_LIST_3_0 function_list_3 = { {CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR}, C_Initialize, C_Finalize, C_GetInfo_3_0, C_GetFunctionList, C_GetSlotList, C_GetSlotInfo, C_GetTokenInfo, C_GetMechanismList, C_GetMechanismInfo, C_InitToken, C_InitPIN, C_SetPIN, C_OpenSession, C_CloseSession, C_CloseAllSessions, C_GetSessionInfo, C_GetOperationState, C_SetOperationState, C_Login, C_Logout, C_CreateObject, C_CopyObject, C_DestroyObject, C_GetObjectSize, C_GetAttributeValue, C_SetAttributeValue, C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal, C_EncryptInit, C_Encrypt, C_EncryptUpdate, C_EncryptFinal, C_DecryptInit, C_Decrypt, C_DecryptUpdate, C_DecryptFinal, C_DigestInit, C_Digest, C_DigestUpdate, C_DigestKey, C_DigestFinal, C_SignInit, C_Sign, C_SignUpdate, C_SignFinal, C_SignRecoverInit, C_SignRecover, C_VerifyInit, C_Verify, C_VerifyUpdate, C_VerifyFinal, C_VerifyRecoverInit, C_VerifyRecover, C_DigestEncryptUpdate, C_DecryptDigestUpdate, C_SignEncryptUpdate, C_DecryptVerifyUpdate, C_GenerateKey, C_GenerateKeyPair, C_WrapKey, C_UnwrapKey, C_DeriveKey, C_SeedRandom, C_GenerateRandom, C_GetFunctionStatus, C_CancelFunction, C_WaitForSlotEvent, C_GetInterfaceList, C_GetInterface, C_LoginUser, C_SessionCancel, C_MessageEncryptInit, C_EncryptMessage, C_EncryptMessageBegin, C_EncryptMessageNext, C_MessageEncryptFinal, C_MessageDecryptInit, C_DecryptMessage, C_DecryptMessageBegin, C_DecryptMessageNext, C_MessageDecryptFinal, C_MessageSignInit, C_SignMessage, C_SignMessageBegin, C_SignMessageNext, C_MessageSignFinal, C_MessageVerifyInit, C_VerifyMessage, C_VerifyMessageBegin, C_VerifyMessageNext, C_MessageVerifyFinal, }; yubihsm-shell-2.7.3/pkcs11/version.rc.in0000644000175000017500000000211415167357110017014 0ustar aveenaveen #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM PKCS11 Module" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "yubihsm_pkcs11.dll" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "yubihsm_pkcs11.dll" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.7.3/pkcs11/util_pkcs11.c0000644000175000017500000054461015167357110016713 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "../common/platform-config.h" #include "../common/util.h" #include "../common/time_win.h" #include "../common/hash.h" #ifdef __WIN32 #include #else #include #include #endif #include #include #include #include #include #include "util_pkcs11.h" #include "debug_p11.h" #include "../common/openssl-compat.h" #include "../common/insecure_memzero.h" #define UNUSED(x) (void) (x) #define ASN1_OCTET_STRING 0x04 #define ASN1_OID 0x06 #define ASN1_PRINTABLE_STRING 0x13 static const uint8_t oid_secp224r1[] = {ASN1_OID, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x21}; static const uint8_t oid_secp256r1[] = {ASN1_OID, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; static const uint8_t oid_secp384r1[] = {ASN1_OID, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22}; static const uint8_t oid_secp521r1[] = {ASN1_OID, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23}; static const uint8_t oid_secp256k1[] = {ASN1_OID, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x0a}; static const uint8_t oid_brainpool256r1[] = {ASN1_OID, 0x09, 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}; static const uint8_t oid_brainpool384r1[] = {ASN1_OID, 0x09, 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0b}; static const uint8_t oid_brainpool512r1[] = {ASN1_OID, 0x09, 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0d}; static const uint8_t oid_ed25519[] = {ASN1_PRINTABLE_STRING, 0x0c, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64, 0x73, 0x32, 0x35, 0x35, 0x31, 0x39}; CK_RV yrc_to_rv(yh_rc rc) { switch (rc) { case YHR_SUCCESS: return CKR_OK; case YHR_MEMORY_ERROR: return CKR_HOST_MEMORY; case YHR_INIT_ERROR: return CKR_GENERAL_ERROR; case YHR_CONNECTION_ERROR: return CKR_DEVICE_REMOVED; case YHR_CONNECTOR_NOT_FOUND: return CKR_TOKEN_NOT_PRESENT; case YHR_INVALID_PARAMETERS: return CKR_ARGUMENTS_BAD; case YHR_WRONG_LENGTH: return CKR_DATA_LEN_RANGE; case YHR_BUFFER_TOO_SMALL: return CKR_BUFFER_TOO_SMALL; case YHR_CRYPTOGRAM_MISMATCH: return CKR_ENCRYPTED_DATA_INVALID; case YHR_SESSION_AUTHENTICATION_FAILED: return CKR_ENCRYPTED_DATA_INVALID; case YHR_MAC_MISMATCH: return CKR_ENCRYPTED_DATA_INVALID; case YHR_DEVICE_OK: return CKR_OK; case YHR_DEVICE_INVALID_COMMAND: return CKR_DEVICE_ERROR; case YHR_DEVICE_INVALID_DATA: return CKR_DEVICE_ERROR; case YHR_DEVICE_INVALID_SESSION: return CKR_SESSION_CLOSED; case YHR_DEVICE_AUTHENTICATION_FAILED: return CKR_DEVICE_ERROR; case YHR_DEVICE_SESSIONS_FULL: return CKR_SESSION_COUNT; case YHR_DEVICE_SESSION_FAILED: return CKR_DEVICE_ERROR; case YHR_DEVICE_STORAGE_FAILED: return CKR_DEVICE_MEMORY; case YHR_DEVICE_WRONG_LENGTH: return CKR_DATA_LEN_RANGE; case YHR_DEVICE_INSUFFICIENT_PERMISSIONS: return CKR_FUNCTION_REJECTED; case YHR_DEVICE_LOG_FULL: return CKR_DEVICE_MEMORY; case YHR_DEVICE_OBJECT_NOT_FOUND: return CKR_OBJECT_HANDLE_INVALID; case YHR_DEVICE_INVALID_ID: return CKR_OBJECT_HANDLE_INVALID; case YHR_DEVICE_INVALID_OTP: return CKR_DEVICE_ERROR; case YHR_DEVICE_DEMO_MODE: return CKR_FUNCTION_REJECTED; case YHR_DEVICE_COMMAND_UNEXECUTED: return CKR_DEVICE_ERROR; case YHR_GENERIC_ERROR: return CKR_FUNCTION_FAILED; case YHR_DEVICE_OBJECT_EXISTS: return CKR_ATTRIBUTE_VALUE_INVALID; case YHR_CONNECTOR_ERROR: return CKR_DEVICE_REMOVED; case YHR_DEVICE_SSH_CA_CONSTRAINT_VIOLATION: return CKR_FUNCTION_REJECTED; case YHR_DEVICE_ALGORITHM_DISABLED: return CKR_FUNCTION_REJECTED; default: return CKR_GENERAL_ERROR; } } static CK_ULONG encode_length(CK_BYTE_PTR buffer, CK_ULONG length) { if (length < 0x80) { *buffer++ = length; return 1; } else if (length < 0x100) { *buffer++ = 0x81; *buffer++ = length; return 2; } else { *buffer++ = 0x82; *buffer++ = (length >> 8) & 0xff; *buffer++ = length & 0xff; return 3; } } static bool find_mech(CK_MECHANISM_TYPE_PTR buf, CK_ULONG count, CK_MECHANISM_TYPE item) { for (CK_ULONG i = 0; i < count; i++) { if (buf[i] == item) { return true; } } return false; } static void add_mech(CK_MECHANISM_TYPE_PTR buf, CK_ULONG_PTR count, CK_MECHANISM_TYPE item) { if (find_mech(buf, *count, item)) { return; } buf[*count] = item; *count = *count + 1; } CK_RV set_operation_part(yubihsm_pkcs11_op_info *op_info, yubihsm_pkcs11_part_type part) { if (part == PART_INIT || op_info->part == PART_INIT || op_info->part == part) { op_info->part = part; return CKR_OK; } return CKR_OPERATION_ACTIVE; } CK_RV get_mechanism_list(yubihsm_pkcs11_slot *slot, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR count) { // NOTE: this is a bit hardcoded, but much more than what we might add below. CK_MECHANISM_TYPE buffer[128] = {0}; CK_ULONG items = 0; for (size_t i = 0; i < slot->connector->device_info.n_algorithms; i++) { switch (slot->connector->device_info.algorithms[i]) { case YH_ALGO_RSA_PKCS1_SHA1: add_mech(buffer, &items, CKM_RSA_PKCS); add_mech(buffer, &items, CKM_SHA1_RSA_PKCS); break; case YH_ALGO_RSA_PKCS1_SHA256: add_mech(buffer, &items, CKM_RSA_PKCS); add_mech(buffer, &items, CKM_SHA256_RSA_PKCS); break; case YH_ALGO_RSA_PKCS1_SHA384: add_mech(buffer, &items, CKM_RSA_PKCS); add_mech(buffer, &items, CKM_SHA384_RSA_PKCS); break; case YH_ALGO_RSA_PKCS1_SHA512: add_mech(buffer, &items, CKM_RSA_PKCS); add_mech(buffer, &items, CKM_SHA512_RSA_PKCS); break; case YH_ALGO_RSA_PSS_SHA1: add_mech(buffer, &items, CKM_RSA_PKCS_PSS); add_mech(buffer, &items, CKM_SHA1_RSA_PKCS_PSS); break; case YH_ALGO_RSA_PSS_SHA256: add_mech(buffer, &items, CKM_RSA_PKCS_PSS); add_mech(buffer, &items, CKM_SHA256_RSA_PKCS_PSS); break; case YH_ALGO_RSA_PSS_SHA384: add_mech(buffer, &items, CKM_RSA_PKCS_PSS); add_mech(buffer, &items, CKM_SHA384_RSA_PKCS_PSS); break; case YH_ALGO_RSA_PSS_SHA512: add_mech(buffer, &items, CKM_RSA_PKCS_PSS); add_mech(buffer, &items, CKM_SHA512_RSA_PKCS_PSS); break; case YH_ALGO_RSA_2048: case YH_ALGO_RSA_3072: case YH_ALGO_RSA_4096: add_mech(buffer, &items, CKM_RSA_PKCS_KEY_PAIR_GEN); break; case YH_ALGO_EC_P224: case YH_ALGO_EC_P256: case YH_ALGO_EC_P384: case YH_ALGO_EC_P521: case YH_ALGO_EC_K256: case YH_ALGO_EC_BP256: case YH_ALGO_EC_BP384: case YH_ALGO_EC_BP512: add_mech(buffer, &items, CKM_EC_KEY_PAIR_GEN); break; case YH_ALGO_EC_ED25519: add_mech(buffer, &items, CKM_EDDSA); add_mech(buffer, &items, CKM_EC_EDWARDS_KEY_PAIR_GEN); break; case YH_ALGO_HMAC_SHA1: add_mech(buffer, &items, CKM_SHA_1_HMAC); add_mech(buffer, &items, CKM_GENERIC_SECRET_KEY_GEN); break; case YH_ALGO_HMAC_SHA256: add_mech(buffer, &items, CKM_SHA256_HMAC); add_mech(buffer, &items, CKM_GENERIC_SECRET_KEY_GEN); break; case YH_ALGO_HMAC_SHA384: add_mech(buffer, &items, CKM_SHA384_HMAC); add_mech(buffer, &items, CKM_GENERIC_SECRET_KEY_GEN); break; case YH_ALGO_HMAC_SHA512: add_mech(buffer, &items, CKM_SHA512_HMAC); add_mech(buffer, &items, CKM_GENERIC_SECRET_KEY_GEN); break; case YH_ALGO_EC_ECDSA_SHA1: add_mech(buffer, &items, CKM_ECDSA); add_mech(buffer, &items, CKM_ECDSA_SHA1); break; case YH_ALGO_EC_ECDSA_SHA256: add_mech(buffer, &items, CKM_ECDSA); add_mech(buffer, &items, CKM_ECDSA_SHA256); break; case YH_ALGO_EC_ECDSA_SHA384: add_mech(buffer, &items, CKM_ECDSA); add_mech(buffer, &items, CKM_ECDSA_SHA384); break; case YH_ALGO_EC_ECDSA_SHA512: add_mech(buffer, &items, CKM_ECDSA); add_mech(buffer, &items, CKM_ECDSA_SHA512); break; case YH_ALGO_EC_ECDH: add_mech(buffer, &items, CKM_ECDH1_DERIVE); break; case YH_ALGO_RSA_OAEP_SHA1: case YH_ALGO_RSA_OAEP_SHA256: case YH_ALGO_RSA_OAEP_SHA384: case YH_ALGO_RSA_OAEP_SHA512: add_mech(buffer, &items, CKM_RSA_PKCS_OAEP); if(find_mech(buffer, items, CKM_AES_KEY_WRAP_KWP)) { add_mech(buffer, &items, CKM_YUBICO_RSA_WRAP); add_mech(buffer, &items, CKM_RSA_AES_KEY_WRAP); } break; case YH_ALGO_AES_KWP: add_mech(buffer, &items, CKM_AES_KEY_WRAP_KWP); if(find_mech(buffer, items, CKM_RSA_PKCS_OAEP)) { add_mech(buffer, &items, CKM_YUBICO_RSA_WRAP); add_mech(buffer, &items, CKM_RSA_AES_KEY_WRAP); } break; case YH_ALGO_AES128_CCM_WRAP: case YH_ALGO_AES192_CCM_WRAP: case YH_ALGO_AES256_CCM_WRAP: add_mech(buffer, &items, CKM_YUBICO_AES_CCM_WRAP); add_mech(buffer, &items, CKM_GENERIC_SECRET_KEY_GEN); break; case YH_ALGO_AES128: case YH_ALGO_AES192: case YH_ALGO_AES256: add_mech(buffer, &items, CKM_AES_KEY_GEN); break; case YH_ALGO_AES_ECB: add_mech(buffer, &items, CKM_AES_ECB); break; case YH_ALGO_AES_CBC: add_mech(buffer, &items, CKM_AES_CBC); add_mech(buffer, &items, CKM_AES_CBC_PAD); break; // NOTE: there are algorithms don't have corresponding mechanisms default: break; } } // NOTE(adma): manually add digest mechanisms add_mech(buffer, &items, CKM_SHA_1); add_mech(buffer, &items, CKM_SHA256); add_mech(buffer, &items, CKM_SHA384); add_mech(buffer, &items, CKM_SHA512); if (pMechanismList != NULL) { if (items > *count) { *count = items; return CKR_BUFFER_TOO_SMALL; } memcpy(pMechanismList, buffer, sizeof(CK_MECHANISM_TYPE) * items); } *count = items; return CKR_OK; } static void find_minmax_rsa_key_length_in_bits(yh_algorithm *algorithms, size_t n_algorithms, CK_ULONG *min, CK_ULONG *max) { *min = 0; *max = 0; for (size_t i = 0; i < n_algorithms; i++) { CK_ULONG size; switch (algorithms[i]) { case YH_ALGO_RSA_2048: size = 2048; break; case YH_ALGO_RSA_3072: size = 3072; break; case YH_ALGO_RSA_4096: size = 4096; break; default: size = 0; } if (size == 0) { continue; } if (*min == 0 || *min > size) { *min = size; } if (size > *max) { *max = size; } } } static void find_minmax_ec_key_length_in_bits(yh_algorithm *algorithms, size_t n_algorithms, CK_ULONG *min, CK_ULONG *max) { *min = 0; *max = 0; for (size_t i = 0; i < n_algorithms; i++) { CK_ULONG size; switch (algorithms[i]) { case YH_ALGO_EC_P224: size = 224; break; case YH_ALGO_EC_P256: case YH_ALGO_EC_K256: case YH_ALGO_EC_BP256: size = 256; break; case YH_ALGO_EC_P384: case YH_ALGO_EC_BP384: size = 384; break; case YH_ALGO_EC_BP512: size = 512; break; case YH_ALGO_EC_P521: size = 521; break; default: size = 0; } if (size == 0) { continue; } if (*min == 0 || *min > size) { *min = size; } if (size > *max) { *max = size; } } } static void find_minmax_aes_key_length_in_bytes(yh_algorithm *algorithms, size_t n_algorithms, CK_ULONG *min, CK_ULONG *max) { *min = 0; *max = 0; for (size_t i = 0; i < n_algorithms; i++) { CK_ULONG size; switch (algorithms[i]) { case YH_ALGO_AES128: size = 16; break; case YH_ALGO_AES192: size = 24; break; case YH_ALGO_AES256: size = 32; break; default: size = 0; break; } if (size == 0) { continue; } if (*min == 0 || *min > size) { *min = size; } if (size > *max) { *max = size; } } } CK_RV get_mechanism_info(yubihsm_pkcs11_slot *slot, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { pInfo->flags = 0; switch (type) { case CKM_RSA_PKCS: pInfo->flags = CKF_DECRYPT | CKF_ENCRYPT; case CKM_SHA1_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: find_minmax_rsa_key_length_in_bits(slot->connector->device_info.algorithms, slot->connector->device_info.n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags |= CKF_HW | CKF_SIGN | CKF_VERIFY; break; case CKM_RSA_PKCS_PSS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: find_minmax_rsa_key_length_in_bits(slot->connector->device_info .algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW | CKF_SIGN | CKF_VERIFY; break; case CKM_RSA_PKCS_OAEP: find_minmax_rsa_key_length_in_bits(slot->connector->device_info .algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW | CKF_DECRYPT | CKF_ENCRYPT; break; case CKM_YUBICO_RSA_WRAP: case CKM_RSA_AES_KEY_WRAP: find_minmax_rsa_key_length_in_bits(slot->connector->device_info .algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW | CKF_WRAP | CKF_UNWRAP; break; case CKM_RSA_PKCS_KEY_PAIR_GEN: find_minmax_rsa_key_length_in_bits(slot->connector->device_info .algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW | CKF_GENERATE_KEY_PAIR; break; case CKM_EC_KEY_PAIR_GEN: find_minmax_ec_key_length_in_bits(slot->connector->device_info.algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_EC_F_P | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS; break; case CKM_EC_EDWARDS_KEY_PAIR_GEN: pInfo->ulMaxKeySize = 255; pInfo->ulMinKeySize = 255; pInfo->flags = CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_EC_F_P | CKF_EC_NAMEDCURVE | CKF_EC_COMPRESS; break; case CKM_EDDSA: pInfo->ulMaxKeySize = 255; pInfo->ulMinKeySize = 255; pInfo->flags = CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P | CKF_EC_NAMEDCURVE | CKF_EC_COMPRESS; break; case CKM_SHA_1_HMAC: pInfo->ulMaxKeySize = 64 * 8; pInfo->ulMinKeySize = 1; pInfo->flags = CKF_HW | CKF_SIGN | CKF_VERIFY; break; case CKM_SHA256_HMAC: pInfo->ulMaxKeySize = 64 * 8; pInfo->ulMinKeySize = 1; pInfo->flags = CKF_HW | CKF_SIGN | CKF_VERIFY; break; case CKM_SHA384_HMAC: pInfo->ulMaxKeySize = 128 * 8; pInfo->ulMinKeySize = 1; pInfo->flags = CKF_HW | CKF_SIGN | CKF_VERIFY; break; case CKM_SHA512_HMAC: pInfo->ulMaxKeySize = 128 * 8; pInfo->ulMinKeySize = 1; pInfo->flags = CKF_HW | CKF_SIGN | CKF_VERIFY; break; case CKM_ECDSA: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: // should all ecdsa mechanisms have all keylengths? or should they be // bounded to length of hash? find_minmax_ec_key_length_in_bits(slot->connector->device_info.algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_F_P | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS; break; case CKM_ECDH1_DERIVE: find_minmax_ec_key_length_in_bits(slot->connector->device_info.algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW | CKF_DERIVE | CKF_EC_F_P | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS; break; case CKM_SHA_1: pInfo->ulMaxKeySize = 0; // NOTE(adma): ignored pInfo->ulMinKeySize = 0; // NOTE(adma): ignored pInfo->flags = CKF_DIGEST; break; case CKM_SHA256: pInfo->ulMaxKeySize = 0; // NOTE(adma): ignored pInfo->ulMinKeySize = 0; // NOTE(adma): ignored pInfo->flags = CKF_DIGEST; break; case CKM_SHA384: pInfo->ulMaxKeySize = 0; // NOTE(adma): ignored pInfo->ulMinKeySize = 0; // NOTE(adma): ignored pInfo->flags = CKF_DIGEST; break; case CKM_SHA512: pInfo->ulMaxKeySize = 0; // NOTE(adma): ignored pInfo->ulMinKeySize = 0; // NOTE(adma): ignored pInfo->flags = CKF_DIGEST; break; case CKM_YUBICO_AES_CCM_WRAP: pInfo->ulMaxKeySize = 256; pInfo->ulMinKeySize = 128; pInfo->flags = CKF_HW | CKF_WRAP | CKF_UNWRAP | CKF_ENCRYPT | CKF_DECRYPT; break; case CKM_GENERIC_SECRET_KEY_GEN: pInfo->ulMaxKeySize = 128 * 8; // NOTE: 128*8 is max key size for sha512-hmac keys pInfo->ulMinKeySize = 1; pInfo->flags = CKF_HW | CKF_GENERATE; break; case CKM_AES_KEY_GEN: find_minmax_aes_key_length_in_bytes(slot->connector->device_info .algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW | CKF_GENERATE; break; case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: find_minmax_aes_key_length_in_bytes(slot->connector->device_info .algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW | CKF_ENCRYPT | CKF_DECRYPT; break; case CKM_AES_KEY_WRAP_KWP: find_minmax_aes_key_length_in_bytes(slot->connector->device_info .algorithms, slot->connector->device_info .n_algorithms, &pInfo->ulMinKeySize, &pInfo->ulMaxKeySize); pInfo->flags = CKF_HW; break; default: DBG_ERR("Invalid mechanism %lu", type); return CKR_MECHANISM_INVALID; } return CKR_OK; } #define PKCS11_ID_TAG 1 #define PKCS11_LABEL_TAG 2 #define PKCS11_PUBKEY_ID_TAG 3 #define PKCS11_PUBKEY_LABEL_TAG 4 const char META_OBJECT_VERSION[5] = "MDB1"; static uint16_t write_meta_item(uint8_t *target_value, uint8_t tag, cka_meta_item *meta_item) { if (meta_item->len == 0) { return 0; } uint8_t *p = target_value; *p++ = tag; *(uint16_t *) p = htons(meta_item->len); p += 2; memcpy(p, &meta_item->value, meta_item->len); return meta_item->len + 3; } static uint16_t read_meta_item(uint8_t *value, cka_meta_item *meta_item) { uint8_t *p = value; meta_item->len = ntohs(*(uint16_t *) p); if (meta_item->len > CKA_ATTRIBUTE_VALUE_SIZE) { DBG_ERR("Parsed meta item length is too long"); return 0; } p += 2; memcpy(&meta_item->value, p, meta_item->len); return meta_item->len + 2; } /* * Meta object value structure: * byte 0-3 : META_OBJECT_VERSION (always present) * byte 4: Original object type (always present) * byte 5 and 6: Original object ID (always present) * byte 7: original object sequence * byte 8 and onward: TLV tripplets */ static CK_RV read_meta_object(yubihsm_pkcs11_slot *slot, uint16_t opaque_id, pkcs11_meta_object *meta_object) { uint8_t opaque_value[YH_MSG_BUF_SIZE] = {0}; size_t opaque_value_len = sizeof(opaque_value); yh_rc yrc = yh_util_get_opaque(slot->device_session, opaque_id, opaque_value, &opaque_value_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to read meta object 0x%x from device", opaque_id); return yrc_to_rv(yrc); } // 4 (version) + 1 (object type) + 2 (id) + 1 (sequence) if (opaque_value_len < 8) { DBG_ERR("Opaque value to import is too small to be a meta obeject data"); return CKR_DATA_INVALID; } uint8_t *p = opaque_value; if (memcmp(p, META_OBJECT_VERSION, strlen(META_OBJECT_VERSION)) != 0) { DBG_ERR("Meta object value has unexpected version"); return CKR_DATA_INVALID; } p += strlen(META_OBJECT_VERSION); meta_object->target_type = *p++; meta_object->target_id = ntohs(*(uint16_t *) p); p += 2; meta_object->target_sequence = *p++; while (p < opaque_value + opaque_value_len) { uint16_t len = 0; switch (*p++) { case PKCS11_ID_TAG: len = read_meta_item(p, &meta_object->cka_id); break; case PKCS11_LABEL_TAG: len = read_meta_item(p, &meta_object->cka_label); break; case PKCS11_PUBKEY_ID_TAG: len = read_meta_item(p, &meta_object->cka_id_pubkey); break; case PKCS11_PUBKEY_LABEL_TAG: len = read_meta_item(p, &meta_object->cka_label_pubkey); break; default: DBG_ERR("Unknown tag in value of opaque PKCS11 object"); return CKR_DATA_INVALID; } if (len == 0) { return CKR_DATA_INVALID; } p += len; } return CKR_OK; } yubihsm_pkcs11_object_desc *_get_object_desc(yubihsm_pkcs11_slot *slot, uint16_t id, uint8_t type, uint16_t sequence) { yubihsm_pkcs11_object_desc *object = NULL; for (uint16_t i = 0; i < YH_MAX_ITEMS_COUNT; i++) { if (slot->objects[i].object.id == id && (slot->objects[i].object.type & 0x7f) == (type & 0x7f)) { object = &slot->objects[i]; if (sequence != 0xffff && object->object.sequence != sequence) { // Force refresh if cache entry has wrong sequence memset(object, 0, sizeof(yubihsm_pkcs11_object_desc)); } break; } } if (!object) { uint16_t low = 0; struct timeval *low_time = NULL; for (uint16_t i = 0; i < YH_MAX_ITEMS_COUNT; i++) { if (slot->objects[i].tv.tv_sec == 0) { low = i; low_time = &slot->objects[i].tv; break; } else { if (!low_time || slot->objects[i].tv.tv_sec < low_time->tv_sec || (slot->objects[i].tv.tv_sec == low_time->tv_sec && slot->objects[i].tv.tv_usec < low_time->tv_usec)) { low_time = &slot->objects[i].tv; low = i; } } } object = &slot->objects[low]; memset(object, 0, sizeof(yubihsm_pkcs11_object_desc)); } if (object->tv.tv_sec == 0) { yh_rc yrc = yh_util_get_object_info(slot->device_session, id, type & 0x7f, &object->object); if (yrc != YHR_SUCCESS) { return NULL; } if (is_meta_object(&object->object)) { // fill in the meta_object value CK_RV rv = read_meta_object(slot, object->object.id, &object->meta_object); if (rv != CKR_OK) { DBG_ERR("Failed to refresh meta object 0x%x", object->object.id); return NULL; } } } object->object.type = type; gettimeofday(&object->tv, NULL); if (sequence != 0xffff && object->object.sequence != sequence) { return NULL; // Only return for correct sequence } return object; } yubihsm_pkcs11_object_desc *get_object_desc(yubihsm_pkcs11_slot *slot, CK_OBJECT_HANDLE objHandle) { uint16_t id = objHandle & 0xffff; uint8_t type = (objHandle >> 16); uint8_t sequence = objHandle >> 24; return _get_object_desc(slot, id, type, sequence); } static bool check_domains(uint16_t subset_domains, yubihsm_pkcs11_slot *slot) { uint16_t authkey_domains = slot->authkey_domains; if (authkey_domains == 0) { yh_object_descriptor authkey = {0}; if (yh_util_get_object_info(slot->device_session, slot->device_session->authkey_id, YH_AUTHENTICATION_KEY, &authkey) != YHR_SUCCESS) { DBG_ERR("Unable to check authentication key domains"); return false; } authkey_domains = authkey.domains; } for (uint16_t i = 0; i < YH_MAX_DOMAINS; i++) { if ((subset_domains & (1 << i)) && !(authkey_domains & (1 << i))) { return false; } } return true; } CK_RV write_meta_object(yubihsm_pkcs11_slot *slot, pkcs11_meta_object *meta_object, yh_capabilities *target_capabilities, uint16_t target_domains, bool replace) { if (!check_domains(target_domains, slot)) { DBG_ERR( "Current user's domain access does not match target_object domains."); return CKR_FUNCTION_REJECTED; } size_t opaque_value_len = 8 /* 4 version + 1 original type + 2 original ID 1 opaque sequence */ + (meta_object->cka_id.len == 0 ? 0 : 3 + meta_object->cka_id.len) + (meta_object->cka_label.len == 0 ? 0 : 3 + meta_object->cka_label.len) + (meta_object->cka_id_pubkey.len == 0 ? 0 : 3 + meta_object->cka_id_pubkey.len) + (meta_object->cka_label_pubkey.len == 0 ? 0 : 3 + meta_object->cka_label_pubkey.len); // 3: 1 tag + 2 value length if (opaque_value_len > (YH_MSG_BUF_SIZE - 20)) { DBG_ERR("Failed to write meta object to device. Meta object too large."); return CKR_DATA_INVALID; } uint8_t opaque_value[YH_MSG_BUF_SIZE] = {0}; uint8_t *p = opaque_value; memcpy(p, META_OBJECT_VERSION, strlen(META_OBJECT_VERSION)); p += strlen(META_OBJECT_VERSION); *p++ = meta_object->target_type; *(uint16_t *) p = htons(meta_object->target_id); p += 2; *p++ = meta_object->target_sequence; p += write_meta_item(p, PKCS11_ID_TAG, &meta_object->cka_id); p += write_meta_item(p, PKCS11_LABEL_TAG, &meta_object->cka_label); p += write_meta_item(p, PKCS11_PUBKEY_ID_TAG, &meta_object->cka_id_pubkey); p += write_meta_item(p, PKCS11_PUBKEY_LABEL_TAG, &meta_object->cka_label_pubkey); char opaque_label[YH_OBJ_LABEL_LEN] = {0}; snprintf(opaque_label, sizeof(opaque_label), "Meta object for 0x%02x%02x%04x", meta_object->target_sequence, meta_object->target_type, meta_object->target_id); yh_rc rc = YHR_SUCCESS; uint16_t meta_object_id = 0; if (replace) { yubihsm_pkcs11_object_desc *meta_desc = find_meta_object_by_target(slot, meta_object->target_id, meta_object->target_type, meta_object->target_sequence, target_domains); if (meta_desc != NULL) { meta_object_id = meta_desc->object.id; rc = yh_util_delete_object(slot->device_session, meta_object_id, YH_OPAQUE); if (rc != YHR_SUCCESS) { DBG_INFO("Failed to delete opaque object 0x%x", meta_object_id); } else { DBG_INFO("Removed opaque object 0x%x with label %s", meta_object_id, opaque_label); } memset(meta_desc, 0, sizeof(yubihsm_pkcs11_object_desc)); } } yh_capabilities capabilities = {{0}}; if (yh_check_capability(target_capabilities, "exportable-under-wrap")) { rc = yh_string_to_capabilities("exportable-under-wrap", &capabilities); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to set meta object capabilities"); return yrc_to_rv(rc); } } rc = yh_util_import_opaque(slot->device_session, &meta_object_id, opaque_label, target_domains, &capabilities, YH_ALGO_OPAQUE_DATA, opaque_value, opaque_value_len); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to import opaque meta object for object 0x%x", meta_object->target_id); return yrc_to_rv(rc); } DBG_INFO("Successfully imported opaque object 0x%x with label: %s", meta_object_id, opaque_label); _get_object_desc(slot, meta_object_id, YH_OPAQUE, 0xffff); return CKR_OK; } bool is_meta_object(yh_object_descriptor *object) { return (object->type == YH_OPAQUE && object->algorithm == YH_ALGO_OPAQUE_DATA && strncmp(object->label, "Meta object", strlen("Meta object")) == 0); } bool match_byte_array(uint8_t *a, uint16_t a_len, uint8_t *b, uint16_t b_len) { return a_len == b_len && memcmp(a, b, a_len) == 0; } CK_RV populate_cache_with_data_opaques(yubihsm_pkcs11_slot *slot) { if (slot == NULL || slot->device_session == NULL) { DBG_INFO("No device session available"); return CKR_OK; } if (slot->objects[0].object.id != 0) { DBG_INFO("Cache already populated"); return CKR_OK; } yh_rc rc = YHR_SUCCESS; yh_object_descriptor opaques[YH_MAX_ITEMS_COUNT] = {0}; size_t n_opaques = YH_MAX_ITEMS_COUNT; yh_capabilities capabilities = {{0}}; rc = yh_util_list_objects(slot->device_session, 0, YH_OPAQUE, 0, &capabilities, YH_ALGO_OPAQUE_DATA, NULL, opaques, &n_opaques); if (rc != YHR_SUCCESS) { DBG_ERR("Failed to get object list"); return yrc_to_rv(rc); } for (size_t i = 0; i < n_opaques; i++) { _get_object_desc(slot, opaques[i].id, opaques[i].type, opaques[i].sequence); } return CKR_OK; } yubihsm_pkcs11_object_desc * find_meta_object_by_target(yubihsm_pkcs11_slot *slot, uint16_t target_id, uint8_t target_type, uint8_t target_sequence, uint16_t target_domains) { for (int i = 0; i < YH_MAX_ITEMS_COUNT; i++) { pkcs11_meta_object *current_meta = &slot->objects[i].meta_object; if (target_domains == slot->objects[i].object.domains && current_meta->target_id == target_id && current_meta->target_type == target_type && current_meta->target_sequence == target_sequence) { return &slot->objects[i]; } } return NULL; } bool create_session(yubihsm_pkcs11_slot *slot, CK_FLAGS flags, CK_SESSION_HANDLE_PTR phSession) { bool authed = false; yubihsm_pkcs11_session session; memset(&session, 0, sizeof(session)); if (slot->pkcs11_sessions.head) { yubihsm_pkcs11_session *s = (yubihsm_pkcs11_session *) slot->pkcs11_sessions.head->data; if (s->session_state & SESSION_AUTHENTICATED) { authed = true; } } if (flags & CKF_RW_SESSION) { session.session_state = authed ? SESSION_AUTHENTICATED_RW : SESSION_RESERVED_RW; } else { session.session_state = authed ? SESSION_AUTHENTICATED_RO : SESSION_RESERVED_RO; } session.id = slot->max_session_id++; session.slot = slot; list_create(&session.ecdh_session_keys, sizeof(ecdh_session_key), NULL); *phSession = (slot->id << 16) + session.id; return list_append(&slot->pkcs11_sessions, &session); } static CK_RV get_label_attribute(yh_object_descriptor *object, bool public, pkcs11_meta_object *meta_object, CK_VOID_PTR value, CK_ULONG_PTR length) { if (meta_object != NULL && !public && meta_object->cka_label.len > 0) { if (*length < meta_object->cka_label.len) { return CKR_HOST_MEMORY; } *length = meta_object->cka_label.len; memcpy(value, meta_object->cka_label.value, *length); } else if (meta_object != NULL && public && meta_object->cka_label_pubkey.len > 0) { if (*length < meta_object->cka_label_pubkey.len) { return CKR_HOST_MEMORY; } *length = meta_object->cka_label_pubkey.len; memcpy(value, meta_object->cka_label_pubkey.value, *length); } else { size_t label_len = strlen(object->label); if (*length < label_len) { return CKR_HOST_MEMORY; } *length = label_len; memcpy(value, object->label, *length); // NOTE(adma): we have seen some weird behvior with different // PKCS#11 tools. We decided not to add '\0' for now. This *seems* // to be a good solution ... } return CKR_OK; } static void get_id_attribute(yh_object_descriptor *object, bool public, pkcs11_meta_object *meta_object, CK_VOID_PTR value, CK_ULONG_PTR length) { if (meta_object != NULL && !public && meta_object->cka_id.len > 0) { *length = meta_object->cka_id.len; memcpy(value, meta_object->cka_id.value, *length); } else if (meta_object != NULL && public && meta_object->cka_id_pubkey.len > 0) { *length = meta_object->cka_id_pubkey.len; memcpy(value, meta_object->cka_id_pubkey.value, *length); } else { uint16_t *ptr = value; *ptr = ntohs(object->id); *length = sizeof(uint16_t); } } static void get_capability_attribute(yh_object_descriptor *object, const char *capability, bool val, CK_VOID_PTR value, CK_ULONG_PTR length, yh_object_type *type) { if ((type == NULL && yh_check_capability(&object->capabilities, capability) == val) || (type != NULL && *type == object->type && yh_check_capability(&object->capabilities, capability) == val)) { *((CK_BBOOL *) value) = CK_TRUE; } else { *((CK_BBOOL *) value) = CK_FALSE; } *length = sizeof(CK_BBOOL); } static CK_RV add_mech_type(CK_BYTE_PTR value, CK_ULONG max, CK_ULONG_PTR length, CK_MECHANISM_TYPE mech) { if(find_mech((CK_MECHANISM_TYPE_PTR)value, *length / sizeof(CK_MECHANISM_TYPE), mech)) { return CKR_OK; } if (*length + sizeof(CK_MECHANISM_TYPE) > max) return CKR_BUFFER_TOO_SMALL; *(CK_MECHANISM_TYPE_PTR)(value + *length) = mech; *length += sizeof(CK_MECHANISM_TYPE); return CKR_OK; } static int compare_mechs(const void *p1, const void *p2) { return *(const CK_MECHANISM_TYPE *) p1 - *(const CK_MECHANISM_TYPE *) p2; } static CK_RV get_allowed_mechs(yh_object_descriptor *object, CK_BYTE_PTR value, CK_ULONG_PTR length) { CK_ULONG max = *length; *length = 0; CK_RV rv; if (yh_is_rsa(object->algorithm)) { if (yh_check_capability(&object->capabilities, "sign-pkcs")) { rv = add_mech_type(value, max, length, CKM_RSA_PKCS); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_SHA1_RSA_PKCS); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_SHA256_RSA_PKCS); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_SHA384_RSA_PKCS); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_SHA512_RSA_PKCS); if (rv != CKR_OK) return rv; } if (yh_check_capability(&object->capabilities, "sign-pss")) { rv = add_mech_type(value, max, length, CKM_RSA_PKCS_PSS); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_SHA1_RSA_PKCS_PSS); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_SHA256_RSA_PKCS_PSS); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_SHA384_RSA_PKCS_PSS); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_SHA512_RSA_PKCS_PSS); if (rv != CKR_OK) return rv; } if (yh_check_capability(&object->capabilities, "decrypt-pkcs")) { rv = add_mech_type(value, max, length, CKM_RSA_PKCS); if (rv != CKR_OK) return rv; } if (yh_check_capability(&object->capabilities, "decrypt-oaep")) { rv = add_mech_type(value, max, length, CKM_RSA_PKCS_OAEP); if (rv != CKR_OK) return rv; } if (yh_check_capability(&object->capabilities, "wrap-data")) { rv = add_mech_type(value, max, length, CKM_RSA_AES_KEY_WRAP); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_YUBICO_RSA_WRAP); if (rv != CKR_OK) return rv; } if (yh_check_capability(&object->capabilities, "unwrap-data")) { rv = add_mech_type(value, max, length, CKM_RSA_AES_KEY_WRAP); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_YUBICO_RSA_WRAP); if (rv != CKR_OK) return rv; } } else if (yh_is_ec(object->algorithm)) { if (yh_check_capability(&object->capabilities, "sign-ecdsa")) { rv = add_mech_type(value, max, length, CKM_ECDSA); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_ECDSA_SHA1); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_ECDSA_SHA256); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_ECDSA_SHA384); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_ECDSA_SHA512); if (rv != CKR_OK) return rv; } if (yh_check_capability(&object->capabilities, "derive-ecdh")) { rv = add_mech_type(value, max, length, CKM_ECDH1_DERIVE); if (rv != CKR_OK) return rv; } } else if (yh_is_aes(object->algorithm)) { if (yh_check_capability(&object->capabilities, "aes-ecb")) { rv = add_mech_type(value, max, length, CKM_AES_ECB); if (rv != CKR_OK) return rv; } if (yh_check_capability(&object->capabilities, "aes-cbc")) { rv = add_mech_type(value, max, length, CKM_AES_CBC); if (rv != CKR_OK) return rv; rv = add_mech_type(value, max, length, CKM_AES_CBC_PAD); if (rv != CKR_OK) return rv; } } else { return CKR_ATTRIBUTE_TYPE_INVALID; } qsort(value, *length / sizeof(CK_MECHANISM_TYPE), sizeof(CK_MECHANISM_TYPE), compare_mechs); return CKR_OK; } static CK_RV get_key_type_attribute(yh_algorithm object_algorithm, CK_KEY_TYPE *value, CK_ULONG_PTR length) { if (yh_is_rsa(object_algorithm)) { *value = CKK_RSA; } else if (yh_is_ec(object_algorithm)) { *value = CKK_EC; } else if (object_algorithm == YH_ALGO_EC_ED25519) { *value = CKK_EC_EDWARDS; } else if (yh_is_aes(object_algorithm)) { *value = CKK_AES; } else if (yh_is_hmac(object_algorithm)) { switch (object_algorithm) { case YH_ALGO_HMAC_SHA1: *value = CKK_SHA_1_HMAC; case YH_ALGO_HMAC_SHA256: *value = CKK_SHA256_HMAC; case YH_ALGO_HMAC_SHA384: *value = CKK_SHA384_HMAC; case YH_ALGO_HMAC_SHA512: *value = CKK_SHA512_HMAC; default: return CKR_FUNCTION_FAILED; } } else { return CKR_FUNCTION_FAILED; } *length = sizeof(*value); return CKR_OK; } static CK_RV get_attribute_opaque(CK_ATTRIBUTE_TYPE type, yh_object_descriptor *object, pkcs11_meta_object *meta_object, CK_VOID_PTR value, CK_ULONG_PTR length, yubihsm_pkcs11_session *session) { if (object->type != YH_OPAQUE) { return CKR_FUNCTION_FAILED; } switch (type) { case CKA_CLASS: if (object->algorithm == YH_ALGO_OPAQUE_X509_CERTIFICATE) { *((CK_OBJECT_CLASS *) value) = CKO_CERTIFICATE; } else { *((CK_OBJECT_CLASS *) value) = CKO_DATA; } *length = sizeof(CK_OBJECT_CLASS); break; // NOTE(adma): Storage Objects attributes case CKA_TOKEN: case CKA_DESTROYABLE: *((CK_BBOOL *) value) = CK_TRUE; *length = sizeof(CK_BBOOL); break; case CKA_PRIVATE: case CKA_SENSITIVE: case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_TRUSTED: *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); break; case CKA_LABEL: return get_label_attribute(object, false, meta_object, value, length); break; case CKA_ID: get_id_attribute(object, false, meta_object, value, length); break; // NOTE(adma): Data Objects attributes case CKA_APPLICATION: { char *str = "Opaque object"; strcpy((char *) value, str); *length = strlen(str); } break; case CKA_OBJECT_ID: *((CK_BYTE_PTR *) value) = NULL; *length = 0; break; case CKA_VALUE: { size_t len = *length; yh_rc yrc = yh_util_get_opaque_ex(session->slot->device_session, object->id, value, &len, NULL, object->algorithm == YH_ALGO_OPAQUE_X509_CERTIFICATE); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } *length = len; } break; case CKA_CERTIFICATE_TYPE: if (object->algorithm == YH_ALGO_OPAQUE_X509_CERTIFICATE) { *((CK_CERTIFICATE_TYPE *) value) = CKC_X_509; *length = sizeof(CK_CERTIFICATE_TYPE); } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; case CKA_SUBJECT: case CKA_ISSUER: case CKA_SERIAL_NUMBER: *((CK_BYTE_PTR *) value) = NULL; *length = 0; break; default: return CKR_ATTRIBUTE_TYPE_INVALID; } return CKR_OK; } static CK_RV get_attribute_secret_key(CK_ATTRIBUTE_TYPE type, yh_object_descriptor *object, pkcs11_meta_object *meta_object, CK_VOID_PTR value, CK_ULONG_PTR length) { yh_object_type objtype; switch (type) { case CKA_CLASS: *((CK_OBJECT_CLASS *) value) = CKO_SECRET_KEY; *length = sizeof(CK_OBJECT_CLASS); break; // NOTE(adma): Storage Objects attributes case CKA_TOKEN: case CKA_PRIVATE: case CKA_DESTROYABLE: *((CK_BBOOL *) value) = CK_TRUE; *length = sizeof(CK_BBOOL); break; case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_ALWAYS_AUTHENTICATE: *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); break; case CKA_LABEL: return get_label_attribute(object, false, meta_object, value, length); break; // NOTE(adma): Key Objects attributes case CKA_KEY_TYPE: return get_key_type_attribute(object->algorithm, value, length); break; case CKA_VALUE_LEN: if (object->type == YH_WRAP_KEY || object->type == YH_SYMMETRIC_KEY || object->type == YH_HMAC_KEY) { size_t key_length = 0; yh_rc yrc = yh_get_key_bitlength(object->algorithm, &key_length); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } *(CK_ULONG_PTR) value = (key_length + 7) / 8; } else { return CKR_ATTRIBUTE_TYPE_INVALID; } *length = sizeof(CK_ULONG); break; case CKA_ID: get_id_attribute(object, false, meta_object, value, length); break; // case CKA_START_DATE: // case CKA_END_DATE: case CKA_DERIVE: case CKA_SIGN_RECOVER: case CKA_VERIFY_RECOVER: *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); break; case CKA_LOCAL: if (object->origin == YH_ORIGIN_GENERATED) { *((CK_BBOOL *) value) = CK_TRUE; } else { *((CK_BBOOL *) value) = CK_FALSE; } *length = sizeof(CK_BBOOL); break; // case CKA_KEY_GEN_MECHANISM: case CKA_ALLOWED_MECHANISMS: return get_allowed_mechs(object, value, length); // NOTE(adma): Secret Key Objects attributes case CKA_SENSITIVE: case CKA_ALWAYS_SENSITIVE: *((CK_BBOOL *) value) = CK_TRUE; *length = sizeof(CK_BBOOL); break; case CKA_SIGN: objtype = YH_HMAC_KEY; get_capability_attribute(object, "sign-hmac", true, value, length, &objtype); break; case CKA_VERIFY: objtype = YH_HMAC_KEY; get_capability_attribute(object, "verify-hmac", true, value, length, &objtype); break; case CKA_DECRYPT: if (object->type == YH_WRAP_KEY) { get_capability_attribute(object, "unwrap-data", true, value, length, NULL); } else if (object->type == YH_SYMMETRIC_KEY) { get_capability_attribute(object, "decrypt-cbc,decrypt-ecb", true, value, length, NULL); } else { *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); } break; case CKA_ENCRYPT: if (object->type == YH_WRAP_KEY) { get_capability_attribute(object, "wrap-data", true, value, length, NULL); } else if (object->type == YH_SYMMETRIC_KEY) { get_capability_attribute(object, "encrypt-cbc,encrypt-ecb", true, value, length, NULL); } else { *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); } break; case CKA_TRUSTED: case CKA_WRAP_WITH_TRUSTED: *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); break; case CKA_WRAP: objtype = YH_WRAP_KEY; get_capability_attribute(object, "export-wrapped", true, value, length, &objtype); break; case CKA_UNWRAP: objtype = YH_WRAP_KEY; get_capability_attribute(object, "import-wrapped", true, value, length, &objtype); break; case CKA_EXTRACTABLE: get_capability_attribute(object, "exportable-under-wrap", true, value, length, NULL); break; case CKA_NEVER_EXTRACTABLE: get_capability_attribute(object, "exportable-under-wrap", false, value, length, NULL); break; case CKA_WRAP_TEMPLATE: case CKA_UNWRAP_TEMPLATE: *((CK_ATTRIBUTE_PTR *) value) = NULL; *length = 0; break; default: return CKR_ATTRIBUTE_TYPE_INVALID; } return CKR_OK; } static CK_RV get_attribute_private_key(CK_ATTRIBUTE_TYPE type, yh_object_descriptor *object, pkcs11_meta_object *meta_object, CK_VOID_PTR value, CK_ULONG_PTR length, yubihsm_pkcs11_session *session) { switch (type) { case CKA_CLASS: *((CK_OBJECT_CLASS *) value) = CKO_PRIVATE_KEY; *length = sizeof(CK_OBJECT_CLASS); break; // NOTE(adma): Storage Objects attributes case CKA_TOKEN: case CKA_PRIVATE: case CKA_DESTROYABLE: *((CK_BBOOL *) value) = CK_TRUE; *length = sizeof(CK_BBOOL); break; case CKA_ENCRYPT: case CKA_MODIFIABLE: case CKA_COPYABLE: *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); break; case CKA_LABEL: return get_label_attribute(object, false, meta_object, value, length); break; // NOTE(adma): Key Objects attributes case CKA_KEY_TYPE: return get_key_type_attribute(object->algorithm, value, length); break; case CKA_ID: get_id_attribute(object, false, meta_object, value, length); break; // case CKA_START_DATE: // case CKA_END_DATE: case CKA_DERIVE: if (object->type == YH_ASYMMETRIC_KEY && yh_is_rsa(object->algorithm) == false && yh_check_capability(&object->capabilities, "derive-ecdh") == true) { *((CK_BBOOL *) value) = CK_TRUE; } else { *((CK_BBOOL *) value) = CK_FALSE; } *length = sizeof(CK_BBOOL); break; case CKA_LOCAL: if (object->origin == YH_ORIGIN_GENERATED) { *((CK_BBOOL *) value) = CK_TRUE; } else { *((CK_BBOOL *) value) = CK_FALSE; } *length = sizeof(CK_BBOOL); break; // case CKA_KEY_GEN_MECHANISM: case CKA_ALLOWED_MECHANISMS: return get_allowed_mechs(object, value, length); // NOTE(adma): Key Objects attributes case CKA_SUBJECT: case CKA_PUBLIC_KEY_INFO: *((CK_BYTE_PTR *) value) = NULL; *length = 0; break; case CKA_SENSITIVE: case CKA_ALWAYS_SENSITIVE: *((CK_BBOOL *) value) = CK_TRUE; *length = sizeof(CK_BBOOL); break; case CKA_DECRYPT: if (object->type == YH_ASYMMETRIC_KEY && yh_is_rsa(object->algorithm)) { get_capability_attribute(object, "decrypt-pkcs,decrypt-oaep", true, value, length, NULL); } else { *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); } break; case CKA_SIGN: if (object->type == YH_ASYMMETRIC_KEY && yh_is_rsa(object->algorithm) == true) { get_capability_attribute(object, "sign-pkcs,sign-pss", true, value, length, NULL); } else if (object->type == YH_ASYMMETRIC_KEY && yh_is_ec(object->algorithm) == true) { get_capability_attribute(object, "sign-ecdsa", true, value, length, NULL); } else if (object->type == YH_ASYMMETRIC_KEY && yh_is_ed(object->algorithm) == true) { get_capability_attribute(object, "sign-eddsa", true, value, length, NULL); } else { *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); } break; case CKA_WRAP: // applicable for RSA wrap keys get_capability_attribute(object, "export-wrapped", true, value, length, NULL); break; case CKA_UNWRAP: // applicable for RSA wrap keys get_capability_attribute(object, "import-wrapped", true, value, length, NULL); break; case CKA_SIGN_RECOVER: case CKA_VERIFY: case CKA_VERIFY_RECOVER: case CKA_WRAP_WITH_TRUSTED: case CKA_ALWAYS_AUTHENTICATE: *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); break; case CKA_EXTRACTABLE: get_capability_attribute(object, "exportable-under-wrap", true, value, length, NULL); break; case CKA_NEVER_EXTRACTABLE: get_capability_attribute(object, "exportable-under-wrap", false, value, length, NULL); break; case CKA_UNWRAP_TEMPLATE: *((CK_ATTRIBUTE_PTR *) value) = NULL; *length = 0; break; case CKA_EC_PARAMS: { const uint8_t *oid; switch (object->algorithm) { case YH_ALGO_EC_P224: oid = oid_secp224r1; *length = sizeof(oid_secp224r1); break; case YH_ALGO_EC_P256: oid = oid_secp256r1; *length = sizeof(oid_secp256r1); break; case YH_ALGO_EC_P384: oid = oid_secp384r1; *length = sizeof(oid_secp384r1); break; case YH_ALGO_EC_P521: oid = oid_secp521r1; *length = sizeof(oid_secp521r1); break; case YH_ALGO_EC_K256: oid = oid_secp256k1; *length = sizeof(oid_secp256k1); break; case YH_ALGO_EC_BP256: oid = oid_brainpool256r1; *length = sizeof(oid_brainpool256r1); break; case YH_ALGO_EC_BP384: oid = oid_brainpool384r1; *length = sizeof(oid_brainpool384r1); break; case YH_ALGO_EC_BP512: oid = oid_brainpool512r1; *length = sizeof(oid_brainpool512r1); break; case YH_ALGO_EC_ED25519: oid = oid_ed25519; *length = sizeof(oid_ed25519); break; default: return CKR_ATTRIBUTE_TYPE_INVALID; } memcpy(value, oid, *length); } break; case CKA_EC_POINT: if (yh_is_ec(object->algorithm)) { uint8_t resp[2048] = {0}; size_t resplen = sizeof(resp); yh_rc yrc = yh_util_get_public_key_ex(session->slot->device_session, object->type, object->id, resp, &resplen, NULL); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } uint8_t *p = value; *p++ = ASN1_OCTET_STRING; p += encode_length(p, resplen + 1); *p++ = 0x04; // UNCOMPRESSED POINT memcpy(p, resp, resplen); p += resplen; *length = p - (uint8_t *) value; } else if (yh_is_ed(object->algorithm)) { uint8_t resp[2048] = {0}; size_t resplen = sizeof(resp); yh_rc yrc = yh_util_get_public_key_ex(session->slot->device_session, object->type, object->id, resp, &resplen, NULL); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } uint8_t *p = value; *p++ = ASN1_OCTET_STRING; p += encode_length(p, resplen); memcpy(p, resp, resplen); p += resplen; *length = p - (uint8_t *) value; } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; case CKA_MODULUS_BITS: if (yh_is_rsa(object->algorithm)) { size_t key_length = 0; yh_rc yrc = yh_get_key_bitlength(object->algorithm, &key_length); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } *(CK_ULONG *) value = key_length; *length = sizeof(CK_ULONG); } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; case CKA_MODULUS: if (yh_is_rsa(object->algorithm)) { uint8_t resp[2048] = {0}; size_t resp_len = sizeof(resp); yh_rc yrc = yh_util_get_public_key_ex(session->slot->device_session, object->type, object->id, resp, &resp_len, NULL); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } *length = resp_len; memcpy(value, resp, *length); } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; case CKA_PUBLIC_EXPONENT: if (yh_is_rsa(object->algorithm)) { uint8_t *p = (uint8_t *) value; p[0] = 0x01; p[1] = 0x00; p[2] = 0x01; *length = 3; } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; case CKA_VALUE: // CKK_EC has the private values in CKA_VALUE case CKA_PRIVATE_EXPONENT: // CKK_RSA has the private exponent in // CKA_PRIVATE_EXPONENT return CKR_ATTRIBUTE_SENSITIVE; default: return CKR_ATTRIBUTE_TYPE_INVALID; } return CKR_OK; } static CK_RV load_public_key(yh_session *session, uint16_t id, uint8_t type, EVP_PKEY **key) { uint8_t data[1024] = {0}; size_t data_len = sizeof(data) - 1; RSA *rsa = NULL; BIGNUM *e = NULL; BIGNUM *n = NULL; EC_KEY *ec_key = NULL; EC_GROUP *ec_group = NULL; EC_POINT *ec_point = NULL; yh_algorithm algo; yh_rc yrc = yh_util_get_public_key_ex(session, type, id, data + 1, &data_len, &algo); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } if (yh_is_rsa(algo)) { rsa = RSA_new(); e = BN_new(); if (rsa == NULL || e == NULL) { goto l_p_k_failure; } BN_set_word(e, 0x010001); n = BN_bin2bn(data + 1, data_len, NULL); if (n == NULL) { goto l_p_k_failure; } if (RSA_set0_key(rsa, n, e, NULL) == 0) { goto l_p_k_failure; } n = NULL; e = NULL; *key = EVP_PKEY_new(); if (*key == NULL) { goto l_p_k_failure; } if (EVP_PKEY_assign_RSA(*key, rsa) == 0) { goto l_p_k_failure; } } else if (yh_is_ec(algo)) { ec_key = EC_KEY_new(); if (ec_key == NULL) { goto l_p_k_failure; } ec_group = EC_GROUP_new_by_curve_name(algo2nid(algo)); if (ec_group == NULL) { goto l_p_k_failure; } // NOTE: this call is important since it makes it a named curve instead of // encoded parameters EC_GROUP_set_asn1_flag(ec_group, OPENSSL_EC_NAMED_CURVE); if (EC_KEY_set_group(ec_key, ec_group) == 0) { goto l_p_k_failure; } ec_point = EC_POINT_new(ec_group); if (ec_point == NULL) { goto l_p_k_failure; } data[0] = 0x04; data_len++; if (EC_POINT_oct2point(ec_group, ec_point, data, data_len, NULL) == 0) { goto l_p_k_failure; } if (EC_KEY_set_public_key(ec_key, ec_point) == 0) { goto l_p_k_failure; } *key = EVP_PKEY_new(); if (*key == NULL) { goto l_p_k_failure; } if (EVP_PKEY_assign_EC_KEY(*key, ec_key) == 0) { goto l_p_k_failure; } EC_POINT_free(ec_point); EC_GROUP_free(ec_group); #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) } else if (yh_is_ed(algo)) { *key = EVP_PKEY_new_raw_public_key(algo2nid(algo), NULL, data + 1, data_len); if (*key == NULL) { goto l_p_k_failure; } #endif } else { DBG_ERR("Unsupported key algorithm"); goto l_p_k_failure; } return CKR_OK; l_p_k_failure: EC_POINT_free(ec_point); EC_GROUP_free(ec_group); EC_KEY_free(ec_key); RSA_free(rsa); BN_free(n); BN_free(e); return CKR_FUNCTION_FAILED; } static CK_RV get_attribute_public_key(CK_ATTRIBUTE_TYPE type, yh_object_descriptor *object, pkcs11_meta_object *meta_object, CK_VOID_PTR value, CK_ULONG_PTR length, yubihsm_pkcs11_session *session) { switch (type) { case CKA_CLASS: *((CK_OBJECT_CLASS *) value) = CKO_PUBLIC_KEY; *length = sizeof(CK_OBJECT_CLASS); break; // NOTE(adma): Storage Objects attributes case CKA_TOKEN: case CKA_DESTROYABLE: case CKA_EXTRACTABLE: *((CK_BBOOL *) value) = CK_TRUE; *length = sizeof(CK_BBOOL); break; case CKA_PRIVATE: case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_DECRYPT: case CKA_DERIVE: case CKA_SENSITIVE: case CKA_ALWAYS_SENSITIVE: case CKA_SIGN: case CKA_SIGN_RECOVER: case CKA_VERIFY_RECOVER: case CKA_UNWRAP: case CKA_WRAP_WITH_TRUSTED: case CKA_ALWAYS_AUTHENTICATE: case CKA_NEVER_EXTRACTABLE: *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); break; case CKA_ENCRYPT: if (object->type == YH_PUBLIC_KEY && yh_is_rsa(object->algorithm)) { get_capability_attribute(object, "decrypt-pkcs,decrypt-oaep", true, value, length, NULL); } else { *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); } break; case CKA_WRAP: if (object->type == YH_PUBLIC_WRAP_KEY) { get_capability_attribute(object, "export-wrapped", true, value, length, NULL); } else { *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); } break; case CKA_VERIFY: if (object->type == YH_PUBLIC_KEY && yh_is_rsa(object->algorithm) == true) { get_capability_attribute(object, "sign-pkcs,sign-pss", true, value, length, NULL); } else if (object->type == YH_PUBLIC_KEY && yh_is_ec(object->algorithm) == true) { get_capability_attribute(object, "sign-ecdsa", true, value, length, NULL); } else if (object->type == (0x80 | YH_ASYMMETRIC_KEY) && yh_is_ed(object->algorithm) == true) { get_capability_attribute(object, "sign-eddsa", true, value, length, NULL); } else { *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); } break; case CKA_LABEL: return get_label_attribute(object, true, meta_object, value, length); break; // NOTE(adma): Key Objects attributes case CKA_KEY_TYPE: return get_key_type_attribute(object->algorithm, value, length); break; case CKA_ID: get_id_attribute(object, true, meta_object, value, length); break; // case CKA_START_DATE: // case CKA_END_DATE: case CKA_LOCAL: if (object->origin == YH_ORIGIN_GENERATED) { *((CK_BBOOL *) value) = CK_TRUE; } else { *((CK_BBOOL *) value) = CK_FALSE; } *length = sizeof(CK_BBOOL); break; // case CKA_KEY_GEN_MECHANISM: case CKA_ALLOWED_MECHANISMS: return get_allowed_mechs(object, value, length); // NOTE(adma): Key Objects attributes case CKA_SUBJECT: case CKA_PUBLIC_KEY_INFO: case CKA_UNWRAP_TEMPLATE: *((CK_BYTE_PTR *) value) = NULL; *length = 0; break; case CKA_EC_PARAMS: { const uint8_t *oid; switch (object->algorithm) { case YH_ALGO_EC_P224: oid = oid_secp224r1; *length = sizeof(oid_secp224r1); break; case YH_ALGO_EC_P256: oid = oid_secp256r1; *length = sizeof(oid_secp256r1); break; case YH_ALGO_EC_P384: oid = oid_secp384r1; *length = sizeof(oid_secp384r1); break; case YH_ALGO_EC_P521: oid = oid_secp521r1; *length = sizeof(oid_secp521r1); break; case YH_ALGO_EC_K256: oid = oid_secp256k1; *length = sizeof(oid_secp256k1); break; case YH_ALGO_EC_BP256: oid = oid_brainpool256r1; *length = sizeof(oid_brainpool256r1); break; case YH_ALGO_EC_BP384: oid = oid_brainpool384r1; *length = sizeof(oid_brainpool384r1); break; case YH_ALGO_EC_BP512: oid = oid_brainpool512r1; *length = sizeof(oid_brainpool512r1); break; case YH_ALGO_EC_ED25519: oid = oid_ed25519; *length = sizeof(oid_ed25519); break; default: return CKR_ATTRIBUTE_TYPE_INVALID; } memcpy(value, oid, *length); break; } case CKA_EC_POINT: if (yh_is_ec(object->algorithm)) { uint8_t resp[2048] = {0}; size_t resplen = sizeof(resp); yh_rc yrc = yh_util_get_public_key_ex(session->slot->device_session, object->type, object->id, resp, &resplen, NULL); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } uint8_t *p = value; *p++ = ASN1_OCTET_STRING; p += encode_length(p, resplen + 1); *p++ = 0x04; // UNCOMPRESSED POINT memcpy(p, resp, resplen); p += resplen; *length = p - (uint8_t *) value; } else if (yh_is_ed(object->algorithm)) { uint8_t resp[2048] = {0}; size_t resplen = sizeof(resp); yh_rc yrc = yh_util_get_public_key_ex(session->slot->device_session, object->type, object->id, resp, &resplen, NULL); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } uint8_t *p = value; *p++ = ASN1_OCTET_STRING; p += encode_length(p, resplen); memcpy(p, resp, resplen); p += resplen; *length = p - (uint8_t *) value; } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; case CKA_MODULUS_BITS: if (yh_is_rsa(object->algorithm)) { size_t key_length = 0; yh_rc yrc = yh_get_key_bitlength(object->algorithm, &key_length); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } *(CK_ULONG *) value = key_length; *length = sizeof(CK_ULONG); } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; case CKA_MODULUS: if (yh_is_rsa(object->algorithm)) { uint8_t resp[2048] = {0}; size_t resp_len = sizeof(resp); yh_rc yrc = yh_util_get_public_key_ex(session->slot->device_session, object->type, object->id, resp, &resp_len, NULL); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } *length = resp_len; memcpy(value, resp, *length); } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; case CKA_PUBLIC_EXPONENT: if (yh_is_rsa(object->algorithm)) { uint8_t *p = (uint8_t *) value; p[0] = 0x01; p[1] = 0x00; p[2] = 0x01; *length = 3; } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; case CKA_VALUE: { EVP_PKEY *pkey = NULL; CK_RV rv = load_public_key(session->slot->device_session, object->id, object->type, &pkey); if (rv != CKR_OK) { EVP_PKEY_free(pkey); return rv; } *length = i2d_PUBKEY(pkey, (unsigned char **) &value); EVP_PKEY_free(pkey); } break; default: return CKR_ATTRIBUTE_TYPE_INVALID; } return CKR_OK; } static CK_RV get_attribute(CK_ATTRIBUTE_TYPE type, yh_object_descriptor *object, CK_BYTE_PTR value, CK_ULONG_PTR length, yubihsm_pkcs11_session *session) { yubihsm_pkcs11_object_desc *meta_desc = find_meta_object_by_target(session->slot, object->id, (object->type & 0x7f), object->sequence, object->domains); pkcs11_meta_object *meta_object = meta_desc ? &meta_desc->meta_object : NULL; switch (object->type) { case YH_OPAQUE: return get_attribute_opaque(type, object, meta_object, value, length, session); case YH_WRAP_KEY: if(yh_is_rsa(object->algorithm)) { return get_attribute_private_key(type, object, meta_object, value, length, session); } else { return get_attribute_secret_key(type, object, meta_object, value, length); } break; case YH_HMAC_KEY: case YH_SYMMETRIC_KEY: return get_attribute_secret_key(type, object, meta_object, value, length); case YH_ASYMMETRIC_KEY: return get_attribute_private_key(type, object, meta_object, value, length, session); case YH_PUBLIC_KEY: case YH_PUBLIC_WRAP_KEY: case YH_WRAP_KEY_PUBLIC: return get_attribute_public_key(type, object, meta_object, value, length, session); case YH_TEMPLATE: case YH_AUTHENTICATION_KEY: case YH_OTP_AEAD_KEY: // TODO: do something good here. break; } // TODO(adma): try to check common attributes in some convenience function return CKR_OK; } static CK_RV get_attribute_ecsession_key(CK_ATTRIBUTE_TYPE type, ecdh_session_key *key, CK_BYTE_PTR value, CK_ULONG_PTR length) { switch (type) { case CKA_CLASS: *((CK_OBJECT_CLASS *) value) = CKO_SECRET_KEY; *length = sizeof(CK_OBJECT_CLASS); break; case CKA_KEY_TYPE: *((CK_KEY_TYPE *) value) = CKK_GENERIC_SECRET; *length = sizeof(CK_KEY_TYPE); break; case CKA_ID: { CK_OBJECT_HANDLE *id = (CK_OBJECT_HANDLE *) value; *id = key->id; *length = sizeof(CK_OBJECT_HANDLE); break; } case CKA_LABEL: *length = strlen(key->label); memcpy(value, key->label, *length); break; case CKA_LOCAL: case CKA_TOKEN: *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); break; case CKA_DESTROYABLE: case CKA_EXTRACTABLE: *((CK_BBOOL *) value) = CK_TRUE; *length = sizeof(CK_BBOOL); break; case CKA_DERIVE: case CKA_NEVER_EXTRACTABLE: case CKA_SENSITIVE: case CKA_ALWAYS_SENSITIVE: case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_SIGN: case CKA_SIGN_RECOVER: case CKA_ALWAYS_AUTHENTICATE: case CKA_UNWRAP: case CKA_WRAP: case CKA_WRAP_WITH_TRUSTED: case CKA_VERIFY: case CKA_ENCRYPT: *((CK_BBOOL *) value) = CK_FALSE; *length = sizeof(CK_BBOOL); break; case CKA_VALUE: memcpy(value, key->ecdh_key, key->len); *length = key->len; break; default: return CKR_ATTRIBUTE_TYPE_INVALID; } return CKR_OK; } CK_RV check_sign_mechanism(yubihsm_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism) { CK_MECHANISM_TYPE mechanisms[128] = {0}; CK_ULONG count = 128; if (!is_RSA_sign_mechanism(pMechanism->mechanism) && !is_ECDSA_sign_mechanism(pMechanism->mechanism) && !is_EDDSA_sign_mechanism(pMechanism->mechanism) && !is_HMAC_sign_mechanism(pMechanism->mechanism)) { return CKR_MECHANISM_INVALID; } CK_RV rv = get_mechanism_list(slot, mechanisms, &count); if (rv != CKR_OK) { return rv; } if (find_mech(mechanisms, count, pMechanism->mechanism)) { return CKR_OK; } return CKR_MECHANISM_INVALID; } CK_RV check_decrypt_mechanism(yubihsm_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism) { CK_MECHANISM_TYPE mechanisms[128] = {0}; CK_ULONG count = 128; if (is_RSA_decrypt_mechanism(pMechanism->mechanism) == false && pMechanism->mechanism != CKM_YUBICO_AES_CCM_WRAP && pMechanism->mechanism != CKM_AES_ECB && pMechanism->mechanism != CKM_AES_CBC && pMechanism->mechanism != CKM_AES_CBC_PAD) { return CKR_MECHANISM_INVALID; } CK_RV rv = get_mechanism_list(slot, mechanisms, &count); if (rv != CKR_OK) { return rv; } if (find_mech(mechanisms, count, pMechanism->mechanism)) { return CKR_OK; } return CKR_MECHANISM_INVALID; } CK_RV check_digest_mechanism(CK_MECHANISM_PTR pMechanism) { switch (pMechanism->mechanism) { case CKM_SHA_1: case CKM_SHA256: case CKM_SHA384: case CKM_SHA512: break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } CK_RV check_wrap_mechanism(yubihsm_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism) { CK_MECHANISM_TYPE mechanisms[128] = {0}; CK_ULONG count = 128; if (pMechanism->mechanism != CKM_YUBICO_AES_CCM_WRAP && pMechanism->mechanism != CKM_YUBICO_RSA_WRAP && pMechanism->mechanism != CKM_RSA_AES_KEY_WRAP) { return CKR_MECHANISM_INVALID; } CK_RV rv = get_mechanism_list(slot, mechanisms, &count); if (rv != CKR_OK) { return rv; } if (find_mech(mechanisms, count, pMechanism->mechanism)) { return CKR_OK; } return CKR_MECHANISM_INVALID; } CK_RV apply_sign_mechanism_init(yubihsm_pkcs11_op_info *op_info) { const EVP_MD *md = NULL; op_info->buffer_length = 0; switch (op_info->mechanism.mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_PSS: case CKM_ECDSA: case CKM_SHA_1_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_EDDSA: // NOTE(adma): no hash required for these mechanisms op_info->op.sign.md_ctx = NULL; return CKR_OK; case CKM_SHA1_RSA_PKCS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_ECDSA_SHA1: md = EVP_sha1(); break; case CKM_SHA256_RSA_PKCS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_ECDSA_SHA256: md = EVP_sha256(); break; case CKM_SHA384_RSA_PKCS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_ECDSA_SHA384: md = EVP_sha384(); break; case CKM_SHA512_RSA_PKCS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_ECDSA_SHA512: md = EVP_sha512(); break; default: DBG_ERR("Mechanism %lu not supported", op_info->mechanism.mechanism); return CKR_MECHANISM_INVALID; } op_info->op.sign.md_ctx = EVP_MD_CTX_create(); if (op_info->op.sign.md_ctx == NULL) { return CKR_HOST_MEMORY; } if (EVP_DigestInit_ex(op_info->op.sign.md_ctx, md, NULL) == 0) { EVP_MD_CTX_destroy(op_info->op.sign.md_ctx); op_info->op.sign.md_ctx = NULL; return CKR_FUNCTION_FAILED; } return CKR_OK; } CK_RV apply_verify_mechanism_init(yubihsm_pkcs11_op_info *op_info) { const EVP_MD *md = NULL; op_info->buffer_length = 0; op_info->op.verify.padding = 0; op_info->op.verify.saltLen = 0; op_info->op.verify.mgf1md = NULL; op_info->op.verify.md = NULL; op_info->op.verify.md_ctx = NULL; switch (op_info->mechanism.mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_PSS: case CKM_ECDSA: case CKM_SHA_1_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_EDDSA: // NOTE(adma): no hash required for these mechanisms return CKR_OK; case CKM_SHA1_RSA_PKCS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_ECDSA_SHA1: md = EVP_sha1(); break; case CKM_SHA256_RSA_PKCS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_ECDSA_SHA256: md = EVP_sha256(); break; case CKM_SHA384_RSA_PKCS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_ECDSA_SHA384: md = EVP_sha384(); break; case CKM_SHA512_RSA_PKCS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_ECDSA_SHA512: md = EVP_sha512(); break; default: DBG_ERR("Mechanism %lu not supported", op_info->mechanism.mechanism); return CKR_MECHANISM_INVALID; } op_info->op.verify.md = md; op_info->op.verify.md_ctx = EVP_MD_CTX_create(); if (op_info->op.verify.md_ctx == NULL) { return CKR_HOST_MEMORY; } if (EVP_DigestInit(op_info->op.verify.md_ctx, md) == 0) { EVP_MD_CTX_destroy(op_info->op.verify.md_ctx); op_info->op.verify.md_ctx = NULL; return CKR_FUNCTION_FAILED; } return CKR_OK; } CK_RV apply_decrypt_mechanism_init(yubihsm_pkcs11_op_info *op_info) { op_info->buffer_length = 0; op_info->op.decrypt.finalized = false; switch (op_info->mechanism.mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: case CKM_YUBICO_AES_CCM_WRAP: case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: return CKR_OK; default: DBG_ERR("Mechanism %lu not supported", op_info->mechanism.mechanism); return CKR_MECHANISM_INVALID; } } CK_RV apply_encrypt_mechanism_init(yubihsm_pkcs11_session *session, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { int type = hKey >> 16; if (type == ECDH_KEY_TYPE) { DBG_ERR("Wrong key type"); return CKR_KEY_TYPE_INCONSISTENT; } yubihsm_pkcs11_object_desc *object = get_object_desc(session->slot, hKey); if (object == NULL) { DBG_ERR("Unable to retrieve object"); return CKR_KEY_HANDLE_INVALID; } session->operation.op.encrypt.oaep_label = NULL; session->operation.op.encrypt.oaep_label_len = 0; session->operation.op.encrypt.oaep_md = NULL; session->operation.op.encrypt.mgf1_md = NULL; session->operation.op.encrypt.key_len = 0; size_t key_length; if (yh_get_key_bitlength(object->object.algorithm, &key_length) != YHR_SUCCESS) { DBG_ERR("Unable to get key length"); return CKR_FUNCTION_FAILED; } session->operation.op.encrypt.key_len = key_length; if (pMechanism->mechanism == CKM_YUBICO_AES_CCM_WRAP) { if (object->object.type != YH_WRAP_KEY) { DBG_ERR("Wrong key type or algorithm"); return CKR_KEY_TYPE_INCONSISTENT; } } else if (pMechanism->mechanism == CKM_RSA_PKCS) { if (object->object.type != YH_PUBLIC_KEY || !yh_is_rsa(object->object.algorithm)) { DBG_ERR("Wrong key type for algorithm"); return CKR_KEY_TYPE_INCONSISTENT; } if (pMechanism->pParameter != NULL) { DBG_ERR("Expecting NULL mechanism parameter for CKM_RSA_PKCS"); return CKR_MECHANISM_PARAM_INVALID; } session->operation.op.encrypt.padding = RSA_PKCS1_PADDING; } else if (pMechanism->mechanism == CKM_RSA_PKCS_OAEP) { if (object->object.type != YH_PUBLIC_KEY || !yh_is_rsa(object->object.algorithm)) { DBG_ERR("Wrong key type for algorithm"); return CKR_KEY_TYPE_INCONSISTENT; } if (pMechanism->pParameter == NULL) { DBG_ERR("Mechanism parameter for CKM_RSA_PKCS_OAEP is NULL"); return CKR_MECHANISM_PARAM_INVALID; } session->operation.op.encrypt.padding = RSA_PKCS1_OAEP_PADDING; if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) { DBG_ERR("Length of mechanism parameters does not match expected value: " "found %lu, expected %zu", pMechanism->ulParameterLen, sizeof(CK_RSA_PKCS_OAEP_PARAMS)); return CKR_MECHANISM_PARAM_INVALID; } CK_RSA_PKCS_OAEP_PARAMS *params = pMechanism->pParameter; if (params->source == 0 && params->ulSourceDataLen != 0) { DBG_ERR("Source parameter empty but sourceDataLen != 0"); return CKR_MECHANISM_PARAM_INVALID; } else if (params->source != 0 && params->source != CKZ_DATA_SPECIFIED) { DBG_ERR("Unknown value in parameter source"); return CKR_MECHANISM_PARAM_INVALID; } DBG_INFO("OAEP params : hashAlg 0x%lx mgf 0x%lx source 0x%lx pSourceData " "%p ulSourceDataLen %lu", params->hashAlg, params->mgf, params->source, params->pSourceData, params->ulSourceDataLen); switch (params->hashAlg) { case CKM_SHA_1: session->operation.op.encrypt.oaep_md = EVP_sha1(); break; case CKM_SHA256: session->operation.op.encrypt.oaep_md = EVP_sha256(); break; case CKM_SHA384: session->operation.op.encrypt.oaep_md = EVP_sha384(); break; case CKM_SHA512: session->operation.op.encrypt.oaep_md = EVP_sha512(); break; default: session->operation.op.encrypt.oaep_md = NULL; break; } switch (params->mgf) { case CKG_MGF1_SHA1: session->operation.op.encrypt.mgf1_md = EVP_sha1(); break; case CKG_MGF1_SHA256: session->operation.op.encrypt.mgf1_md = EVP_sha256(); break; case CKG_MGF1_SHA384: session->operation.op.encrypt.mgf1_md = EVP_sha384(); break; case CKG_MGF1_SHA512: session->operation.op.encrypt.mgf1_md = EVP_sha512(); break; default: session->operation.op.encrypt.mgf1_md = NULL; break; } if (params->source == CKZ_DATA_SPECIFIED && params->pSourceData) { session->operation.op.encrypt.oaep_label = malloc(params->ulSourceDataLen); if (session->operation.op.encrypt.oaep_label == NULL) { DBG_INFO("Unable to allocate memory for %lu byte OAEP label", params->ulSourceDataLen); return CKR_HOST_MEMORY; } memcpy(session->operation.op.encrypt.oaep_label, params->pSourceData, params->ulSourceDataLen); session->operation.op.encrypt.oaep_label_len = params->ulSourceDataLen; } } else if (pMechanism->mechanism == CKM_AES_ECB) { if (object->object.type != YH_SYMMETRIC_KEY || !yh_is_aes(object->object.algorithm)) { DBG_ERR("Wrong key type for algorithm"); return CKR_KEY_TYPE_INCONSISTENT; } if (pMechanism->pParameter != NULL || pMechanism->ulParameterLen != 0) { return CKR_MECHANISM_PARAM_INVALID; } } else if (pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) { if (object->object.type != YH_SYMMETRIC_KEY || !yh_is_aes(object->object.algorithm)) { DBG_ERR("Wrong key type for algorithm"); return CKR_KEY_TYPE_INCONSISTENT; } if (pMechanism->pParameter == NULL || pMechanism->ulParameterLen != sizeof(session->operation.mechanism.cbc.iv)) { DBG_ERR("IV invalid"); return CKR_MECHANISM_PARAM_INVALID; } memcpy(session->operation.mechanism.cbc.iv, pMechanism->pParameter, sizeof(session->operation.mechanism.cbc.iv)); } return CKR_OK; } CK_RV apply_digest_mechanism_init(yubihsm_pkcs11_op_info *op_info) { const EVP_MD *md = NULL; op_info->buffer_length = 0; switch (op_info->mechanism.mechanism) { case CKM_SHA_1: md = EVP_sha1(); break; case CKM_SHA256: md = EVP_sha256(); break; case CKM_SHA384: md = EVP_sha384(); break; case CKM_SHA512: md = EVP_sha512(); break; default: DBG_ERR("Mechanism %lu not supported", op_info->mechanism.mechanism); return CKR_MECHANISM_INVALID; } op_info->op.digest.md_ctx = EVP_MD_CTX_create(); if (op_info->op.digest.md_ctx == NULL) { return CKR_HOST_MEMORY; } if (EVP_DigestInit_ex(op_info->op.digest.md_ctx, md, NULL) == 0) { EVP_MD_CTX_destroy(op_info->op.digest.md_ctx); op_info->op.digest.md_ctx = NULL; return CKR_FUNCTION_FAILED; } set_operation_part(op_info, PART_INIT); return CKR_OK; } CK_RV apply_sign_mechanism_update(yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR in, CK_ULONG in_len) { switch (op_info->mechanism.mechanism) { case CKM_RSA_PKCS: // NOTE(adma): Specs say there should be enough space for PKCS#1 padding if (op_info->buffer_length + in_len > (op_info->op.sign.key_len + 7) / 8 - 11) { return CKR_DATA_LEN_RANGE; } memcpy(op_info->buffer + op_info->buffer_length, in, in_len); op_info->buffer_length += in_len; break; case CKM_ECDSA: if (op_info->buffer_length + in_len > 128) { // NOTE(adma): Specs say ECDSA only supports data up to 1024 bit return CKR_DATA_LEN_RANGE; } memcpy(op_info->buffer + op_info->buffer_length, in, in_len); op_info->buffer_length += in_len; break; case CKM_RSA_PKCS_PSS: case CKM_SHA_1_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_EDDSA: if (op_info->buffer_length + in_len > sizeof(op_info->buffer)) { return CKR_DATA_LEN_RANGE; } memcpy(op_info->buffer + op_info->buffer_length, in, in_len); op_info->buffer_length += in_len; break; case CKM_SHA1_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: if (EVP_DigestUpdate(op_info->op.sign.md_ctx, in, in_len) != 1) { EVP_MD_CTX_destroy(op_info->op.sign.md_ctx); op_info->op.sign.md_ctx = NULL; return CKR_FUNCTION_FAILED; } break; default: return CKR_FUNCTION_FAILED; } return CKR_OK; } CK_RV apply_verify_mechanism_update(yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR in, CK_ULONG in_len) { switch (op_info->mechanism.mechanism) { case CKM_SHA_1_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_RSA_PKCS: case CKM_RSA_PKCS_PSS: case CKM_ECDSA: case CKM_EDDSA: // NOTE(adma): no hash required for these mechanisms if (op_info->buffer_length + in_len > sizeof(op_info->buffer)) { return CKR_DATA_LEN_RANGE; } memcpy(op_info->buffer + op_info->buffer_length, in, in_len); op_info->buffer_length += in_len; break; case CKM_SHA1_RSA_PKCS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_ECDSA_SHA1: case CKM_SHA256_RSA_PKCS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_ECDSA_SHA256: case CKM_SHA384_RSA_PKCS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_ECDSA_SHA384: case CKM_SHA512_RSA_PKCS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_ECDSA_SHA512: if (EVP_DigestUpdate(op_info->op.verify.md_ctx, in, in_len) != 1) { EVP_MD_CTX_destroy(op_info->op.verify.md_ctx); op_info->op.sign.md_ctx = NULL; return CKR_FUNCTION_FAILED; } break; default: return CKR_FUNCTION_FAILED; } return CKR_OK; } static CK_RV op_info_buffer_append(yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR ptr, CK_ULONG len) { if (op_info->buffer_length > sizeof(op_info->buffer) || sizeof(op_info->buffer) - op_info->buffer_length < len) { return CKR_DATA_LEN_RANGE; } memcpy(op_info->buffer + op_info->buffer_length, ptr, len); op_info->buffer_length += len; return CKR_OK; } static CK_RV do_aes_encdec(yh_session *session, yubihsm_pkcs11_op_info *op_info, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len, bool final) { yh_rc yhr = YHR_GENERIC_ERROR; bool encrypt = op_info->type == OPERATION_ENCRYPT; if (in_len < AES_BLOCK_SIZE) { // This function should only be called internally when there is // enough data to encrypt/decrypt at least one block. This is // required for correct IV handling. return CKR_FUNCTION_FAILED; } switch (op_info->mechanism.mechanism) { case CKM_AES_ECB: yhr = encrypt ? yh_util_encrypt_aes_ecb(session, op_info->op.encrypt.key_id, in, in_len, out, out_len) : yh_util_decrypt_aes_ecb(session, op_info->op.decrypt.key_id, in, in_len, out, out_len); break; case CKM_AES_CBC: case CKM_AES_CBC_PAD: if (encrypt) { if ((yhr = yh_util_encrypt_aes_cbc(session, op_info->op.encrypt.key_id, op_info->mechanism.cbc.iv, in, in_len, out, out_len)) == YHR_SUCCESS && !final) { memcpy(op_info->mechanism.cbc.iv, out + *out_len - AES_BLOCK_SIZE, AES_BLOCK_SIZE); } } else { // `in` and `out` may overlap. uint8_t iv[AES_BLOCK_SIZE] = {0}; memcpy(iv, in + in_len - AES_BLOCK_SIZE, AES_BLOCK_SIZE); if ((yhr = yh_util_decrypt_aes_cbc(session, op_info->op.encrypt.key_id, op_info->mechanism.cbc.iv, in, in_len, out, out_len)) == YHR_SUCCESS && !final) { memcpy(op_info->mechanism.cbc.iv, iv, AES_BLOCK_SIZE); } } break; default: return CKR_FUNCTION_FAILED; } return yrc_to_rv(yhr); } static CK_RV perform_aes_update(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG_PTR out_len) { size_t prev = op_info->buffer_length; if (SIZE_MAX - prev < in_len) { return CKR_DATA_LEN_RANGE; } size_t size = prev + in_len; size_t next = size % AES_BLOCK_SIZE; // We may have to hold off an entire block. if (size && !next && op_info->type == OPERATION_DECRYPT && op_info->mechanism.mechanism == CKM_AES_CBC_PAD) { next = 16; } // Block-align the data. size -= next; if (out == NULL) { DBG_INFO("User querying output size, returning %zu bytes", size); *out_len = size; return CKR_OK; } if (size > *out_len) { DBG_ERR("Provided buffer is too small (%lu < %zu)", *out_len, size); *out_len = size; return CKR_BUFFER_TOO_SMALL; } if (!size) { DBG_INFO("Nothing to do for this update, buffering all input"); *out_len = 0; return op_info_buffer_append(op_info, in, in_len); } // Temporarily store next remainder. uint8_t tmp[AES_BLOCK_SIZE] = {0}; memcpy(tmp, in + in_len - next, next); // Move input into place (may overlap). memmove(out + prev, in, size - prev); // Move previous remainder into place. memcpy(out, op_info->buffer, prev); // Store the next remainder. memcpy(op_info->buffer, tmp, next); insecure_memzero(tmp, sizeof(tmp)); op_info->buffer_length = next; CK_RV rv; if ((rv = do_aes_encdec(session, op_info, out, size, out, &size, false)) != CKR_OK) { DBG_ERR("Failed to encrypt/decrypt data"); return rv; } DBG_INFO("Returning %zu bytes (buffered %zu bytes)", size, next); *out_len = size; return CKR_OK; } static CK_RV perform_aes_final(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR out, CK_ULONG_PTR out_len) { size_t len = op_info->buffer_length; uint8_t last[AES_BLOCK_SIZE * 2] = {0}; if (op_info->mechanism.mechanism != CKM_AES_CBC_PAD) { if (len != 0) { DBG_ERR("Data not a multiple of block size"); return op_info->type == OPERATION_ENCRYPT ? CKR_DATA_LEN_RANGE : CKR_ENCRYPTED_DATA_LEN_RANGE; } // Nothing to do for mechanisms that have no padding. *out_len = 0; return CKR_OK; } CK_RV rv; memcpy(last, op_info->buffer, len); if (op_info->type == OPERATION_ENCRYPT && yh_util_pad_pkcs7(last, &len, sizeof(last), AES_BLOCK_SIZE) != YHR_SUCCESS) { DBG_ERR("Could not pad remainder"); rv = CKR_FUNCTION_FAILED; goto daf_out; } if (do_aes_encdec(session, op_info, last, len, last, &len, true) != CKR_OK) { DBG_ERR("Could not %s remainder", op_info->type == OPERATION_ENCRYPT ? "encrypt" : "decrypt"); rv = CKR_FUNCTION_FAILED; goto daf_out; } if (op_info->type == OPERATION_DECRYPT && yh_util_unpad_pkcs7(last, &len, AES_BLOCK_SIZE) != YHR_SUCCESS) { DBG_ERR("Could not unpad remainder"); rv = CKR_ENCRYPTED_DATA_INVALID; goto daf_out; } // For single part encryption; reaching this point means the // internal IV may have been modified by an earlier call to // `perform_aes_update()` (used internally). Restore the original // IV so that the user can try again for return values that do not // terminate the operation. if (op_info->part == PART_SINGLE) { memcpy(op_info->mechanism.cbc.iv, op_info->mechanism.cbc.orig, sizeof(op_info->mechanism.cbc.iv)); } if (out == NULL) { *out_len = len; rv = CKR_OK; goto daf_out; } if (*out_len < len) { *out_len = len; rv = CKR_BUFFER_TOO_SMALL; goto daf_out; } memcpy(out, last, len); op_info->buffer_length = 0; *out_len = len; rv = CKR_OK; daf_out: insecure_memzero(last, sizeof(last)); return rv; } CK_RV apply_decrypt_mechanism_update(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { switch (op_info->mechanism.mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: case CKM_YUBICO_AES_CCM_WRAP: *pulPartLen = 0; // Only append to the buffer if the user has provided an output // buffer. Otherwise, they're just querying the output size. return pPart ? op_info_buffer_append(op_info, pEncryptedPart, ulEncryptedPartLen) : CKR_OK; case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: return perform_aes_update(session, op_info, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); default: return CKR_FUNCTION_FAILED; } return CKR_OK; } CK_RV apply_digest_mechanism_update(yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR in, CK_ULONG in_len) { switch (op_info->mechanism.mechanism) { case CKM_SHA_1: case CKM_SHA256: case CKM_SHA384: case CKM_SHA512: if (EVP_DigestUpdate(op_info->op.digest.md_ctx, in, in_len) != 1) { EVP_MD_CTX_destroy(op_info->op.digest.md_ctx); op_info->op.digest.md_ctx = NULL; return CKR_FUNCTION_FAILED; } break; default: return CKR_FUNCTION_FAILED; } return CKR_OK; } CK_RV apply_sign_mechanism_finalize(yubihsm_pkcs11_op_info *op_info) { if (is_hashed_mechanism(op_info->mechanism.mechanism)) { int ret; ret = EVP_DigestFinal_ex(op_info->op.sign.md_ctx, op_info->buffer, &op_info->buffer_length); EVP_MD_CTX_destroy(op_info->op.sign.md_ctx); op_info->op.sign.md_ctx = NULL; if (ret != 1) { return CKR_FUNCTION_FAILED; } } if (is_ECDSA_sign_mechanism(op_info->mechanism.mechanism)) { if (op_info->buffer_length > op_info->op.sign.sig_len / 2) { op_info->buffer_length = op_info->op.sign.sig_len / 2; } } // TODO(adma): check if more steps are need for PSS or ECDSA return CKR_OK; } CK_RV apply_verify_mechanism_finalize(yubihsm_pkcs11_op_info *op_info, CK_ULONG sig_len) { CK_ULONG siglen = 0; if (is_HMAC_sign_mechanism(op_info->mechanism.mechanism) == true) { switch (op_info->mechanism.mechanism) { case CKM_SHA_1_HMAC: siglen = 20; break; case CKM_SHA256_HMAC: siglen = 32; break; case CKM_SHA384_HMAC: siglen = 48; break; case CKM_SHA512_HMAC: siglen = 64; break; default: return CKR_MECHANISM_INVALID; } } else if (is_RSA_sign_mechanism(op_info->mechanism.mechanism)) { siglen = (op_info->op.verify.key_len + 7) / 8; } else if (is_ECDSA_sign_mechanism(op_info->mechanism.mechanism) || is_EDDSA_sign_mechanism(op_info->mechanism.mechanism)) { siglen = ((op_info->op.verify.key_len + 7) / 8) * 2; } else { return CKR_MECHANISM_INVALID; } if (sig_len != siglen) { DBG_ERR("Wrong signature length, expected %lu, got %lu", siglen, sig_len); return CKR_SIGNATURE_LEN_RANGE; } return CKR_OK; } CK_RV apply_decrypt_mechanism_finalize(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { yh_rc yrc; size_t outlen = *pulDataLen; if (op_info->mechanism.mechanism == CKM_RSA_PKCS) { yrc = yh_util_decrypt_pkcs1v1_5(session, op_info->op.decrypt.key_id, op_info->buffer, op_info->buffer_length, pData, &outlen); } else if (op_info->mechanism.mechanism == CKM_RSA_PKCS_OAEP) { yrc = yh_util_decrypt_oaep(session, op_info->op.decrypt.key_id, op_info->buffer, op_info->buffer_length, pData, &outlen, op_info->mechanism.oaep.label, op_info->mechanism.oaep.label_len, op_info->mechanism.oaep.mgf1Algo); } else if (op_info->mechanism.mechanism == CKM_YUBICO_AES_CCM_WRAP) { yrc = yh_util_unwrap_data(session, op_info->op.decrypt.key_id, op_info->buffer, op_info->buffer_length, pData, &outlen); } else if (op_info->mechanism.mechanism == CKM_AES_ECB || op_info->mechanism.mechanism == CKM_AES_CBC || op_info->mechanism.mechanism == CKM_AES_CBC_PAD) { return perform_aes_final(session, op_info, pData, pulDataLen); } else { DBG_ERR("Mechanism %lu not supported", op_info->mechanism.mechanism); return CKR_MECHANISM_INVALID; } if (yrc != YHR_SUCCESS && yrc != YHR_BUFFER_TOO_SMALL) { DBG_ERR("Decryption failed: %s", yh_strerror(yrc)); return yrc_to_rv(yrc); } if (yrc == YHR_BUFFER_TOO_SMALL || outlen > *pulDataLen) { *pulDataLen = outlen; return CKR_BUFFER_TOO_SMALL; } *pulDataLen = outlen; return CKR_OK; } CK_RV apply_encrypt_mechanism_finalize(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { CK_RV rv = CKR_MECHANISM_INVALID; if (op_info->mechanism.mechanism == CKM_YUBICO_AES_CCM_WRAP) { rv = perform_wrap_encrypt(session, op_info, pEncryptedData, (uint16_t *) pulEncryptedDataLen); if (rv != CKR_OK) { DBG_ERR("Unable to AES wrap data"); } } else if (op_info->mechanism.mechanism == CKM_RSA_PKCS || op_info->mechanism.mechanism == CKM_RSA_PKCS_OAEP) { rv = perform_rsa_encrypt(session, op_info, op_info->buffer, op_info->buffer_length, pEncryptedData, pulEncryptedDataLen); if (rv != CKR_OK) { DBG_ERR("Unable to RSA encrypt data"); } } else if (op_info->mechanism.mechanism == CKM_AES_ECB || op_info->mechanism.mechanism == CKM_AES_CBC || op_info->mechanism.mechanism == CKM_AES_CBC_PAD) { return perform_aes_final(session, op_info, pEncryptedData, pulEncryptedDataLen); } return rv; } CK_RV apply_digest_mechanism_finalize(yubihsm_pkcs11_op_info *op_info) { int ret; ret = EVP_DigestFinal_ex(op_info->op.digest.md_ctx, op_info->buffer, &op_info->buffer_length); EVP_MD_CTX_destroy(op_info->op.digest.md_ctx); op_info->op.digest.md_ctx = NULL; if (ret != 1) { return CKR_FUNCTION_FAILED; } return CKR_OK; } static bool apply_DER_encoding_to_ECSIG(uint8_t *signature, uint16_t *signature_len) { ECDSA_SIG *sig = ECDSA_SIG_new(); BIGNUM *r = NULL; BIGNUM *s = NULL; bool ret = false; if (sig == NULL) { return false; } r = BN_bin2bn(signature, *signature_len / 2, NULL); s = BN_bin2bn(signature + *signature_len / 2, *signature_len / 2, NULL); if (r == NULL || s == NULL) { goto adete_out; } if (ECDSA_SIG_set0(sig, r, s) == 0) { goto adete_out; } r = s = NULL; unsigned char *pp = signature; *signature_len = i2d_ECDSA_SIG(sig, &pp); if (*signature_len == 0) { goto adete_out; } else { ret = true; } adete_out: if (sig != NULL) { ECDSA_SIG_free(sig); } if (r != NULL) { BN_free(r); } if (s != NULL) { BN_free(s); } return ret; } CK_RV perform_verify(yh_session *session, yubihsm_pkcs11_op_info *op_info, uint8_t *signature, uint16_t signature_len) { if (is_HMAC_sign_mechanism(op_info->mechanism.mechanism)) { bool verified = false; yh_rc yrc = yh_util_verify_hmac(session, op_info->op.verify.key_id, signature, signature_len, op_info->buffer, op_info->buffer_length, &verified); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } if (verified == false) { return CKR_SIGNATURE_INVALID; } return CKR_OK; } else { CK_RV rv; EVP_PKEY *key = NULL; uint8_t md_data[EVP_MAX_MD_SIZE] = {0}; uint8_t *md = md_data; unsigned int md_len = sizeof(md_data); EVP_PKEY_CTX *ctx = NULL; rv = load_public_key(session, op_info->op.verify.key_id, YH_ASYMMETRIC_KEY, &key); if (rv != CKR_OK) { goto pv_failure; } #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) if (EVP_PKEY_base_id(key) == EVP_PKEY_ED25519) { EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); int rc = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, key); if (rc <= 0) { EVP_MD_CTX_free(md_ctx); return CKR_FUNCTION_FAILED; } rc = EVP_DigestVerify(md_ctx, signature, signature_len, op_info->buffer, op_info->buffer_length); EVP_MD_CTX_free(md_ctx); EVP_PKEY_free(key); if (rc == 1) { return CKR_OK; } else if (rc == 0) { return CKR_SIGNATURE_INVALID; } else { return CKR_FUNCTION_FAILED; } } #endif ctx = EVP_PKEY_CTX_new(key, NULL); if (ctx == NULL) { rv = CKR_HOST_MEMORY; goto pv_failure; } if (EVP_PKEY_verify_init(ctx) <= 0) { rv = CKR_FUNCTION_FAILED; goto pv_failure; } unsigned char data[2048] = {0}; if (is_hashed_mechanism(op_info->mechanism.mechanism)) { if (EVP_DigestFinal_ex(op_info->op.verify.md_ctx, md, &md_len) <= 0) { rv = CKR_FUNCTION_FAILED; goto pv_failure; } } else if (EVP_PKEY_base_id(key) == EVP_PKEY_RSA) { if (op_info->mechanism.mechanism == CKM_RSA_PKCS_PSS) { md = op_info->buffer; md_len = op_info->buffer_length; } else { int di_len = parse_NID(op_info->buffer, op_info->buffer_length, &op_info->op.verify.md); if (di_len == 0) { rv = CKR_DATA_INVALID; goto pv_failure; } md = op_info->buffer + di_len; md_len = op_info->buffer_length - di_len; } } else if (EVP_PKEY_base_id(key) == EVP_PKEY_EC) { md = op_info->buffer; md_len = op_info->buffer_length; if (md_len == 20) { op_info->op.verify.md = EVP_sha1(); } else if (md_len == 32) { op_info->op.verify.md = EVP_sha256(); } else if (md_len == 48) { op_info->op.verify.md = EVP_sha384(); } else if (md_len == 64) { op_info->op.verify.md = EVP_sha512(); } else { rv = CKR_FUNCTION_FAILED; goto pv_failure; } } else { rv = CKR_FUNCTION_FAILED; goto pv_failure; } if (EVP_PKEY_CTX_set_signature_md(ctx, op_info->op.verify.md) <= 0) { rv = CKR_FUNCTION_FAILED; goto pv_failure; } if (op_info->op.verify.padding) { if (EVP_PKEY_CTX_set_rsa_padding(ctx, op_info->op.verify.padding) <= 0) { rv = CKR_FUNCTION_FAILED; goto pv_failure; } if (op_info->op.verify.padding == RSA_PKCS1_PSS_PADDING) { if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, op_info->op.verify.saltLen) <= 0) { rv = CKR_FUNCTION_FAILED; goto pv_failure; } if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, op_info->op.verify.mgf1md) <= 0) { rv = CKR_FUNCTION_FAILED; goto pv_failure; } } } if (is_ECDSA_sign_mechanism(op_info->mechanism.mechanism)) { memcpy(data, signature, signature_len); signature = data; if (apply_DER_encoding_to_ECSIG(signature, &signature_len) == false) { DBG_ERR("Failed to apply DER encoding to ECDSA signature"); rv = CKR_FUNCTION_FAILED; goto pv_failure; } } int res = EVP_PKEY_verify(ctx, signature, signature_len, md, md_len); if (res == 1) { rv = CKR_OK; } else if (res == 0) { rv = CKR_SIGNATURE_INVALID; } else { rv = CKR_FUNCTION_FAILED; } pv_failure: EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(key); return rv; } return CKR_FUNCTION_FAILED; } static bool strip_DER_encoding_from_ECSIG(uint8_t *signature, size_t *signature_len, size_t sig_len) { ECDSA_SIG *sig; const unsigned char *pp = (const unsigned char *) signature; const BIGNUM *r, *s; sig = ECDSA_SIG_new(); if (sig == NULL) { return false; } if (d2i_ECDSA_SIG(&sig, &pp, *signature_len) == NULL) { ECDSA_SIG_free(sig); return false; } // since we're going to copy the data out again in signature we need to clear // it memset(signature, 0, *signature_len); ECDSA_SIG_get0(sig, &r, &s); BN_bn2binpad(r, signature, sig_len / 2); BN_bn2binpad(s, signature + sig_len / 2, sig_len / 2); *signature_len = sig_len; ECDSA_SIG_free(sig); return true; } CK_RV perform_signature(yh_session *session, yubihsm_pkcs11_op_info *op_info, uint8_t *signature, uint16_t *signature_len) { yh_rc yrc; size_t outlen = sizeof(op_info->buffer); if (is_RSA_sign_mechanism(op_info->mechanism.mechanism)) { if (is_PSS_sign_mechanism(op_info->mechanism.mechanism)) { yrc = yh_util_sign_pss(session, op_info->op.sign.key_id, op_info->buffer, op_info->buffer_length, op_info->buffer, &outlen, op_info->mechanism.pss.salt_len, op_info->mechanism.pss.mgf1Algo); } else { yrc = yh_util_sign_pkcs1v1_5(session, op_info->op.sign.key_id, is_hashed_mechanism( op_info->mechanism.mechanism), op_info->buffer, op_info->buffer_length, op_info->buffer, &outlen); } } else if (is_EDDSA_sign_mechanism(op_info->mechanism.mechanism)) { yrc = yh_util_sign_eddsa(session, op_info->op.sign.key_id, op_info->buffer, op_info->buffer_length, op_info->buffer, &outlen); } else if (is_ECDSA_sign_mechanism(op_info->mechanism.mechanism)) { yrc = yh_util_sign_ecdsa(session, op_info->op.sign.key_id, op_info->buffer, op_info->buffer_length, op_info->buffer, &outlen); if (yrc == YHR_SUCCESS) { // NOTE(adma): ECDSA, we must remove the DER encoding and only // return R,S as required by the specs if (strip_DER_encoding_from_ECSIG(op_info->buffer, &outlen, op_info->op.sign.sig_len) == false) { return CKR_FUNCTION_FAILED; } } } else if (is_HMAC_sign_mechanism(op_info->mechanism.mechanism)) { yrc = yh_util_sign_hmac(session, op_info->op.sign.key_id, op_info->buffer, op_info->buffer_length, op_info->buffer, &outlen); } else { DBG_ERR("Mechanism %lu not supported", op_info->mechanism.mechanism); return CKR_MECHANISM_INVALID; } if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } if (outlen > *signature_len) { return CKR_BUFFER_TOO_SMALL; } memcpy(signature, op_info->buffer, outlen); *signature_len = outlen; return CKR_OK; } CK_RV perform_wrap_encrypt(yh_session *session, yubihsm_pkcs11_op_info *op_info, uint8_t *data, uint16_t *data_len) { yh_rc yrc; size_t outlen = sizeof(op_info->buffer); if (op_info->mechanism.mechanism == CKM_YUBICO_AES_CCM_WRAP) { yrc = yh_util_wrap_data(session, op_info->op.decrypt.key_id, op_info->buffer, op_info->buffer_length, op_info->buffer, &outlen); } else { DBG_ERR("Mechanism %lu not supported", op_info->mechanism.mechanism); return CKR_MECHANISM_INVALID; } if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } if (outlen > *data_len) { return CKR_BUFFER_TOO_SMALL; } memcpy(data, op_info->buffer, outlen); *data_len = outlen; return CKR_OK; } CK_RV perform_rsa_encrypt(yh_session *session, yubihsm_pkcs11_op_info *op_info, CK_BYTE_PTR data, CK_ULONG data_len, CK_BYTE_PTR enc, CK_ULONG_PTR enc_len) { if (data == NULL) { DBG_ERR("data is null"); return CKR_ARGUMENTS_BAD; } EVP_PKEY *public_key = NULL; EVP_PKEY_CTX *ctx = NULL; CK_RV rv = load_public_key(session, op_info->op.encrypt.key_id, YH_ASYMMETRIC_KEY, &public_key); if (rv != CKR_OK) { DBG_ERR("Failed to load public key"); goto rsa_enc_cleanup; } ctx = EVP_PKEY_CTX_new(public_key, NULL); if (ctx == NULL) { DBG_ERR("Failed to create EVP_PKEY_CTX object for public key"); rv = CKR_HOST_MEMORY; goto rsa_enc_cleanup; } if (EVP_PKEY_encrypt_init(ctx) <= 0) { rv = CKR_FUNCTION_FAILED; goto rsa_enc_cleanup; } CK_ULONG padding = op_info->op.encrypt.padding; if (padding == RSA_NO_PADDING) { DBG_ERR("Unsupported padding RSA_NO_PADDING"); rv = CKR_FUNCTION_REJECTED; goto rsa_enc_cleanup; } else { if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0) { rv = CKR_FUNCTION_FAILED; goto rsa_enc_cleanup; } } if (op_info->op.encrypt.oaep_md != NULL) { if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, op_info->op.encrypt.oaep_md) <= 0) { rv = CKR_FUNCTION_FAILED; goto rsa_enc_cleanup; } } if (op_info->op.encrypt.mgf1_md != NULL) { if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, op_info->op.encrypt.mgf1_md) <= 0) { rv = CKR_FUNCTION_FAILED; goto rsa_enc_cleanup; } } if (op_info->op.encrypt.oaep_label != NULL) { if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, op_info->op.encrypt.oaep_label, op_info->op.encrypt.oaep_label_len) <= 0) { rv = CKR_FUNCTION_FAILED; goto rsa_enc_cleanup; } } size_t cbLen = *enc_len; if (EVP_PKEY_encrypt(ctx, enc, &cbLen, data, data_len) <= 0) { rv = CKR_FUNCTION_FAILED; goto rsa_enc_cleanup; } *enc_len = cbLen; rv = CKR_OK; rsa_enc_cleanup: if (rv != CKR_OK) { free(op_info->op.encrypt.oaep_label); } EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(public_key); return rv; } CK_RV perform_digest(yubihsm_pkcs11_op_info *op_info, uint8_t *digest, uint16_t *digest_len) { if (op_info->buffer_length > *digest_len) { return CKR_BUFFER_TOO_SMALL; } memcpy(digest, op_info->buffer, op_info->buffer_length); *digest_len = op_info->buffer_length; return CKR_OK; } void sign_mechanism_cleanup(yubihsm_pkcs11_op_info *op_info) { if (op_info->op.sign.md_ctx != NULL) { EVP_MD_CTX_destroy(op_info->op.sign.md_ctx); op_info->op.sign.md_ctx = NULL; } } void verify_mechanism_cleanup(yubihsm_pkcs11_op_info *op_info) { if (op_info->op.verify.md_ctx != NULL) { EVP_MD_CTX_destroy(op_info->op.verify.md_ctx); op_info->op.verify.md_ctx = NULL; } } void decrypt_mechanism_cleanup(yubihsm_pkcs11_op_info *op_info) { UNUSED(op_info); } void digest_mechanism_cleanup(yubihsm_pkcs11_op_info *op_info) { if (op_info->op.digest.md_ctx != NULL) { EVP_MD_CTX_destroy(op_info->op.digest.md_ctx); op_info->op.digest.md_ctx = NULL; } } CK_ULONG get_digest_bytelength(CK_MECHANISM_TYPE m) { switch (m) { case CKM_SHA_1: return 20; case CKM_SHA256: return 32; case CKM_SHA384: return 48; case CKM_SHA512: return 64; default: break; } return 0; } bool is_RSA_sign_mechanism(CK_MECHANISM_TYPE m) { switch (m) { case CKM_RSA_PKCS: case CKM_SHA1_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_RSA_PKCS_PSS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: return true; default: break; } return false; } bool is_RSA_decrypt_mechanism(CK_MECHANISM_TYPE m) { switch (m) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: return true; default: break; } return false; } bool is_hashed_mechanism(CK_MECHANISM_TYPE m) { switch (m) { case CKM_SHA1_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: case CKM_SHA_1: case CKM_SHA256: case CKM_SHA384: case CKM_SHA512: return true; default: break; } return false; } bool is_PKCS1v1_5_sign_mechanism(CK_MECHANISM_TYPE m) { switch (m) { case CKM_RSA_PKCS: case CKM_SHA1_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: return true; default: break; } return false; } bool is_ECDSA_sign_mechanism(CK_MECHANISM_TYPE m) { switch (m) { case CKM_ECDSA: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: return true; default: break; } return false; } bool is_EDDSA_sign_mechanism(CK_MECHANISM_TYPE m) { switch (m) { case CKM_EDDSA: return true; default: break; } return false; } bool is_PSS_sign_mechanism(CK_MECHANISM_TYPE m) { switch (m) { case CKM_RSA_PKCS_PSS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: return true; default: break; } return false; } bool is_HMAC_sign_mechanism(CK_MECHANISM_TYPE m) { switch (m) { case CKM_SHA_1_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: return true; default: break; } return false; } static void free_pkcs11_slot(void *data) { yubihsm_pkcs11_slot *slot = (yubihsm_pkcs11_slot *) data; free(slot->connector_name); if (slot->device_session) { if (yh_destroy_session(&slot->device_session) != YHR_SUCCESS) { DBG_ERR("Failed destroying session"); } } if (slot->connector) { yh_disconnect(slot->connector); } list_destroy(&slot->pkcs11_sessions); } static bool compare_slot(void *data, void *item) { uint16_t *a = data; uint16_t b = ((yubihsm_pkcs11_slot *) item)->id; return *a == b; } static bool compare_session(void *data, void *item) { uint16_t *a = data; uint16_t b = ((yubihsm_pkcs11_session *) item)->id; return *a == b; } yubihsm_pkcs11_slot *get_slot(yubihsm_pkcs11_context *ctx, CK_ULONG id) { ListItem *item = list_get(&ctx->slots, &id, compare_slot); if (item) { yubihsm_pkcs11_slot *slot = (yubihsm_pkcs11_slot *) item->data; if (slot->mutex != NULL) { if (ctx->lock_mutex(slot->mutex) != CKR_OK) { return NULL; } } return slot; } return NULL; } void release_slot(yubihsm_pkcs11_context *ctx, yubihsm_pkcs11_slot *slot) { if (slot->mutex != NULL) { ctx->unlock_mutex(slot->mutex); } } CK_RV get_session(yubihsm_pkcs11_context *ctx, CK_SESSION_HANDLE hSession, yubihsm_pkcs11_session **session, int session_state) { uint16_t slot_id = hSession >> 16; uint16_t session_id = hSession & 0xffff; yubihsm_pkcs11_slot *slot = get_slot(ctx, slot_id); if (slot == NULL) { DBG_ERR("Slot %d doesn't exist", slot_id); return CKR_SESSION_HANDLE_INVALID; } ListItem *item = list_get(&slot->pkcs11_sessions, &session_id, compare_session); if (item == NULL) { release_slot(ctx, slot); DBG_ERR("Session %d doesn't exist", session_id); return CKR_SESSION_HANDLE_INVALID; } *session = (yubihsm_pkcs11_session *) item->data; int state = (int) (*session)->session_state; if (session_state == 0 || ((session_state & state) == state)) { // NOTE(thorduri): slot is locked. return CKR_OK; } CK_RV rv = CKR_SESSION_HANDLE_INVALID; if (session_state == SESSION_AUTHENTICATED) { rv = CKR_USER_NOT_LOGGED_IN; DBG_ERR("Session %d user not logged in", session_id); } else if (session_state == SESSION_AUTHENTICATED_RW) { rv = CKR_SESSION_READ_ONLY; DBG_ERR("Session %d read only", session_id); } else if (session_state == SESSION_NOT_AUTHENTICATED) { rv = CKR_USER_ALREADY_LOGGED_IN; DBG_ERR("Session %d user already logged in", session_id); } else { DBG_ERR("Session %d invalid state %d (requested %d)", session_id, state, session_state); } release_slot(ctx, slot); return rv; } bool delete_session(yubihsm_pkcs11_context *ctx, CK_SESSION_HANDLE_PTR phSession) { uint16_t slot_id = *phSession >> 16; uint16_t session_id = *phSession & 0xffff; yubihsm_pkcs11_slot *slot = get_slot(ctx, slot_id); bool ret = false; if (slot) { ListItem *item = list_get(&slot->pkcs11_sessions, &session_id, compare_session); if (item) { list_delete(&slot->pkcs11_sessions, item); ret = true; } release_slot(ctx, slot); } return ret; } void release_session(yubihsm_pkcs11_context *ctx, yubihsm_pkcs11_session *session) { release_slot(ctx, session->slot); } static CK_RV native_create_mutex(void **mutex) { #ifdef __WIN32 CRITICAL_SECTION *mtx = calloc(1, sizeof(CRITICAL_SECTION)); if (mtx == NULL) { return CKR_GENERAL_ERROR; } InitializeCriticalSection(mtx); #else pthread_mutex_t *mtx = calloc(1, sizeof(pthread_mutex_t)); if (mtx == NULL) { return CKR_GENERAL_ERROR; } pthread_mutex_init(mtx, NULL); #endif *mutex = mtx; return CKR_OK; } static CK_RV native_destroy_mutex(void *mutex) { #ifdef __WIN32 DeleteCriticalSection(mutex); #else pthread_mutex_destroy(mutex); #endif free(mutex); return CKR_OK; } static CK_RV native_lock_mutex(void *mutex) { #ifdef __WIN32 EnterCriticalSection(mutex); #else if (pthread_mutex_lock(mutex) != 0) { return CKR_GENERAL_ERROR; } #endif return CKR_OK; } static CK_RV native_unlock_mutex(void *mutex) { #ifdef __WIN32 LeaveCriticalSection(mutex); #else if (pthread_mutex_unlock(mutex) != 0) { return CKR_GENERAL_ERROR; } #endif return CKR_OK; } void set_native_locking(yubihsm_pkcs11_context *ctx) { ctx->create_mutex = native_create_mutex; ctx->destroy_mutex = native_destroy_mutex; ctx->lock_mutex = native_lock_mutex; ctx->unlock_mutex = native_unlock_mutex; } CK_RV add_connectors(yubihsm_pkcs11_context *ctx, int n_connectors, char **connector_names, yh_connector **connectors) { list_create(&ctx->slots, sizeof(yubihsm_pkcs11_slot), free_pkcs11_slot); for (int i = 0; i < n_connectors; i++) { yubihsm_pkcs11_slot slot; memset(&slot, 0, sizeof(yubihsm_pkcs11_slot)); slot.id = i; slot.connector_name = strdup(connector_names[i]); slot.max_session_id = 1; if (!slot.connector_name) { return CKR_HOST_MEMORY; } slot.connector = connectors[i]; if (ctx->create_mutex != NULL) { CK_RV rv = ctx->create_mutex(&slot.mutex); if (rv != CKR_OK) { return rv; } } list_create(&slot.pkcs11_sessions, sizeof(yubihsm_pkcs11_session), NULL); if (list_append(&ctx->slots, &slot) != true) { return CKR_HOST_MEMORY; } } return CKR_OK; } CK_RV set_template_attribute(yubihsm_pkcs11_attribute *attribute, CK_BBOOL *value) { if (*attribute == ATTRIBUTE_NOT_SET) { if (*value == CK_TRUE) { *attribute = ATTRIBUTE_TRUE; } else { *attribute = ATTRIBUTE_FALSE; } return CKR_OK; } else { return CKR_TEMPLATE_INCONSISTENT; } } CK_RV check_bool_attribute(CK_BBOOL *value, bool check) { if (check == true && *value == CK_TRUE) { return CKR_OK; } else if (check == false && *value == CK_FALSE) { return CKR_OK; } return CKR_ATTRIBUTE_VALUE_INVALID; } static int BN_cmp_f4(BIGNUM *bn) { BIGNUM *f4 = BN_new(); BN_set_word(f4, 0x010001); int cmp = BN_cmp(bn, f4); BN_free(f4); return cmp; } CK_RV parse_rsa_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template) { BIGNUM *e = NULL; CK_RV rv; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_PRIME_1: if (template->obj.rsa.p == NULL) { template->obj.rsa.p = BN_bin2bn(pTemplate[i].pValue, pTemplate[i].ulValueLen, NULL); } else { DBG_ERR("CKA_PRIME_1 inconsistent in template"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_PRIME_2: if (template->obj.rsa.q == NULL) { template->obj.rsa.q = BN_bin2bn(pTemplate[i].pValue, pTemplate[i].ulValueLen, NULL); } else { DBG_ERR("CKA_PRIME_2 inconsistent in template"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_PUBLIC_EXPONENT: if (e == NULL) { e = BN_bin2bn(pTemplate[i].pValue, pTemplate[i].ulValueLen, NULL); if (e == NULL || BN_cmp_f4(e)) { DBG_ERR("CKA_PUBLIC_EXPONENT invalid in template"); BN_free(e); return CKR_ATTRIBUTE_VALUE_INVALID; } BN_free(e); } else { DBG_ERR("CKA_PUBLIC_EXPONENT inconsistent in template"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_SIGN: if ((rv = set_template_attribute(&template->sign, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_SIGN inconsistent in template"); return rv; } break; case CKA_DECRYPT: if ((rv = set_template_attribute(&template->decrypt, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DECRYPT inconsistent in template"); return rv; } break; case CKA_ENCRYPT: if ((rv = set_template_attribute(&template->encrypt, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_ENCRYPT inconsistent in template"); return rv; } break; case CKA_TOKEN: case CKA_PRIVATE: case CKA_SENSITIVE: case CKA_DESTROYABLE: if ((rv = check_bool_attribute(pTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pTemplate[i].type); return rv; } break; case CKA_WRAP: if ((rv = set_template_attribute(&template->wrap, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_WRAP inconsistent in template"); return rv; } break; case CKA_UNWRAP: if ((rv = set_template_attribute(&template->unwrap, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_UNWRAP inconsistent in template"); return rv; } break; case CKA_DERIVE: if ((rv = set_template_attribute(&template->derive, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DERIVE inconsistent in template"); return rv; } break; case CKA_VERIFY: case CKA_VERIFY_RECOVER: case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_ALWAYS_AUTHENTICATE: case CKA_SIGN_RECOVER: if ((rv = check_bool_attribute(pTemplate[i].pValue, false)) != CKR_OK) { return rv; } break; case CKA_MODULUS: case CKA_PRIVATE_EXPONENT: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: case CKA_CLASS: case CKA_KEY_TYPE: case CKA_SUBJECT: case CKA_ID: case CKA_LABEL: case CKA_EXTRACTABLE: break; default: DBG_ERR("Invalid attribute type in key template: 0x%lx\n", pTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } if (template->obj.rsa.p && template->obj.rsa.q) { template->objlen = (BN_num_bits(template->obj.rsa.p) + 7) / 8; if ((BN_num_bits(template->obj.rsa.q) + 7) / 8 != template->objlen) { DBG_ERR("Inconsistent prime sizes in template"); return CKR_ATTRIBUTE_VALUE_INVALID; } switch (template->objlen) { case 128: template->algorithm = YH_ALGO_RSA_2048; break; case 192: template->algorithm = YH_ALGO_RSA_3072; break; case 256: template->algorithm = YH_ALGO_RSA_4096; break; default: DBG_ERR("Invalid %u bit primes in template", template->objlen * 8); return CKR_ATTRIBUTE_VALUE_INVALID; } } else { DBG_ERR("Iconsistent RSA template"); return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } static CK_RV parse_ecparams(const uint8_t *ecparams, uint16_t ecparams_len, yh_algorithm *algorithm, uint16_t *key_len) { EC_GROUP *group = EC_GROUP_new(EC_GFp_simple_method()); int curve = 0; if (group == NULL) { return CKR_HOST_MEMORY; } if (d2i_ECPKParameters(&group, &ecparams, ecparams_len) != NULL) { curve = EC_GROUP_get_curve_name(group); } EC_GROUP_free(group); switch (curve) { case NID_secp224r1: *algorithm = YH_ALGO_EC_P224; *key_len = 28; break; case NID_X9_62_prime256v1: *algorithm = YH_ALGO_EC_P256; *key_len = 32; break; case NID_secp384r1: *algorithm = YH_ALGO_EC_P384; *key_len = 48; break; case NID_secp521r1: *algorithm = YH_ALGO_EC_P521; *key_len = 66; break; case NID_secp256k1: *algorithm = YH_ALGO_EC_K256; *key_len = 32; break; #ifdef NID_brainpoolP256r1 case NID_brainpoolP256r1: *algorithm = YH_ALGO_EC_BP256; *key_len = 32; break; #endif #ifdef NID_brainpoolP384r1 case NID_brainpoolP384r1: *algorithm = YH_ALGO_EC_BP384; *key_len = 48; break; #endif #ifdef NID_brainpoolP512r1 case NID_brainpoolP512r1: *algorithm = YH_ALGO_EC_BP512; *key_len = 64; break; #endif default: return CKR_CURVE_NOT_SUPPORTED; } return CKR_OK; } static CK_RV parse_edparams(uint8_t *ecparams, uint16_t ecparams_len, yh_algorithm *algorithm, uint16_t *key_len) { if (ecparams_len != sizeof(oid_ed25519) || memcmp(ecparams, oid_ed25519, sizeof(oid_ed25519))) { return CKR_CURVE_NOT_SUPPORTED; } *algorithm = YH_ALGO_EC_ED25519; *key_len = 32; return CKR_OK; } CK_RV parse_ec_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template) { CK_RV rv; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_VALUE: if (template->obj.ec.d == NULL) { template->obj.ec.d = BN_bin2bn(pTemplate[i].pValue, pTemplate[i].ulValueLen, NULL); } else { DBG_ERR("CKA_VALUE inconsistent in template"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_EC_PARAMS: if (template->objlen == 0) { rv = parse_ecparams(pTemplate[i].pValue, pTemplate[i].ulValueLen, &template->algorithm, &template->objlen); if (rv != CKR_OK) { DBG_ERR("Invalid EC parameters in template"); return rv; } } else { DBG_ERR("CKA_EC_PARAMS inconsistent in template"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_SIGN: if ((rv = set_template_attribute(&template->sign, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_SIGN inconsistent in template"); return rv; } break; case CKA_DERIVE: if ((rv = set_template_attribute(&template->derive, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DERIVE inconsistent in template"); return rv; } break; case CKA_TOKEN: case CKA_PRIVATE: case CKA_SENSITIVE: case CKA_DESTROYABLE: if ((rv = check_bool_attribute(pTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pTemplate[i].type); return rv; } break; case CKA_VERIFY: case CKA_WRAP: case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_VERIFY_RECOVER: case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_ALWAYS_AUTHENTICATE: if ((rv = check_bool_attribute(pTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx.", pTemplate[i].type); return rv; } break; case CKA_SIGN_RECOVER: case CKA_UNWRAP: { CK_BBOOL b_val = *(CK_BBOOL *) pTemplate[i].pValue; if (b_val != CK_FALSE) { DBG_ERR("Boolean false check failed for attribute 0x%lx. This will " "be ignored", pTemplate[i].type); } } break; case CKA_CLASS: case CKA_KEY_TYPE: case CKA_SUBJECT: case CKA_ID: case CKA_LABEL: case CKA_EXTRACTABLE: break; default: DBG_ERR("Invalid attribute type in key template: 0x%lx\n", pTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } if (template->obj.ec.d == NULL || template->objlen == 0) { DBG_ERR("Inconsistent EC template"); return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } CK_RV parse_ed_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template) { uint8_t *ecparams = NULL; uint16_t ecparams_len = 0; CK_RV rv; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_VALUE: if (template->obj.buf == NULL) { template->obj.buf = (CK_BYTE_PTR) pTemplate[i].pValue; template->objlen = pTemplate[i].ulValueLen; } else { return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_EC_PARAMS: if (ecparams == NULL) { ecparams = (CK_BYTE_PTR) pTemplate[i].pValue; ecparams_len = pTemplate[i].ulValueLen; } else { return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_SIGN: if ((rv = set_template_attribute(&template->sign, pTemplate[i].pValue)) != CKR_OK) { return rv; } break; case CKA_TOKEN: case CKA_PRIVATE: case CKA_SENSITIVE: if ((rv = check_bool_attribute(pTemplate[i].pValue, true)) != CKR_OK) { return rv; } break; case CKA_CLASS: case CKA_KEY_TYPE: case CKA_SUBJECT: case CKA_ID: case CKA_LABEL: case CKA_EXTRACTABLE: case CKA_DERIVE: break; default: return CKR_ATTRIBUTE_TYPE_INVALID; } } if (ecparams && template->obj.buf) { uint16_t key_len; rv = parse_edparams(ecparams, ecparams_len, &template->algorithm, &key_len); if (rv != CKR_OK) { return rv; } if (key_len != template->objlen) { return CKR_ATTRIBUTE_VALUE_INVALID; } } else { return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } CK_RV parse_hmac_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template, bool generate) { CK_RV rv; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_VALUE: if (generate == false && template->obj.buf == NULL) { // TODO: consider hashing the key here if it's longer than blocklen template->obj.buf = pTemplate[i].pValue; template->objlen = pTemplate[i].ulValueLen; } else { DBG_ERR("CKA_VALUE inconsistent in template"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_SIGN: if ((rv = set_template_attribute(&template->sign, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_SIGN inconsistent in template"); return rv; } break; case CKA_VERIFY: if ((rv = set_template_attribute(&template->verify, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_VERIFY inconsistent in template"); return rv; } break; case CKA_KEY_TYPE: switch (*((CK_ULONG_PTR) pTemplate[i].pValue)) { case CKK_SHA_1_HMAC: template->algorithm = YH_ALGO_HMAC_SHA1; break; case CKK_SHA256_HMAC: template->algorithm = YH_ALGO_HMAC_SHA256; break; case CKK_SHA384_HMAC: template->algorithm = YH_ALGO_HMAC_SHA384; break; case CKK_SHA512_HMAC: template->algorithm = YH_ALGO_HMAC_SHA512; break; default: DBG_ERR("CKA_KEY_TYPE inconsistent in template"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_DESTROYABLE: case CKA_PRIVATE: case CKA_SENSITIVE: case CKA_TOKEN: if ((rv = check_bool_attribute(pTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pTemplate[i].type); return rv; } break; case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_WRAP: case CKA_UNWRAP: case CKA_DERIVE: case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_SIGN_RECOVER: case CKA_VERIFY_RECOVER: case CKA_ALWAYS_AUTHENTICATE: if ((rv = check_bool_attribute(pTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx", pTemplate[i].type); return rv; } break; case CKA_CLASS: case CKA_SUBJECT: case CKA_ID: case CKA_LABEL: case CKA_EXTRACTABLE: break; default: DBG_ERR("Invalid attribute type in key template: 0x%lx\n", pTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } if (template->algorithm && (generate == true || template->obj.buf)) { return CKR_OK; } else { DBG_ERR("Inconsistent HMAC template"); return CKR_TEMPLATE_INCONSISTENT; } } CK_RV parse_meta_id_template(yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta, bool pubkey, uint8_t *value, size_t value_len) { if (value_len > CKA_ATTRIBUTE_VALUE_SIZE) { DBG_ERR("Failed to parse too large CKA_ID"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (pubkey) { // Store pubkey metadata pkcs11meta->cka_id_pubkey.len = value_len; memcpy(pkcs11meta->cka_id_pubkey.value, value, value_len); } else { // Check if it is a valid regular id if (value_len == 2) { // Parse the id for backwards compat template->id = parse_id_value(value, value_len); // Check if both ids are the same if (pkcs11meta->cka_id_pubkey.len == value_len && memcmp(pkcs11meta->cka_id_pubkey.value, value, value_len) == 0) { // Remove metadata pkcs11meta->cka_id_pubkey.len = 0; } } else { // Store privkey metadata pkcs11meta->cka_id.len = value_len; memcpy(pkcs11meta->cka_id.value, value, value_len); // Use random id for invalid length template->id = 0; } } return CKR_OK; } CK_RV parse_meta_label_template(yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta, bool pubkey, uint8_t *value, size_t value_len) { if (value_len > CKA_ATTRIBUTE_VALUE_SIZE) { DBG_ERR("Failed to parse too large CKA_LABEL"); return CKR_ATTRIBUTE_VALUE_INVALID; } if (pubkey) { // Store pubkey metadata pkcs11meta->cka_label_pubkey.len = value_len; memcpy(pkcs11meta->cka_label_pubkey.value, value, value_len); } else { // Check if it can fit as regular label if (value_len <= YH_OBJ_LABEL_LEN) { // Store as regular label memcpy(template->label, value, value_len); // Check if both labels are the same if (pkcs11meta->cka_label_pubkey.len == value_len && memcmp(pkcs11meta->cka_label_pubkey.value, value, value_len) == 0) { // Remove pubkey metadata pkcs11meta->cka_label_pubkey.len = 0; } } else { // Store privkey metadata pkcs11meta->cka_label.len = value_len; memcpy(pkcs11meta->cka_label.value, value, value_len); // Also store first part as regular label memcpy(template->label, value, YH_OBJ_LABEL_LEN); } } return CKR_OK; } CK_RV parse_rsa_generate_template(CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta) { uint8_t *e = NULL; CK_RV rv; memset(template->label, 0, sizeof(template->label)); for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++) { switch (pPublicKeyTemplate[i].type) { case CKA_CLASS: if (*((CK_ULONG_PTR) pPublicKeyTemplate[i].pValue) != CKO_PUBLIC_KEY) { DBG_ERR("CKA_CLASS inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_KEY_TYPE: if (*((CK_ULONG_PTR) pPublicKeyTemplate[i].pValue) != CKK_RSA) { DBG_ERR("CKA_KEY_TYPE inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_ID: rv = parse_meta_id_template(template, pkcs11meta, true, pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_PUBLIC_EXPONENT: if (e == NULL) { e = (CK_BYTE_PTR) pPublicKeyTemplate[i].pValue; if (!((pPublicKeyTemplate[i].ulValueLen == 3 && memcmp(e, "\x01\x00\x01", 3) == 0) || (pPublicKeyTemplate[i].ulValueLen == 4 && memcmp(e, "\x00\x01\x00\x01", 4) == 0))) { DBG_ERR("CKA_PUBLIC_EXPONENT invalid in PublicKeyTemplate"); return CKR_ATTRIBUTE_VALUE_INVALID; } } else { DBG_ERR("CKA_PUBLIC_EXPONENT inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_MODULUS_BITS: switch (*((CK_ULONG_PTR) pPublicKeyTemplate[i].pValue)) { case 2048: template->algorithm = YH_ALGO_RSA_2048; break; case 3072: template->algorithm = YH_ALGO_RSA_3072; break; case 4096: template->algorithm = YH_ALGO_RSA_4096; break; default: DBG_ERR("CKA_MODULUS_BITS wrong length in PublicKeyTemplate (%lu)", *((CK_ULONG_PTR) pPublicKeyTemplate[i].pValue)); return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CKA_LABEL: rv = parse_meta_label_template(template, pkcs11meta, true, pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_EXTRACTABLE: case CKA_DESTROYABLE: if ((rv = check_bool_attribute(pPublicKeyTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pPublicKeyTemplate[i].type); return rv; } break; case CKA_PRIVATE: case CKA_SENSITIVE: case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_DECRYPT: case CKA_SIGN: case CKA_DERIVE: case CKA_SIGN_RECOVER: case CKA_VERIFY_RECOVER: case CKA_ALWAYS_AUTHENTICATE: if ((rv = check_bool_attribute(pPublicKeyTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx", pPublicKeyTemplate[i].type); return rv; } break; case CKA_TOKEN: case CKA_WRAP: // pkcs11-tool sets this on public keys case CKA_UNWRAP: // pkcs11-tool sets this on public keys case CKA_VERIFY: case CKA_ENCRYPT: break; default: DBG_ERR("Invalid attribute type in PublicKeyTemplate: 0x%lx", pPublicKeyTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } for (CK_ULONG i = 0; i < ulPrivateKeyAttributeCount; i++) { switch (pPrivateKeyTemplate[i].type) { case CKA_CLASS: if (*((CK_ULONG_PTR) pPrivateKeyTemplate[i].pValue) != CKO_PRIVATE_KEY) { DBG_ERR("CKA_CLASS inconsistent in PrivateKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_KEY_TYPE: if (*((CK_ULONG_PTR) pPrivateKeyTemplate[i].pValue) != CKK_RSA) { DBG_ERR("CKA_KEY_TYPE inconsistent in PrivateKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_ID: { rv = parse_meta_id_template(template, pkcs11meta, false, pPrivateKeyTemplate[i].pValue, pPrivateKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } } break; case CKA_DECRYPT: if ((rv = set_template_attribute(&template->decrypt, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DECRYPT inconsistent in PrivateKeyTemplate"); return rv; } break; case CKA_SIGN: if ((rv = set_template_attribute(&template->sign, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_SIGN inconsistent in PrivateKeyTemplate"); return rv; } break; case CKA_EXTRACTABLE: if ((rv = set_template_attribute(&template->exportable, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_EXTRACTABLE inconsistent in PrivateKeyTemplate"); return rv; } break; case CKA_LABEL: rv = parse_meta_label_template(template, pkcs11meta, false, pPrivateKeyTemplate[i].pValue, pPrivateKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_TOKEN: case CKA_SENSITIVE: case CKA_PRIVATE: case CKA_DESTROYABLE: if ((rv = check_bool_attribute(pPrivateKeyTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pPrivateKeyTemplate[i].type); return rv; } break; case CKA_WRAP: if ((rv = check_bool_attribute(pPrivateKeyTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute CKA_WRAP"); return rv; } break; case CKA_UNWRAP: // pkcs11-tool sets this on private keys if ((rv = set_template_attribute(&template->unwrap, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_UNWRAP inconsistent in template"); return rv; } break; case CKA_DERIVE: if ((rv = set_template_attribute(&template->derive, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DERIVE inconsistent in template"); return rv; } break; case CKA_ENCRYPT: case CKA_SIGN_RECOVER: case CKA_VERIFY: case CKA_VERIFY_RECOVER: case CKA_MODIFIABLE: case CKA_COPYABLE: if ((rv = check_bool_attribute(pPrivateKeyTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx", pPrivateKeyTemplate[i].type); return rv; } break; case CKA_SUBJECT: break; default: DBG_ERR("Invalid attribute type in PrivateKeyTemplate: 0x%lx", pPrivateKeyTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } if (template->algorithm == 0) { DBG_ERR("No RSA bitlength set"); return CKR_TEMPLATE_INCOMPLETE; } return CKR_OK; } uint16_t parse_id_value(void *value, CK_ULONG len) { switch (len) { case 0: return 0; case 1: return *(uint8_t *) value; case 2: return ntohs(*(uint16_t *) value); default: DBG_INFO("Supplied id is long, truncating it (was %lu bytes)", len); return ntohs(*(uint16_t *) value); } } CK_RV parse_ec_generate_template(CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta) { uint8_t *ecparams = NULL; uint16_t ecparams_len = 0; CK_RV rv; memset(template->label, 0, sizeof(template->label)); for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++) { switch (pPublicKeyTemplate[i].type) { case CKA_CLASS: if (*((CK_ULONG_PTR) pPublicKeyTemplate[i].pValue) != CKO_PUBLIC_KEY) { DBG_ERR("CKA_CLASS inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_KEY_TYPE: if (*((CK_ULONG_PTR) pPublicKeyTemplate[i].pValue) != CKK_EC) { DBG_ERR("CKA_KEY_TYPE inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_ID: rv = parse_meta_id_template(template, pkcs11meta, true, pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_EC_PARAMS: if (ecparams == NULL) { ecparams = (CK_BYTE_PTR) pPublicKeyTemplate[i].pValue; ecparams_len = pPublicKeyTemplate[i].ulValueLen; } else { DBG_ERR("CKA_EC_PARAMS inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_LABEL: rv = parse_meta_label_template(template, pkcs11meta, true, pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_EXTRACTABLE: case CKA_DESTROYABLE: if ((rv = check_bool_attribute(pPublicKeyTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pPublicKeyTemplate[i].type); return rv; } break; case CKA_PRIVATE: case CKA_SENSITIVE: case CKA_MODIFIABLE: case CKA_COPYABLE: case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_WRAP: case CKA_UNWRAP: case CKA_SIGN: case CKA_SIGN_RECOVER: case CKA_VERIFY_RECOVER: case CKA_ALWAYS_AUTHENTICATE: if ((rv = check_bool_attribute(pPublicKeyTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx", pPublicKeyTemplate[i].type); return rv; } break; case CKA_TOKEN: case CKA_VERIFY: case CKA_DERIVE: // pkcs11-tool sets this on public keys break; default: DBG_ERR("Invalid attribute type in PublicKeyTemplate: 0x%lx", pPublicKeyTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } for (CK_ULONG i = 0; i < ulPrivateKeyAttributeCount; i++) { switch (pPrivateKeyTemplate[i].type) { case CKA_CLASS: if (*((CK_ULONG_PTR) pPrivateKeyTemplate[i].pValue) != CKO_PRIVATE_KEY) { DBG_ERR("CKA_CLASS inconsistent in PrivateKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_KEY_TYPE: if (*((CK_ULONG_PTR) pPrivateKeyTemplate[i].pValue) != CKK_EC) { DBG_ERR("CKA_KEY_TYPE inconsistent in PrivateKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_ID: { rv = parse_meta_id_template(template, pkcs11meta, false, pPrivateKeyTemplate[i].pValue, pPrivateKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } } break; case CKA_SIGN: if ((rv = set_template_attribute(&template->sign, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_SIGN inconsistent in PrivateKeyTemplate"); return rv; } break; case CKA_EXTRACTABLE: if ((rv = set_template_attribute(&template->exportable, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_EXTRACTABLE inconsistent in PrivateKeyTemplate"); return rv; } break; case CKA_DERIVE: if ((rv = set_template_attribute(&template->derive, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DERIVE inconsistent in PrivateKeyTemplate"); return rv; } break; case CKA_LABEL: rv = parse_meta_label_template(template, pkcs11meta, false, pPrivateKeyTemplate[i].pValue, pPrivateKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_TOKEN: case CKA_SENSITIVE: case CKA_PRIVATE: case CKA_DESTROYABLE: if ((rv = check_bool_attribute(pPrivateKeyTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pPrivateKeyTemplate[i].type); return rv; } break; case CKA_VERIFY: case CKA_WRAP: case CKA_UNWRAP: case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_SIGN_RECOVER: case CKA_VERIFY_RECOVER: case CKA_MODIFIABLE: case CKA_COPYABLE: if ((rv = check_bool_attribute(pPrivateKeyTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx", pPrivateKeyTemplate[i].type); return rv; } break; case CKA_SUBJECT: break; default: DBG_ERR("Invalid attribute type in PrivateKeyTemplate: 0x%lx", pPrivateKeyTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } if (ecparams == NULL) { DBG_ERR("CKA_EC_PARAMS not set"); return CKR_TEMPLATE_INCOMPLETE; } uint16_t key_len; rv = parse_ecparams(ecparams, ecparams_len, &template->algorithm, &key_len); if (rv != CKR_OK) { DBG_ERR("Failed to parse CKA_EC_PARAMS"); return rv; } return CKR_OK; } CK_RV parse_ed_generate_template(CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta) { uint8_t *ecparams = NULL; uint16_t ecparams_len = 0; CK_RV rv; memset(template->label, 0, sizeof(template->label)); for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++) { switch (pPublicKeyTemplate[i].type) { case CKA_CLASS: if (*((CK_ULONG_PTR) pPublicKeyTemplate[i].pValue) != CKO_PUBLIC_KEY) { DBG_ERR("CKA_CLASS inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_KEY_TYPE: if (*((CK_ULONG_PTR) pPublicKeyTemplate[i].pValue) != CKK_EC_EDWARDS) { DBG_ERR("CKA_KEY_TYPE inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_ID: rv = parse_meta_id_template(template, pkcs11meta, true, pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_EC_PARAMS: if (ecparams == NULL) { ecparams = (CK_BYTE_PTR) pPublicKeyTemplate[i].pValue; ecparams_len = pPublicKeyTemplate[i].ulValueLen; } else { DBG_ERR("CKA_PUBLIC_EXPONENT inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_LABEL: rv = parse_meta_label_template(template, pkcs11meta, true, pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_TOKEN: case CKA_EXTRACTABLE: case CKA_DESTROYABLE: case CKA_VERIFY: if ((rv = check_bool_attribute(pPublicKeyTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pPublicKeyTemplate[i].type); return rv; } break; case CKA_SENSITIVE: case CKA_PRIVATE: case CKA_COPYABLE: case CKA_MODIFIABLE: case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_SIGN: case CKA_SIGN_RECOVER: case CKA_WRAP: case CKA_WRAP_WITH_TRUSTED: case CKA_UNWRAP: case CKA_DERIVE: case CKA_VERIFY_RECOVER: if ((rv = check_bool_attribute(pPublicKeyTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx", pPublicKeyTemplate[i].type); return rv; } break; case CKA_SUBJECT: break; default: DBG_ERR("invalid attribute type in PublicKeyTemplate: 0x%lx\n", pPublicKeyTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } for (CK_ULONG i = 0; i < ulPrivateKeyAttributeCount; i++) { switch (pPrivateKeyTemplate[i].type) { case CKA_CLASS: if (*((CK_ULONG_PTR) pPrivateKeyTemplate[i].pValue) != CKO_PRIVATE_KEY) { DBG_ERR("CKA_CLASS inconsistent in PrivateKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_KEY_TYPE: if (*((CK_ULONG_PTR) pPrivateKeyTemplate[i].pValue) != CKK_EC_EDWARDS) { DBG_ERR("CKA_KEY_TYPE inconsistent in PrivateKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_ID: { rv = parse_meta_id_template(template, pkcs11meta, false, pPrivateKeyTemplate[i].pValue, pPrivateKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } } break; case CKA_SIGN: if ((rv = set_template_attribute(&template->sign, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_SIGN inconsistent in PrivateKeyTemplate"); return rv; } break; case CKA_EXTRACTABLE: if ((rv = set_template_attribute(&template->exportable, pPrivateKeyTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_EXTRACTABLE inconsistent in PrivateKeyTemplate"); return rv; } break; case CKA_LABEL: rv = parse_meta_label_template(template, pkcs11meta, false, pPrivateKeyTemplate[i].pValue, pPrivateKeyTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_TOKEN: case CKA_SENSITIVE: case CKA_PRIVATE: case CKA_DESTROYABLE: if ((rv = check_bool_attribute(pPrivateKeyTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pPrivateKeyTemplate[i].type); return rv; } break; case CKA_COPYABLE: case CKA_MODIFIABLE: case CKA_ENCRYPT: case CKA_DECRYPT: case CKA_SIGN_RECOVER: case CKA_VERIFY: case CKA_VERIFY_RECOVER: case CKA_WRAP: case CKA_WRAP_WITH_TRUSTED: case CKA_UNWRAP: case CKA_DERIVE: if ((rv = check_bool_attribute(pPrivateKeyTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx", pPrivateKeyTemplate[i].type); return rv; } break; case CKA_SUBJECT: break; default: DBG_ERR("invalid attribute type in PrivateKeyTemplate: 0x%lx\n", pPrivateKeyTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } if (ecparams == NULL) { DBG_ERR("CKA_EC_PARAMS not set"); return CKR_TEMPLATE_INCOMPLETE; } uint16_t key_len; rv = parse_edparams(ecparams, ecparams_len, &template->algorithm, &key_len); if (rv != CKR_OK) { DBG_ERR("Failed to parse CKA_EC_PARAMS"); return rv; } return CKR_OK; } CK_RV parse_wrap_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template, yh_algorithm algorithm, bool generate) { CK_RV rv; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_VALUE: if (generate == false && template->obj.buf == NULL) { template->obj.buf = pTemplate[i].pValue; template->objlen = pTemplate[i].ulValueLen; } else { DBG_ERR("CKA_VALUE inconsistent in template"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_VALUE_LEN: if (generate == true) { size_t key_length = 0; yh_rc yrc = yh_get_key_bitlength(algorithm, &key_length); if (yrc != YHR_SUCCESS) { return yrc_to_rv(yrc); } if ((key_length + 7) / 8 != *(CK_ULONG_PTR) pTemplate[i].pValue) { return CKR_TEMPLATE_INCONSISTENT; } } else { return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_WRAP: if ((rv = set_template_attribute(&template->wrap, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_WRAP inconsistent in template"); return rv; } break; case CKA_UNWRAP: if ((rv = set_template_attribute(&template->unwrap, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_UNWRAP inconsistent in template"); return rv; } break; case CKA_ENCRYPT: if ((rv = set_template_attribute(&template->encrypt, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_ENCRYPT inconsistent in template"); return rv; } break; case CKA_DECRYPT: if ((rv = set_template_attribute(&template->decrypt, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DECRYPT inconsistent in template"); return rv; } break; case CKA_TOKEN: case CKA_PRIVATE: case CKA_SENSITIVE: case CKA_DESTROYABLE: if ((rv = check_bool_attribute(pTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pTemplate[i].type); return rv; } break; case CKA_SIGN: case CKA_VERIFY: case CKA_SIGN_RECOVER: case CKA_VERIFY_RECOVER: case CKA_DERIVE: case CKA_COPYABLE: case CKA_MODIFIABLE: if ((rv = check_bool_attribute(pTemplate[i].pValue, false)) != CKR_OK) { return rv; } break; case CKA_KEY_TYPE: case CKA_CLASS: case CKA_SUBJECT: case CKA_ID: case CKA_LABEL: case CKA_EXTRACTABLE: break; default: DBG_ERR("Invalid attribute type in key template: 0x%lx", pTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } if (generate == true || template->obj.buf) { return CKR_OK; } else { DBG_ERR("Inconsistent wrap key template"); return CKR_TEMPLATE_INCONSISTENT; } } CK_RV set_object_type(uint8_t *type, uint8_t expected_type) { if (*type == 0) { *type = expected_type; return CKR_OK; } if (*type != expected_type) { DBG_ERR("Mismatch in attribute values"); return CKR_TEMPLATE_INCONSISTENT; } return CKR_OK; } CK_RV parse_rsa_wrappedkey_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template, pkcs11_meta_object *pkcs11meta, CK_BYTE* type) { CK_RV rv; CK_ULONG ckk_type = 0; uint8_t *ecparams = NULL; uint16_t ecparams_len = 0; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_CLASS: { uint32_t value = *((CK_ULONG_PTR) (pTemplate[i].pValue)); switch (value) { case CKO_SECRET_KEY: rv = set_object_type(type, YH_SYMMETRIC_KEY); if (rv != CKR_OK) { return rv; } break; case CKO_PRIVATE_KEY: rv = set_object_type(type, YH_ASYMMETRIC_KEY); if (rv != CKR_OK) { return rv; } break; default: DBG_ERR("Unsupported wrapped key class"); return CKR_ATTRIBUTE_VALUE_INVALID; } } break; case CKA_KEY_TYPE: { ckk_type = *((CK_ULONG_PTR) (pTemplate[i].pValue)); switch (ckk_type) { case CKK_RSA: case CKK_EC: case CKK_EC_EDWARDS: rv = set_object_type(type, YH_ASYMMETRIC_KEY); if (rv != CKR_OK) { return rv; } break; case CKK_AES: rv = set_object_type(type, YH_SYMMETRIC_KEY); if (rv != CKR_OK) { return rv; } break; default: DBG_ERR("Unsupported wrapped key type 0x%lx", ckk_type); return CKR_ATTRIBUTE_VALUE_INVALID; } } break; case CKA_ID: rv = parse_meta_id_template(template, pkcs11meta, true, pTemplate[i].pValue, pTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_LABEL: rv = parse_meta_label_template(template, pkcs11meta, true, pTemplate[i].pValue, pTemplate[i].ulValueLen); if (rv != CKR_OK) { return rv; } break; case CKA_MODULUS_BITS: rv = set_object_type(type, YH_ASYMMETRIC_KEY); if (rv != CKR_OK) { return rv; } switch (*((CK_ULONG_PTR) pTemplate[i].pValue)) { case 2048: template->algorithm = YH_ALGO_RSA_2048; break; case 3072: template->algorithm = YH_ALGO_RSA_3072; break; case 4096: template->algorithm = YH_ALGO_RSA_4096; break; default: DBG_ERR("CKA_MODULUS_BITS wrong length in PublicKeyTemplate (%lu)", *((CK_ULONG_PTR) pTemplate[i].pValue)); return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CKA_EC_PARAMS: rv = set_object_type(type, YH_ASYMMETRIC_KEY); if (rv != CKR_OK) { return rv; } if (ecparams == NULL) { ecparams = (CK_BYTE_PTR) pTemplate[i].pValue; ecparams_len = pTemplate[i].ulValueLen; } else { DBG_ERR("CKA_EC_PARAMS inconsistent in PublicKeyTemplate"); return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_VALUE_LEN: rv = set_object_type(type, YH_SYMMETRIC_KEY); if (rv != CKR_OK) { return rv; } CK_ULONG keylen = *((CK_ULONG_PTR) pTemplate[i].pValue); switch (keylen) { case 16: template->algorithm = YH_ALGO_AES128; break; case 24: template->algorithm = YH_ALGO_AES192; break; case 32: template->algorithm = YH_ALGO_AES256; break; default: DBG_ERR("Invalid key length %lu", keylen); return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CKA_DECRYPT: if ((rv = set_template_attribute(&template->encrypt, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DECRYPT inconsistent in pTemplate"); return rv; } break; case CKA_ENCRYPT: if ((rv = set_template_attribute(&template->decrypt, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DECRYPT inconsistent in pTemplate"); return rv; } break; case CKA_SIGN: rv = set_object_type(type, YH_ASYMMETRIC_KEY); if (rv != CKR_OK) { return rv; } if ((rv = set_template_attribute(&template->sign, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_SIGN inconsistent in pTemplate"); return rv; } break; case CKA_DERIVE: rv = set_object_type(type, YH_ASYMMETRIC_KEY); if (rv != CKR_OK) { return rv; } if ((rv = set_template_attribute(&template->derive, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_DERIVE inconsistent in PrivateKeyTemplate"); return rv; } break; case CKA_EXTRACTABLE: if ((rv = set_template_attribute(&template->exportable, pTemplate[i].pValue)) != CKR_OK) { DBG_ERR("CKA_EXTRACTABLE inconsistent in PrivateKeyTemplate"); return rv; } break; default: DBG_ERR("unknown attribute 0x%lx", pTemplate[i].type); break; } } if (ecparams != NULL) { uint16_t key_len; if (ckk_type == CKK_EC) { rv = parse_ecparams(ecparams, ecparams_len, &template->algorithm, &key_len); } else if (ckk_type == CKK_EC_EDWARDS) { rv = parse_edparams(ecparams, ecparams_len, &template->algorithm, &key_len); } else { DBG_ERR("Found EC parameters for non EC keys"); return CKR_TEMPLATE_INCONSISTENT; } if (rv != CKR_OK) { DBG_ERR("Failed to parse CKA_EC_PARAMS"); return rv; } } return CKR_OK; } CK_RV parse_aes_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_object_template *template, bool generate) { CK_RV rv; CK_ULONG keylen = 0; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_VALUE: if (generate == false && template->obj.buf == NULL) { template->obj.buf = pTemplate[i].pValue; template->objlen = keylen = pTemplate[i].ulValueLen; } else { return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_VALUE_LEN: if (generate == true && template->obj.buf == NULL) { keylen = *((CK_ULONG *) pTemplate[i].pValue); } else { return CKR_TEMPLATE_INCONSISTENT; } break; case CKA_ENCRYPT: if ((rv = set_template_attribute(&template->encrypt, pTemplate[i].pValue)) != CKR_OK) { return rv; } break; case CKA_DECRYPT: if ((rv = set_template_attribute(&template->decrypt, pTemplate[i].pValue)) != CKR_OK) { return rv; } break; case CKA_TOKEN: case CKA_PRIVATE: case CKA_SENSITIVE: if ((rv = check_bool_attribute(pTemplate[i].pValue, true)) != CKR_OK) { DBG_ERR("Boolean truth check failed for attribute 0x%lx", pTemplate[i].type); return rv; } break; case CKA_WRAP: case CKA_UNWRAP: case CKA_DERIVE: case CKA_SIGN: case CKA_VERIFY: case CKA_COPYABLE: case CKA_MODIFIABLE: if ((rv = check_bool_attribute(pTemplate[i].pValue, false)) != CKR_OK) { DBG_ERR("Boolean false check failed for attribute 0x%lx", pTemplate[i].type); return rv; } break; case CKA_KEY_TYPE: case CKA_CLASS: case CKA_SUBJECT: case CKA_ID: case CKA_LABEL: case CKA_EXTRACTABLE: break; default: DBG_ERR("unknown attribute 0x%lx", pTemplate[i].type); return CKR_ATTRIBUTE_TYPE_INVALID; } } switch (keylen) { case 16: template->algorithm = YH_ALGO_AES128; break; case 24: template->algorithm = YH_ALGO_AES192; break; case 32: template->algorithm = YH_ALGO_AES256; break; default: DBG_ERR("Invalid key length %lu", keylen); return CKR_ATTRIBUTE_VALUE_INVALID; } if (generate == true || template->obj.buf) { return CKR_OK; } else { return CKR_TEMPLATE_INCONSISTENT; } } CK_RV populate_template(int type, void *object, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, yubihsm_pkcs11_session *session) { CK_RV rv = CKR_OK; //#ifdef FUZZING // /* TODO in fuzzing builds make the data buffers smaller // * there are currently many locations in the code which make assumptions // * that the size of the tmp buffer (and aliases) is large enough // * decreasing the size now artificially will prevent the fuzzer from progressing well // */ // CK_BYTE tmp[20] = {0}; //#else CK_BYTE tmp[16384] = {0}; //#endif for (CK_ULONG i = 0; i < ulCount; i++) { DBG_INFO("Getting attribute 0x%lx", pTemplate[i].type); CK_ULONG len = sizeof(tmp); CK_RV attribute_rc; if (type == ECDH_KEY_TYPE) { ecdh_session_key *key = object; attribute_rc = get_attribute_ecsession_key(pTemplate[i].type, key, tmp, &len); } else { yubihsm_pkcs11_object_desc *desc = object; attribute_rc = get_attribute(pTemplate[i].type, &desc->object, tmp, &len, session); } if (attribute_rc == CKR_OK) { if (pTemplate[i].pValue == NULL) { DBG_INFO("Retrieving only length which is %lu", len); pTemplate[i].ulValueLen = len; } else if (len > pTemplate[i].ulValueLen) { DBG_WARN("Skipping attribute, buffer too small %lu > %lu", len, pTemplate[i].ulValueLen); attribute_rc = CKR_BUFFER_TOO_SMALL; } else { DBG_INFO("Retrieving attribute value, length is %lu", len); memcpy(pTemplate[i].pValue, tmp, len); pTemplate[i].ulValueLen = len; } } // NOTE: this needs to be a separate if since attribute_rc might be changed // inside of the above if statement if (attribute_rc != CKR_OK) { pTemplate[i].ulValueLen = CK_UNAVAILABLE_INFORMATION; rv = attribute_rc; if (attribute_rc == CKR_ATTRIBUTE_TYPE_INVALID) { DBG_ERR("Attribute type invalid"); } else if (attribute_rc == CKR_BUFFER_TOO_SMALL) { DBG_ERR("Skipping attribute because buffer is too small"); } else { DBG_ERR("Get attribute failed: %lx", attribute_rc); } } else { DBG_INFO("Attribute/length successfully returned with length %lu", pTemplate[i].ulValueLen); } // NOTE(adma): Array of attributes like CKA_WRAP_TEMPLATE are special // cases. /* In the special case of an attribute whose value is an array of * attributes, for example CKA_WRAP_TEMPLATE, where it is passed in with * pValue not NULL, then if the pValue of elements within the array is * NULL_PTR then the ulValueLen of elements within the array will be set * to the required length. If the pValue of elements within the array is * not NULL_PTR, then the ulValueLen element of attributes within the * array MUST reflect the space that the corresponding pValue points to, * and pValue is filled in if there is sufficient room. Therefore it is * important to initialize the contents of a buffer before calling * C_GetAttributeValue to get such an array value. If any ulValueLen * within the array isn't large enough, it will be set to * CK_UNAVAILABLE_INFORMATION and the function will return * CKR_BUFFER_TOO_SMALL, as it does if an attribute in the pTemplate * argument has ulValueLen too small. Note that any attribute whose value * is an array of attributes is identifiable by virtue of the attribute * type having the CKF_ARRAY_ATTRIBUTE bit set.*/ } insecure_memzero(tmp, sizeof(tmp)); return rv; } CK_RV validate_derive_key_attribute(CK_ATTRIBUTE_TYPE type, void *value) { switch (type) { case CKA_TOKEN: if (*((CK_BBOOL *) value) == CK_TRUE) { DBG_ERR("Derived key can only be a session object"); return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CKA_CLASS: if (*((CK_ULONG_PTR) value) != CKO_SECRET_KEY) { DBG_ERR("Derived key class is unsupported"); return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CKA_KEY_TYPE: if (*((CK_ULONG_PTR) value) != CKK_GENERIC_SECRET) { DBG_ERR("Derived key type is unsupported"); return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CKA_EXTRACTABLE: if (*((CK_BBOOL *) value) == CK_FALSE) { DBG_ERR("The derived key must be extractable"); return CKR_ATTRIBUTE_VALUE_INVALID; } break; default: DBG_WARN("ECDH key derive template contains the ignored attribute: %lx", type); break; } return CKR_OK; } bool match_meta_attributes(yubihsm_pkcs11_session *session, yh_object_descriptor *object, uint8_t *cka_id, uint16_t cka_id_len, uint8_t *cka_label, uint16_t cka_label_len) { CK_RV rv = CKR_OK; #ifdef FUZZING // in fuzzing builds make the data buffers smaller CK_BYTE tmp[200] = {0}; #else CK_BYTE tmp[8192] = {0}; #endif CK_ULONG len = sizeof(tmp); if (cka_id_len > 0) { rv = get_attribute(CKA_ID, object, tmp, &len, session); if (rv != CKR_OK) { DBG_ERR("Failed to parse CKA_ID"); return false; } if (!match_byte_array(tmp, len, cka_id, cka_id_len)) { return false; } } if (cka_label_len > 0) { memset(tmp, 0, len); len = sizeof(tmp); rv = get_attribute(CKA_LABEL, object, tmp, &len, session); if (rv != CKR_OK) { DBG_ERR("Failed to parse CKA_LABEL"); return false; } if (!match_byte_array(tmp, len, cka_label, cka_label_len)) { return false; } } return true; } #ifndef FUZZING static void increment_ctr(uint8_t *ctr, size_t len) { while (len > 0) { if (++ctr[--len]) { break; } } } #endif CK_RV ecdh_with_kdf(ecdh_session_key *shared_secret, uint8_t *fixed_info, size_t fixed_len, CK_ULONG kdf, size_t value_len) { if (fixed_len > 0 && fixed_info == NULL) { return CKR_MECHANISM_PARAM_INVALID; } hash_ctx hash = NULL; switch (kdf) { case CKD_NULL: DBG_INFO("KDF is CKD_NULL"); // Do nothing break; case CKD_SHA1_KDF_SP800: DBG_INFO("KDF is CKD_SHA1_KDF_SP800"); hash_create(&hash, _SHA1); break; case CKD_SHA256_KDF_SP800: DBG_INFO("KDF is CKD_SHA256_KDF_SP800"); hash_create(&hash, _SHA256); break; case CKD_SHA384_KDF_SP800: DBG_INFO("KDF is CKD_SHA384_KDF_SP800"); hash_create(&hash, _SHA384); break; case CKD_SHA512_KDF_SP800: DBG_INFO("KDF is CKD_SHA512_KDF_SP800"); hash_create(&hash, _SHA512); break; } if (hash) { uint8_t ctr[sizeof(uint32_t)] = {0}; uint8_t res[ECDH_KEY_BUF_SIZE] = {0}; size_t res_len = 0; do { increment_ctr(ctr, sizeof(ctr)); hash_init(hash); hash_update(hash, ctr, sizeof(ctr)); hash_update(hash, shared_secret->ecdh_key, shared_secret->len); hash_update(hash, fixed_info, fixed_len); size_t len = sizeof(res) - res_len; hash_final(hash, res + res_len, &len); res_len += len; } while (res_len < value_len); if (value_len == 0) { value_len = res_len; } memcpy(shared_secret->ecdh_key, res, value_len); memset(shared_secret->ecdh_key + value_len, 0, sizeof(shared_secret->ecdh_key) - value_len); shared_secret->len = value_len; } else if (kdf != CKD_NULL) { DBG_ERR("Unsupported KDF %lu", kdf); return CKR_MECHANISM_PARAM_INVALID; } return CKR_OK; } yubihsm-shell-2.7.3/pkcs11/CMakeLists.txt0000644000175000017500000001157415167357110017146 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(${CMAKE_SOURCE_DIR}/cmake/openssl.cmake) find_libcrypto() set( SOURCE ../common/hash.c ../common/util.c ../common/parsing.c ../common/openssl-compat.c util_pkcs11.c yubihsm_pkcs11.c list.c debug_p11.c ) if(WIN32) set(SOURCE ${SOURCE} cmdline.c ../common/time_win.c ${CMAKE_CURRENT_BINARY_DIR}/version.rc) include(${CMAKE_SOURCE_DIR}/cmake/getopt.cmake) find_getopt() else(WIN32) include(gengetopt) add_gengetopt_files(cmdline "--conf-parser" "--no-handle-error" "--string-parser") set(SOURCE ${SOURCE} ${GGO_C}) endif(WIN32) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${CMAKE_CURRENT_SOURCE_DIR} ${LIBCRYPTO_INCLUDEDIR} ) # NOTE(adma): required by gengetopt add_definitions(-DPACKAGE="yubihsm_pkcs11") add_definitions(-DVERSION="${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") add_definitions(-DVERSION_MAJOR=${yubihsm_shell_VERSION_MAJOR}) add_definitions(-DVERSION_MINOR=${yubihsm_shell_VERSION_MINOR}) add_definitions(-DVERSION_PATCH=${yubihsm_shell_VERSION_PATCH}) list(APPEND LCOV_REMOVE_PATTERNS "'${PROJECT_SOURCE_DIR}/pkcs11/cmdline.c'") if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") set_property(SOURCE ${GGO_C} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-but-set-variable ") endif() add_library(yubihsm_pkcs11 SHARED ${SOURCE}) if (FUZZING AND ENABLE_STATIC) target_sources(yubihsm_pkcs11 PUBLIC ${PROJECT_SOURCE_DIR}/lib/fuzz/yubihsm_fuzz.cc) set_target_properties (yubihsm_pkcs11 PROPERTIES COMPILE_FLAGS "-DSTATIC ") endif() add_coverage (yubihsm_pkcs11) # Remove "lib" form the built target set_target_properties(yubihsm_pkcs11 PROPERTIES PREFIX "") # Set install RPATH if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # lib/pkcs11/ -> one level up to reach lib/ where sibling dylibs live set_target_properties(yubihsm_pkcs11 PROPERTIES INSTALL_RPATH "@loader_path/..") else() set_target_properties(yubihsm_pkcs11 PROPERTIES INSTALL_RPATH "${YUBIHSM_INSTALL_LIB_DIR}") endif() if(NOT MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") endif() add_definitions(-DCRYPTOKI_EXPORTS) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # glibc provides the iconv functionality out of the box, this # will probably be required on other platforms besides macOS. set_target_properties(yubihsm_pkcs11 PROPERTIES LINK_FLAGS "-liconv") endif() target_link_libraries( yubihsm_pkcs11 ${LIBCRYPTO_LDFLAGS} ${GETOPT_LIBS} ) if(ENABLE_STATIC) target_link_libraries(yubihsm_pkcs11 yubihsm_static) else() target_link_libraries(yubihsm_pkcs11 yubihsm) endif() if(WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) endif(WIN32) install( TARGETS yubihsm_pkcs11 ARCHIVE DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}/pkcs11" LIBRARY DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}/pkcs11" RUNTIME DESTINATION "${YUBIHSM_INSTALL_BIN_DIR}/pkcs11") install(FILES pkcs11.h DESTINATION "${YUBIHSM_INSTALL_INC_DIR}/pkcs11") install(FILES pkcs11t.h DESTINATION "${YUBIHSM_INSTALL_INC_DIR}/pkcs11") install(FILES pkcs11f.h DESTINATION "${YUBIHSM_INSTALL_INC_DIR}/pkcs11") install(FILES pkcs11y.h DESTINATION "${YUBIHSM_INSTALL_INC_DIR}/pkcs11") add_subdirectory (tests) if (FUZZING) include_directories( ../lib/fuzz ) add_executable(fuzz_get_attribute_value # harness sources fuzz/fuzz_get_attribute_value.cc ../lib/fuzz/yubihsm_fuzz.cc # pkcs11 sources ../common/hash.c ../common/util.c ../common/parsing.c ../common/openssl-compat.c util_pkcs11.c yubihsm_pkcs11.c list.c debug_p11.c # libyubihsm sources ../aes_cmac/aes.c ../aes_cmac/aes_cmac.c ../common/hash.c ../common/pkcs5.c ../common/rand.c ../common/ecdh.c ../common/openssl-compat.c ../lib/error.c ../lib/lib_util.c ../lib/yubihsm.c # cmdline sources ${GGO_C} ) set_target_properties (fuzz_get_attribute_value PROPERTIES COMPILE_FLAGS "-DSTATIC -fsanitize=fuzzer") set_target_properties (fuzz_get_attribute_value PROPERTIES LINK_FLAGS "-fsanitize=fuzzer") target_link_libraries(fuzz_get_attribute_value ${LIBCRYPTO_LDFLAGS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types") endif (FUZZING) yubihsm-shell-2.7.3/pkcs11/list.h0000644000175000017500000000251015167357110015520 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIST_H #define LIST_H #include typedef void (*FreeItemFn)(void *); typedef bool (*CompareItemFn)(void *, void *); typedef void (*IteratorFn)(void *); typedef struct ListItem ListItem; struct ListItem { void *data; ListItem *next; }; typedef struct { int length; int item_size; ListItem *head; ListItem *tail; FreeItemFn free_item_fn; } List; void list_create(List *list, int item_size, FreeItemFn free_item_fn); void list_destroy(List *list); bool list_prepend(List *list, void *item); bool list_append(List *list, void *item); ListItem *list_get(List *list, void *data, CompareItemFn compare_item_fn); void list_delete(List *list, ListItem *item); void list_iterate(List *list, IteratorFn iterator_fn); #endif yubihsm-shell-2.7.3/pkcs11/tests/0000755000175000017500000000000015167357110015540 5ustar aveenaveenyubihsm-shell-2.7.3/pkcs11/tests/asym_wrap_test.c0000644000175000017500000010540615167357110020753 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include "../pkcs11y.h" #include "../lib/yubihsm.h" #include "common.h" #include "../common/util.h" const char rsa2048[] = "-----BEGIN RSA PRIVATE KEY-----\n" "MIIEpAIBAAKCAQEA1mA5mATDvo4dN7gTNyXMr+Sen2vkTaYY2vDY6B59ZuQp7si9\n" "H4sjjZjXm0/+CCuwmi287mu8zrqDYsi+cVtw+KsVdMp7EmaHUelael0JzUy+pbJs\n" "4+PT8kZ/ytx2640j5P1H7mt/LJKcJCq7U0N4WUGx5YEyPUPGJxCgYgnXx8CSxCst\n" "A3leSfVEnPu9kA7hztMREfyrSIyLoDcNY3y0n7yHL/uHlNAIMvOT1+RAqYHm1mxQ\n" "sKZtDNtRBACRh4j1wKZSjK+0Wt0h15RJ4fp0i+smNR5rU0UpvpjfbeEe14DBxxE5\n" "v0W64hsIoedJh5GD9vWARa1wF8+pi+KDHny5KwIDAQABAoIBAG4o4k+g2yl3g8IX\n" "ICCtluIn++72FUpleM5BB2U4Db6qrnWax7yG1k0z5k9UKrjuIoEH0dc+m7Yrl8pS\n" "V7KOh53w5ESwq8+Hyi+oVysb1iaeMjWZW2U7tLUBzzdiVOW0EGbiVG1K5f30lLHt\n" "F3ew6w4KuSyzWCqtQgze+VuHrU9iT/jllv/KFxxaIFQeUOL0sR0CeE7gji7QE4C1\n" "2WjYjGYb7+N+3R+nmWq3NOXBarj4vSQ42UngzO2eH6d04KsCWJzOQ/2ymCzoai+v\n" "AaiACdrOrZFscJw8E8jyrNHDEBXvqY6j3S4444FshKiXij5gLoZZ22rY2lWcc3s+\n" "qOPK9MkCgYEA7wVV3ON+nmS+GZKRa+RlQ0Ooh/VlYw2NJBxmPrYVTN/YQAzE2hoA\n" "OVrXOjfuF4g/YgxvvbKcImSxUvAoemUPO0v/9NA0L1u8ehP/S+RrmvTk4IG2OlGs\n" "LqAzpUp1t4OONKzulISmJ0LNRblwbA2ORgugVo5/X495XIwJZ5V2cX0CgYEA5Zq2\n" "scXFMmcl99OgH5DwPtlYLlKjub4lhiyEEWghcCMDriLlbT/oqi3cJlJejsqHhI+u\n" "pWH8WBfoVc2xNvaqzqzCJtKHxjjrEhwpjFO7e+idxwbKCB6blpBwayClVjd3UURz\n" "TNBWPPvx0a1cMyufF1g1Nw8DwpjfTeA7WZdsVccCgYAhW0NCUlVHUZPeCcBVqEgh\n" "fP22C58clbWOxo/WTJ7oXYzWU3HdZieF2ZGTxF5r1k3SJx4pARYdDqRYiL99ZUEc\n" "61xLFAtUWJ8TAltsgfIqa+bNFg0SUnePAjhy5tNKywc7fq7E90Yg0IfJJTn1OmcS\n" "i2jS64wHEATFz504YXloGQKBgQCntZCI3YqivFExanTlWbsCTUNp4pcQz2EdVlrJ\n" "VCRIgmrnwTmPyUSrOYA6xaOn7St7mm/ZAW+O8TeVpP8yxI4TFIFkVhcypNSfj86R\n" "X3/sjAbjH4Rm1eST38EdnuTlyvHufG8zxmGXffguTdCw18YHCTkllGQMuhkyCv2O\n" "/Vn2dQKBgQDI1dM1/jCLg6mh51np0ZB8BgTv8mEIOvgdlD21lTpWaCeAWFJZOqWY\n" "Oo/dNh3YcbW0I6kTpriukDSxXJ095BhcBAG8jGNxw2293A/lKeyQyGKCYOX2Foh/\n" "dBVLu4zKddTSxwy7p5iu5fTf4m0T/BJIea16hiyWfL01UxfiS+ybRg==\n" "-----END RSA PRIVATE KEY-----"; const char rsa3072[] = "-----BEGIN RSA PRIVATE KEY-----\n" "MIIG5AIBAAKCAYEAy9VfKYjKmcggcZaopxgy0TxrnLTQWT+EkInakIz1J7FCRpCw\n" "FaD/d0eIFcfUka5hRHMSPnP/XtZFoV0CpfOy8lJ/8YSPDv9v/E8Z+A5bATiRlkoD\n" "iJENb5XhBNe3HGuF6bZUVQWPBpmNTna4t4JiMwJ9xXsnF9m0gWlqz7BSuLM5ivWg\n" "BSOzcSCwJ3hV6nVygDqWebrULWJ87qGA26zFGBNbYZbwAxHEMAoN9Ys0mxa4WidV\n" "estUt3fFD3Coc9BdeA7kDD844rDQ74t3joagrwqnsXyTx61g7RyrT+gAOfNvEFpx\n" "N/1Y4FPgpwHBZLxiF2yFw/Zapq1DPTXQJY2tkHyTb5PUKxXEpOjZlOcxKvJq/x50\n" "AZMdIxo/UZQ6OwGUTtYq1TpWzH8fa/NNKXu3ciGKvGO5HU+dYRZ2Hl8ZpVbA+PR/\n" "wGdBd8fENFk6HEP6ztHAC0EHD34BRMXtheSvWJDoa7VuZ+RuwibdQmHOea2rRcHT\n" "/ljEp6tJNHcp2yDtAgMBAAECggGATWgiU2uXRP8zEu/b7FjMM5l2ZHRmCv6MITe4\n" "wNxG3WP7f0DDHfOeEHYhv+O7XfeTCKOKch0rBaDpoHXp44vAkTWzUMy+ZzuqE28W\n" "tZT+CmCpKSHCZcJwD8gjQ+uHpktO94o+TGtn/WGiwAFl9IqXMDfp+2zhU7VhTyPx\n" "ZB3ZzDqDx7mvo0QDiRqYyuRv/DHN4dReAKxqlzGnsBe1D7d0wcfYFB911jSRBI1M\n" "78qFl7/xEouNcqx055ecRljKH/EoX5CRm6dGBcThem5EeRY+S0xQGg8escKB4Iiu\n" "UIQ3drKpHxh6fwIg+rXh7DNp6MasVKjBgEAYEpRkPuJn7KIW1mxU7WTadFyYCzJp\n" "ABtxUxnplxML4O9+7CYA0SUjOzhGzqN/Clymr7LNAiYSY9fYFc5+M0FhslE+JF7J\n" "5DJC8fqc08yQ9gx5VAtXVor5ezw64Bahldh9y+tjkLv8DQephQhSuzWugzVIwJgp\n" "xITOgINUdJ3DPhhekQemAo2z03MBAoHBAPojsnGhahNeu8AwhlUu+JhBiLx4kmxo\n" "SrU5w183NhEf0jePZQ4GKxxcUkjRM49YIGMA1q646rhA+8Qsk1iKvenPXKiV+9hS\n" "iYv5Mp4Ou1Xx7RDkdvsdE6i3NV7ZAWQiBXTEQlgufqAO465fR+5lICnhoIV5bU8y\n" "oEzJXq3zu4VXuX7OCU1nCsNMg+5cIla0EUn932ruwIRuyHUsoWTSkxJCl033SeC9\n" "srZIhh9oE1MLhsHhCBVd9/Z7SJ4EUgHTZQKBwQDQm/APC7puxCR/bLpYFyYOnLt8\n" "oqZrI6PjWX7tdI35+4ZIHP2ap0bQUm/7Y22Ihy1DTb/xGU8nJ/3ff9Pkhnrg0nTO\n" "IeOVlz5PDoywMjj0EuBWcES9b7PHMZ1V/hPjWFY/lyhIwUe2VsH8Ff1kyR3uPZHR\n" "ijbdorPzAXx1eoSCmmcH1kO7hgV9tiKMPUcbKng+yNVjki0nJhp8fe2mwGmo83j9\n" "ZiiNCXs5h4Blue0gsJMHhGNIEXaak5TZZLTIMukCgcEA0eY2jSeX7Z0nC4UslDqQ\n" "HKORbCX5KMLzPdO04CdiVUhQjJLlh7khX/EQk04JaBXZR3qiq4c8X1UYb2vAUSJL\n" "bvG0nTsOVF4eUbjRAtT12o7iEbTFKr8higgC3w5WHoJ19Z/i1EBfvUwBPodxwthU\n" "/w/4NUjJsxWWchjgPDQ0fRY57/BQ2gTHgU6pvtDNd9guUdqZKhAiuH6F8915qTMS\n" "etYqRSBnfBFy74c4FQ6ueJdJg1OkBtoNg2W8b+zMLAAJAoHBALY4sL6D0St2fCcu\n" "s6vFNMIo2IErltEZxcwPXhdP68EEnCyb3k9cdTf9+sGN/Zz372rOHK8fG4wpm9LC\n" "VzZU3jtKuytgYOtHvO7T18MFa8iQQJRg5zrOuyxxw2zdT0QU4uoTQOYkp164dCSe\n" "lMSYBWQZNiniYMDDogrQLoZ0KhHni75FxM6maF+CXLVBxb4OIBE/315lzrlWyGYc\n" "nh4+D028t+Apf5yLPq9nFJpHicI3W4eCdjL6xi6KYchv9pa2GQKBwBEfxlxetAKu\n" "QnK4xSWJ0VdlI6QInZN3AjuLRonaS4OeiymZJ2nmmk8Gow3UZfQJcUJ/ucEHWbxY\n" "eYzv2F8s9x5dHY46hhfNFi+fOb5nc2yLPGlFiD8C5Np6SjxkGPaXASRzO4HUWVB2\n" "U43rrVtnDR+qIPFQd7V6MWEFF6TDgpEJptpqu741kkm/gT0qFdUXHiQ8tSCZMzDX\n" "hc3roHoelzSkhPdUeKn0PVTz4LHmsw9FnpdaxzV21F98i0jNCWB28w==\n" "-----END RSA PRIVATE KEY-----"; const char rsa4096[] = "-----BEGIN RSA PRIVATE KEY-----\n" "MIIJKAIBAAKCAgEA5pyOip8CLSY6a15Cnrvrr9d5Xs6JSaryH3YGsfkpqe9P+NtZ\n" "qQXYwsUPNboEJh8RF3y9l6qkJNwW/WQXPfQ46zkCrBuTDpAkSaTsGvXnb7bEUyvu\n" "ORVgLKIqv69KrwGbP+dRm02xUJiEJiWGxzREOUgTjf+dgtIvbDBSV7SjI1C3Z7Ww\n" "z2Lx+P5qq34c2HM1F2DL9tSHAYtOoNgcefjMSbwCDABcNwcXofn7ZHXU0NKXDVkI\n" "3UV4SWNnoABkqmLYKqlM7T5OyFO88C35M55wWj64/WiHJQRy1RSDHhP8Il1VsAMm\n" "j2mBg+sDL98OhyHP9PwuOZPZ5fABjsKfm5otZmPummffCA3bD5LldVLV/fAIKix+\n" "QPeArchSD55iafP4Bz1xG5+GXwCWQ1D9DKYVRhiDGHfaJsEJOuZETteHWfs1iC9t\n" "Oc53eTcqne1TEKS0+KZcdKUpG9LigLXRIHOq61Gg2nKvIK0l9uvNyd1+7GE7CyR+\n" "q3UXQqQYW0HPduaFIe8l+WIDugCxdWN9yK1l9/xWnIVhhd4BZlaqqO1SvfApyCj9\n" "RIyPuCkyw2BncRjJ3g58tmdiVUF9GPl9ycUtjCG52aNJIzFa6/jYVWik9QXkp1hA\n" "ipjWHL0ow1bPYcRQaKJBSby95mcVdHjS3wsJylsQZydQe4v+N6T8p54NXHUCAwEA\n" "AQKCAgBqojnHH3+CIQsiWpOzknGI/bnBfP8+cS1EHu85nF0HlwEDsWnkHi/83+II\n" "ldsVRYhBtAx29RCxepOm14FnxGYNXm895gI52azt4LTMQqihn4FodAfTnW67NMFP\n" "oV6HTdbb1bqGdYZoHh39BZ0sv55MXmesYWYT99y1yiJJK93Dlq835Wu8eaQp3nq0\n" "kbwE2kDSbo/hsqQ6so/JECUawVC1R5oqsn/xcfYbj9wOt+2QIdB2+5R9vIHCbZSd\n" "B5GEt+/8ygwoJ4eGWjIjXR6+H6UUFay0gID9PPFcVf/LCLKtsTrOCKbr6X1Z4nG2\n" "0Q2GrrvaLEGzngpDqJcPzC7BZKlYrj+mC6+yC5exT8fbd64HCbaG6XLnKW8HZnw6\n" "iin8ZFXkejyJEtk2oqvxFfMPxkagYMqUSqfLTnLgf/4a0fNrNDSb4el4L/5AxKby\n" "NSqE5eATa2cSAK/cBTI1iLfTk6vAneP16S9oGAO7IxzT8d7t2mwSb1xWg2+KdAzg\n" "NnRLIp9XTz09d21LGzW1Kj6wlPe1j+a37sdLLQ1OH6g7NA7k1m3R+RF8tQU8wIMA\n" "/DBp3tk38N71rbuTdlxYQ+ur+zxiqoQjN1rNPTc6FMQdekDsXg1uNmyQuAUAYnvo\n" "BIM2E0w8YQ/07ghDf3KJbIVkPV8FZgjY9zkMIP000ODMYY4oAQKCAQEA/FDQ1nxM\n" "4EZwLw1Vt33W3SV0iLXJsUUS34Rwy+xcAfPy3WBViaqDZE4ju2kZLQhoFA4L+RIw\n" "cyIZF+ShOkDf1lVJgBq5yDFRjkC39IAFHQf3E7HyG+3iVo29k+jb0HTR19f2arI6\n" "LCygQPviNbvJJ+Yr8EyZslCqW0NjhQWw/z2ydWrMwmVgg2wMO/64y2LYq2RujQKi\n" "SzMnZsIGNBVm/eB7geKDv0JB4XOfnWBml7PYUx05Pd8QHxbEhLrXvSCv75nRRSVh\n" "lCDa+ebwXCHWIzIJPeye+5YOYrbtQ35dNbhAerP2DwyqAjG/LarZT+uGXpy90WtP\n" "zuX1nDojCwc9cQKCAQEA6fqbyW4apLZwj2y1X0Bf6YvLRCOyPJV7XqKhM3humgFN\n" "Ry/VXTS3JqrlcquxB1LTaXeS8FoGENMAZX+e4Yw+4MFKqMoI3YkN9EUTa3iJF/0U\n" "ZhvMikwDPgkddvKSZQqs/jTauqEdDBe5R2hITu95PoThrOg4a2ish1nML8Y+0QYR\n" "R0bTgt96IIq/Hmhl84NwWaC+rx5U8GcFhKuVx3tN+wys1MK2eXwUGlVt1p1KtpWx\n" "2F/5Z9AIbfU1ovRH7+ugql0Cupu+KtczOeO5Z6BCk9CFMz32qLDYw+dXBJ+6kUcy\n" "UImgd+u/tULJ2K7GLkAIeK6Z7SBYH2pA1XxBg2QdRQKCAQAqvg4Cp5/mRkhu0BV7\n" "NggWAmhRWGpIa2kdEDSDdxDHC+pSciVLYuVLMql+7/jh1hC7hP2mPdyTRG13zLU7\n" "Rw4kIuKGnwBl12T3ciM3ehBjsJu8bGKVNKEpBG3fBo1mLMP3ipAl1vdf0Fd9aq4R\n" "aDRVW/qJhJBs0plpSGstd59aPbtjhKoXLFFDMiSIbUgkvCP0NNk9bfrMPmgoUin2\n" "3MFLtKF3iUXEOpcqeAnMAS6f+ElnGwY9YvI6MgMscPJnCYiEUExRKFn1W/N8bhC9\n" "qsW5xJooMVNlTzA0rMRYsKldlk7l+mJufji2knLOa6jQjxd+I5NMTJ+CbxZCVt7k\n" "2V8hAoIBAGc3refjUY+eB/PNggl+DZGqoMXzdVpymxT5a2GYXDpGHsArotVWPwGo\n" "3EWE5jiT2j2piUHMhOaBHqin7wAS7V4bBwOE9Po9ztEWc+WyK9BQTeJpmwbbV4bT\n" "YJMrmVdHqV8PE/rGvliqUorkvxlLXVIuLpwnaVRAvfOLsp7UtrthENg/r2kJiwe2\n" "DW+toGQXdMWlOtln6RKQcAfB5fY1OAZq5geJyhO3n+qqCyVlCCOZz/XjCNQ6Gq3f\n" "QYUcfGujp6HgHCcUM4UUoD2GbzD+qsAoecpMKHbsZQOvF10r1ZLnNJQA0rB0aILe\n" "7spO95BJoTMT20WXQijBp85F3WTIEn0CggEBAPhtkW3ezzzwCwAwN8wsJ/qNmY0Z\n" "QWmflKPmz1SPzIkArtysDEO4/K9zBrP1/DTpOCknzpoxDZjt7iPFyOw6hIyYL4oI\n" "+kbEBrw7mrOBLZyp0WUia+KXGzM6TA1HQxtZZMd1MbyI7ZA1l8gaidENfl5OeFgC\n" "m43X4wJEWD2EyGX7Uvc/DsEYSey1ESQtdp6bxmBiqg53BcfL2V7VmXUv1skDJY0i\n" "qSeb46nVbqBha4bRBPTxeh7a4DAuwn/2J2p+8bzGiHmBLNB31RNJiVtkqzQYLqzi\n" "Gh0FCwVmpa+sRcA2c0N7gwt6YEWo4QJgUjQ16GxxszS9Y+xjw2jdYUaOdBQ=\n" "-----END RSA PRIVATE KEY-----"; #define BUFSIZE 1024 static CK_FUNCTION_LIST_3_0_PTR p11; static CK_SESSION_HANDLE session; static void generate_ec_keys(CK_OBJECT_HANDLE_PTR pubkey, CK_OBJECT_HANDLE_PTR pvtkey) { CK_BYTE ec_params[] = {0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; CK_ULONG class_k = CKO_PRIVATE_KEY; CK_ULONG class_c = CKO_PUBLIC_KEY; CK_ULONG kt = CKK_EC; CK_BBOOL exportable_capability = CK_TRUE; CK_BBOOL sign_capability = CK_TRUE; char *label = "eckey"; CK_ATTRIBUTE privateKeyTemplate[] = {{CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_LABEL, label, strlen(label)}, {CKA_EXTRACTABLE, &exportable_capability, sizeof(exportable_capability)}, {CKA_SIGN, &sign_capability, sizeof(sign_capability)}}; CK_ATTRIBUTE publicKeyTemplate[] = {{CKA_CLASS, &class_c, sizeof(class_c)}, {CKA_EC_PARAMS, ec_params, sizeof(ec_params)}}; CK_MECHANISM mech = {CKM_EC_KEY_PAIR_GEN, NULL, 0}; assert(p11->C_GenerateKeyPair(session, &mech, publicKeyTemplate, 2, privateKeyTemplate, 5, pubkey, pvtkey) == CKR_OK); fprintf(stdout, "Generated EC key. Handle 0x%06lx\n", *pvtkey); } static void generate_aes_key(CK_OBJECT_HANDLE_PTR key) { CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE type = CKK_AES; CK_ULONG key_len = 32; CK_BBOOL exportable_capability = CK_TRUE; CK_BBOOL encrypt_capability = CK_TRUE; CK_BBOOL decrypt_capability = CK_TRUE; CK_ATTRIBUTE templ[] = {{CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &type, sizeof(type)}, {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, {CKA_EXTRACTABLE, &exportable_capability, sizeof(exportable_capability)}, {CKA_ENCRYPT, &encrypt_capability, sizeof(encrypt_capability)}, {CKA_DECRYPT, &decrypt_capability, sizeof(decrypt_capability)}}; CK_MECHANISM mech = {CKM_AES_KEY_GEN, NULL, 0}; assert(p11->C_GenerateKey(session, &mech, templ, 6, key) == CKR_OK); fprintf(stdout, "Generated AES key. Handle 0x%06lx\n", *key); } static void import_rsa_wrapkey(const char *key, int keylen, CK_OBJECT_HANDLE_PTR keyid) { CK_BYTE e[] = {0x01, 0x00, 0x01}; CK_BYTE *p, *q, *dp, *dq, *qinv; int len = keylen / 16; p = malloc(len); q = malloc(len); dp = malloc(len); dq = malloc(len); qinv = malloc(len); BIO *bio = BIO_new_mem_buf((void *) key, strlen(key)); RSA *rsak = PEM_read_bio_RSAPrivateKey(bio, 0, 0, 0); const BIGNUM *bp, *bq, *biqmp, *bdmp1, *bdmq1; RSA_get0_factors(rsak, &bp, &bq); RSA_get0_crt_params(rsak, &bdmp1, &bdmq1, &biqmp); BN_bn2binpad(bp, p, len); BN_bn2binpad(bq, q, len); BN_bn2binpad(bdmp1, dp, len); BN_bn2binpad(bdmq1, dq, len); BN_bn2binpad(biqmp, qinv, len); CK_ULONG class_k = CKO_PRIVATE_KEY; CK_ULONG kt = CKK_RSA; CK_BYTE id[] = {0, 0}; CK_BBOOL wrap_capability = CK_TRUE; CK_BBOOL sign_capability = CK_TRUE; char *label = "rsa_wrap"; CK_ATTRIBUTE keyTemplate[] = {{CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_ID, &id, sizeof(id)}, {CKA_LABEL, label, strlen(label)}, {CKA_UNWRAP, &wrap_capability, sizeof(wrap_capability)}, {CKA_SIGN, &sign_capability, sizeof(sign_capability)}, {CKA_PUBLIC_EXPONENT, e, sizeof(e)}, {CKA_PRIME_1, p, len}, {CKA_PRIME_2, q, len}, {CKA_EXPONENT_1, dp, len}, {CKA_EXPONENT_2, dq, len}, {CKA_COEFFICIENT, qinv, len}}; assert(p11->C_CreateObject(session, keyTemplate, 12, keyid) == CKR_OK); fprintf(stdout, "Imorted RSA wrap key. Size %d. Handle 0x%06lx\n", keylen, *keyid); free(p); free(q); free(dp); free(dq); free(qinv); } static CK_OBJECT_HANDLE import_rsa_pub_wrapkey(uint8_t *pubkey, size_t pubkey_len) { CK_OBJECT_HANDLE pubkey_handle; CK_ULONG class_k = CKO_PUBLIC_KEY; CK_BBOOL wrap_capability = CK_TRUE; char *label = "pub_rsa_wrap"; CK_ULONG kt = CKK_RSA; CK_ATTRIBUTE template[] = {{CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_LABEL, label, strlen(label)}, {CKA_WRAP, &wrap_capability, sizeof(wrap_capability)}, {CKA_VALUE, pubkey, pubkey_len}}; assert(p11->C_CreateObject(session, template, 5, &pubkey_handle) == CKR_OK); return pubkey_handle; } static void generate_rsa_wrapkey(int keylen, CK_OBJECT_HANDLE_PTR keyid) { CK_ULONG class_k = CKO_PRIVATE_KEY; CK_ULONG class_c = CKO_PUBLIC_KEY; CK_ULONG kt = CKK_RSA; CK_BYTE id[] = {0, 0}; char *label = "rsa_wrap"; CK_BBOOL wrap_capability = CK_TRUE; CK_BBOOL sign_capability = CK_TRUE; CK_ULONG key_len = keylen; CK_OBJECT_HANDLE pub_keyid; CK_MECHANISM mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0}; CK_ATTRIBUTE privateKeyTemplate[] = {{CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_ID, &id, sizeof(id)}, {CKA_LABEL, label, strlen(label)}, {CKA_UNWRAP, &wrap_capability, sizeof(wrap_capability)}, {CKA_SIGN, &sign_capability, sizeof(sign_capability)}}; CK_ATTRIBUTE publicKeyTemplate[] = {{CKA_CLASS, &class_c, sizeof(class_c)}, {CKA_MODULUS_BITS, &key_len, sizeof(key_len)}}; assert(p11->C_GenerateKeyPair(session, &mech, publicKeyTemplate, 2, privateKeyTemplate, 6, &pub_keyid, keyid) == CKR_OK); fprintf(stdout, "Generated RSA wrap key. Size %lu. Handle 0x%06lx\n", key_len, *keyid); } static void get_pub_wrapkey(CK_OBJECT_HANDLE key_handle, uint8_t *pubkey, size_t *pubkey_len) { CK_ATTRIBUTE template[] = { {CKA_MODULUS, pubkey, *pubkey_len}, }; assert(p11->C_GetAttributeValue(session, key_handle, template, 1) == CKR_OK); *pubkey_len = template[0].ulValueLen; } static void generate_rsa_wrapkey_with_attributes(void) { CK_ULONG class_k = CKO_PRIVATE_KEY; CK_ULONG class_c = CKO_PUBLIC_KEY; CK_ULONG kt = CKK_RSA; char *label = "rsa_wrap"; CK_BBOOL attr_true = CK_TRUE; CK_BBOOL attr_false = CK_FALSE; CK_ULONG key_len = 2048; CK_OBJECT_HANDLE priv_keyid; CK_OBJECT_HANDLE pub_keyid; CK_MECHANISM mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0}; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_SENSITIVE, &attr_true, sizeof(attr_true)}, {CKA_TOKEN, &attr_true, sizeof(attr_true)}, {CKA_PRIVATE, &attr_true, sizeof(attr_true)}, {CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_LABEL, label, strlen(label)}, {CKA_SIGN, &attr_true, sizeof(attr_true)}, {CKA_DECRYPT, &attr_false, sizeof(attr_false)}, {CKA_UNWRAP, &attr_true, sizeof(attr_true)}, {CKA_DERIVE, &attr_false, sizeof(attr_false)}, {CKA_EXTRACTABLE, &attr_false, sizeof(attr_false)}, {CKA_MODIFIABLE, &attr_false, sizeof(attr_false)} }; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_MODULUS_BITS, &key_len, sizeof(key_len)}, {CKA_CLASS, &class_c, sizeof(class_c)}, {CKA_TOKEN, &attr_true, sizeof(attr_true)}, {CKA_PRIVATE, &attr_false, sizeof(attr_false)}, {CKA_LABEL, label, strlen(label)}, {CKA_VERIFY, &attr_true, sizeof(attr_true)}, {CKA_ENCRYPT, &attr_false, sizeof(attr_false)}, {CKA_WRAP, &attr_false, sizeof(attr_false)}, {CKA_DERIVE, &attr_false, sizeof(attr_false)}, {CKA_MODIFIABLE, &attr_false, sizeof(attr_false)}, }; assert(p11->C_GenerateKeyPair(session, &mech, publicKeyTemplate, 10, privateKeyTemplate, 12, &pub_keyid, &priv_keyid) == CKR_OK); uint8_t object_type = (priv_keyid >> 16); assert(object_type == YH_WRAP_KEY); fprintf(stdout, "Generated RSA wrap key when CKA_UNWRAP is set\n"); CK_BOOL priv_sensitive; CK_BOOL priv_token, pub_token; CK_BOOL priv_private, pub_private; CK_ULONG priv_class, pub_class; CK_ULONG priv_key_type, pub_key_type; char priv_label[64] = {0}, pub_label[64] = {0}; CK_BOOL priv_sign; CK_BOOL priv_decrypt; CK_BOOL priv_unwrap, pub_wrap; CK_BOOL priv_derive, pub_derive; CK_BOOL priv_extractable; CK_BOOL priv_modifiable, pub_modifiable; CK_BOOL pub_verify; CK_BOOL pub_encrypt; CK_ULONG pub_modulus_bits; uint8_t pubkey[2048] = {0}; size_t pubkey_len = sizeof(pubkey); CK_ATTRIBUTE priv_attrs[] = { {CKA_SENSITIVE, &priv_sensitive, sizeof(priv_sensitive)}, {CKA_TOKEN, &priv_token, sizeof(priv_token)}, {CKA_PRIVATE, &priv_private, sizeof(priv_private)}, {CKA_CLASS, &priv_class, sizeof(priv_class)}, {CKA_KEY_TYPE, &priv_key_type, sizeof(priv_key_type)}, {CKA_LABEL, &priv_label, sizeof(priv_label)}, {CKA_SIGN, &priv_sign, sizeof(priv_sign)}, {CKA_DECRYPT, &priv_decrypt, sizeof(priv_decrypt)}, {CKA_UNWRAP, &priv_unwrap, sizeof(priv_unwrap)}, {CKA_DERIVE, &priv_derive, sizeof(priv_derive)}, {CKA_EXTRACTABLE, &priv_extractable, sizeof(priv_extractable)}, {CKA_MODIFIABLE, &priv_modifiable, sizeof(priv_modifiable)}, {CKA_MODULUS, pubkey, pubkey_len}, }; assert(p11->C_GetAttributeValue(session, priv_keyid, priv_attrs, 13) == CKR_OK); assert(priv_sensitive == CK_TRUE); assert(priv_token == CK_TRUE); assert(priv_private == CK_TRUE); assert(priv_class == CKO_PRIVATE_KEY); assert(priv_key_type == CKK_RSA); assert(strncmp(priv_label, label, strlen(label)) == 0); assert(priv_sign == CK_FALSE); assert(priv_decrypt == CK_FALSE); assert(priv_unwrap == CK_TRUE); assert(priv_derive == CK_FALSE); assert(priv_extractable == CK_FALSE); assert(priv_modifiable == CK_FALSE); assert(pubkey_len == key_len); CK_ATTRIBUTE pub_attrs[] = { {CKA_MODULUS_BITS, &pub_modulus_bits, sizeof(pub_modulus_bits)}, {CKA_CLASS, &pub_class, sizeof(pub_class)}, {CKA_TOKEN, &pub_token, sizeof(pub_token)}, {CKA_PRIVATE, &pub_private, sizeof(pub_private)}, {CKA_KEY_TYPE, &pub_key_type, sizeof(pub_key_type)}, {CKA_LABEL, &pub_label, sizeof(pub_label)}, {CKA_VERIFY, &pub_verify, sizeof(pub_verify)}, {CKA_ENCRYPT, &pub_encrypt, sizeof(pub_encrypt)}, {CKA_WRAP, &pub_wrap, sizeof(pub_wrap)}, {CKA_DERIVE, &pub_derive, sizeof(pub_derive)}, {CKA_MODIFIABLE, &pub_modifiable, sizeof(pub_modifiable)}, }; assert(p11->C_GetAttributeValue(session, pub_keyid, pub_attrs, 11) == CKR_OK); assert(pub_modulus_bits == key_len); assert(pub_token == CK_TRUE); assert(pub_private == CK_FALSE); assert(pub_class == CKO_PUBLIC_KEY); assert(pub_key_type == CKK_RSA); assert(strcmp(pub_label, label) == 0); assert(pub_verify == CK_FALSE); assert(pub_encrypt == CK_FALSE); assert(pub_wrap == CK_FALSE); assert(pub_derive == CK_FALSE); assert(pub_modifiable == CK_FALSE); destroy_object(p11, session, priv_keyid); destroy_object(p11, session, pub_keyid); } static void generate_not_rsa_wrapkey(void) { CK_ULONG class_k = CKO_PRIVATE_KEY; CK_ULONG class_c = CKO_PUBLIC_KEY; CK_ULONG kt = CKK_RSA; char *label = "not-rsa_wrap"; CK_BBOOL attr_true = CK_TRUE; CK_BBOOL attr_false = CK_FALSE; CK_ULONG key_len = 2048; CK_OBJECT_HANDLE priv_keyid; CK_OBJECT_HANDLE pub_keyid; CK_MECHANISM mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0}; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_SENSITIVE, &attr_true, sizeof(attr_true)}, {CKA_TOKEN, &attr_true, sizeof(attr_true)}, {CKA_PRIVATE, &attr_true, sizeof(attr_true)}, {CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_LABEL, label, strlen(label)}, {CKA_SIGN, &attr_true, sizeof(attr_true)}, {CKA_DECRYPT, &attr_false, sizeof(attr_false)}, {CKA_UNWRAP, &attr_false, sizeof(attr_false)}, {CKA_DERIVE, &attr_false, sizeof(attr_false)}, {CKA_EXTRACTABLE, &attr_false, sizeof(attr_false)}, {CKA_MODIFIABLE, &attr_false, sizeof(attr_false)} }; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_MODULUS_BITS, &key_len, sizeof(key_len)}, {CKA_CLASS, &class_c, sizeof(class_c)}, {CKA_TOKEN, &attr_true, sizeof(attr_true)}, {CKA_PRIVATE, &attr_false, sizeof(attr_false)}, {CKA_LABEL, label, strlen(label)}, {CKA_VERIFY, &attr_true, sizeof(attr_true)}, {CKA_ENCRYPT, &attr_false, sizeof(attr_false)}, {CKA_WRAP, &attr_false, sizeof(attr_false)}, {CKA_DERIVE, &attr_false, sizeof(attr_false)}, {CKA_MODIFIABLE, &attr_false, sizeof(attr_false)}, }; assert(p11->C_GenerateKeyPair(session, &mech, publicKeyTemplate, 10, privateKeyTemplate, 12, &pub_keyid, &priv_keyid) == CKR_OK); uint8_t object_type = (priv_keyid >> 16); assert(object_type == YH_ASYMMETRIC_KEY); fprintf(stdout, "Generated RSA asymmetric key when CKA_UNWRAP is not set\n"); destroy_object(p11, session, priv_keyid); destroy_object(p11, session, pub_keyid); } static void get_wrapped_data(CK_OBJECT_HANDLE wrapping_keyid, CK_OBJECT_HANDLE keyid, uint8_t *wrapped_obj, CK_ULONG_PTR wrapped_obj_len, bool only_key) { CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, 0, NULL, 0}; CK_RSA_AES_KEY_WRAP_PARAMS params = {256, &oaep_params}; CK_MECHANISM mech = {0, ¶ms, sizeof(params)}; if (only_key) { mech.mechanism = CKM_RSA_AES_KEY_WRAP; } else { mech.mechanism = CKM_YUBICO_RSA_WRAP; } assert(p11->C_WrapKey(session, &mech, wrapping_keyid, keyid, wrapped_obj, wrapped_obj_len) == CKR_OK); } static CK_OBJECT_HANDLE import_wrapped_data(CK_OBJECT_HANDLE wrapping_keyid, uint8_t *wrapped_obj, CK_ULONG wrapped_obj_len, bool only_key, CK_ULONG key_type) { CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, 0, NULL, 0}; CK_RSA_AES_KEY_WRAP_PARAMS params = {256, &oaep_params}; CK_MECHANISM mech = {0, ¶ms, sizeof(params)}; if (only_key) { mech.mechanism = CKM_RSA_AES_KEY_WRAP; } else { mech.mechanism = CKM_YUBICO_RSA_WRAP; } CK_OBJECT_HANDLE imported_keyhandle; CK_ULONG kt = key_type; CK_ULONG class_k = kt == CKK_EC ? CKO_PRIVATE_KEY : CKO_SECRET_KEY; if (kt == CKK_EC) { CK_BYTE ec_params[] = {0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; CK_BBOOL sign_capability = CK_TRUE; CK_ATTRIBUTE template[] = {{CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_SIGN, &sign_capability, sizeof(sign_capability)}, {CKA_EC_PARAMS, ec_params, sizeof(ec_params)}}; assert(p11->C_UnwrapKey(session, &mech, wrapping_keyid, wrapped_obj, wrapped_obj_len, template, 4, &imported_keyhandle) == CKR_OK); } else { CK_ULONG keylen = 32; CK_BBOOL encrypt_capability = CK_TRUE; CK_BBOOL decrypt_capability = CK_TRUE; CK_ATTRIBUTE template[] = {{CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_DECRYPT, &decrypt_capability, sizeof(decrypt_capability)}, {CKA_ENCRYPT, &encrypt_capability, sizeof(encrypt_capability)}, {CKA_VALUE_LEN, &keylen, sizeof(keylen)}}; assert(p11->C_UnwrapKey(session, &mech, wrapping_keyid, wrapped_obj, wrapped_obj_len, template, 5, &imported_keyhandle) == CKR_OK); } return imported_keyhandle; } static void find_rsa_wrapkey(CK_OBJECT_HANDLE keyid, size_t key_size) { CK_BBOOL wrap_capability = CK_TRUE; char *label = "rsa_wrap"; CK_ATTRIBUTE template[] = {{CKA_LABEL, label, strlen(label)}, {CKA_UNWRAP, &wrap_capability, sizeof(wrap_capability)}}; CK_OBJECT_HANDLE objects[10] = {0}; CK_ULONG n_objects = 0; assert(p11->C_FindObjectsInit(session, template, 2) == CKR_OK); assert(p11->C_FindObjects(session, objects, 10, &n_objects) == CKR_OK); assert(p11->C_FindObjectsFinal(session) == CKR_OK); assert(n_objects == 1); assert(objects[0] == keyid); CK_ULONG mod_bits = 0; CK_ATTRIBUTE value_template[] = { {CKA_MODULUS_BITS, &mod_bits, sizeof(CK_ULONG)}}; assert(p11->C_GetAttributeValue(session, objects[0], value_template, 1) == CKR_OK); assert(mod_bits == key_size); } static void find_pub_rsa_wrapkey(CK_OBJECT_HANDLE keyid, size_t key_size) { CK_BBOOL wrap_capability = CK_TRUE; char *label = "pub_rsa_wrap"; CK_ATTRIBUTE template[] = {{CKA_LABEL, label, strlen(label)}, {CKA_WRAP, &wrap_capability, sizeof(wrap_capability)}}; CK_OBJECT_HANDLE objects[10] = {0}; CK_ULONG n_objects = 0; assert(p11->C_FindObjectsInit(session, template, 2) == CKR_OK); assert(p11->C_FindObjects(session, objects, 10, &n_objects) == CKR_OK); assert(p11->C_FindObjectsFinal(session) == CKR_OK); assert(n_objects == 1); assert(objects[0] == keyid); CK_ULONG mod_bits = 0; CK_ULONG key_type = 0; CK_ATTRIBUTE value_template[] = {{CKA_MODULUS_BITS, &mod_bits, sizeof(CK_ULONG)}, {CKA_KEY_TYPE, &key_type, sizeof(CK_ULONG)}}; assert(p11->C_GetAttributeValue(session, objects[0], value_template, 2) == CKR_OK); assert(mod_bits == key_size); assert(key_type == CKK_RSA); } static CK_OBJECT_HANDLE get_public_key_handle(CK_OBJECT_HANDLE privkey) { CK_OBJECT_HANDLE found_obj[10] = {0}; CK_ULONG n_found_obj = 0; CK_ULONG class_pub = CKO_PUBLIC_KEY; uint16_t ckaid = 0; CK_ATTRIBUTE idTemplate[] = { {CKA_ID, &ckaid, sizeof(ckaid)} }; CK_ATTRIBUTE idClassTemplate[] = { {CKA_ID, &ckaid, sizeof(ckaid)}, {CKA_CLASS, &class_pub, sizeof(class_pub)} }; assert(p11->C_GetAttributeValue(session, privkey, idTemplate, 1) == CKR_OK); assert(p11->C_FindObjectsInit(session, idClassTemplate, 2) == CKR_OK); assert(p11->C_FindObjects(session, found_obj, 10, &n_found_obj) == CKR_OK); assert(n_found_obj == 1); assert(p11->C_FindObjectsFinal(session) == CKR_OK); return found_obj[0]; } static void do_ecdsa_sign(CK_OBJECT_HANDLE eckey) { CK_MECHANISM mech = {CKM_ECDSA_SHA1, NULL, 0}; CK_BYTE sig[64] = {0}; CK_ULONG sig_len = sizeof(sig); CK_BYTE data[16] = {0}; CK_ULONG data_len = sizeof(data); assert((RAND_bytes(data, data_len) > 0)); assert(p11->C_SignInit(session, &mech, eckey) == CKR_OK); assert(p11->C_Sign(session, data, sizeof(data), sig, &sig_len) == CKR_OK); CK_OBJECT_HANDLE eckey_pub = get_public_key_handle(eckey); assert(p11->C_VerifyInit(session, &mech, eckey_pub) == CKR_OK); assert(p11->C_Verify(session, data, sizeof(data), sig, sig_len) == CKR_OK); } static void do_aesecb_encryption(CK_OBJECT_HANDLE aeskey) { CK_MECHANISM mech = {CKM_AES_ECB, NULL, 0}; CK_BYTE enc[16] = {0}; CK_ULONG enc_len = sizeof(enc); CK_BYTE dec[16] = {0}; CK_ULONG dec_len = sizeof(dec); CK_BYTE data[16] = {0}; CK_ULONG data_len = sizeof(data); assert((RAND_bytes(data, data_len) > 0)); assert(p11->C_EncryptInit(session, &mech, aeskey) == CKR_OK); assert(p11->C_Encrypt(session, data, sizeof(data), enc, &enc_len) == CKR_OK); assert(p11->C_DecryptInit(session, &mech, aeskey) == CKR_OK); assert(p11->C_Decrypt(session, enc, enc_len, dec, &dec_len) == CKR_OK); assert(dec_len == 16); assert(memcmp(data, dec, dec_len) == 0); } static void test_asym_wrapkey(CK_OBJECT_HANDLE_PTR eckey, CK_OBJECT_HANDLE_PTR aeskey, CK_OBJECT_HANDLE wrapkey, size_t keysize) { CK_OBJECT_HANDLE pub_wrapkey, imported_eckey, imported_aeskey; find_rsa_wrapkey(wrapkey, keysize); // Get public key of RSA wrap key: C_GetAttributeValue(CKA_MODULUS) uint8_t pubkey[2048] = {0}; size_t pubkey_len = sizeof(pubkey); get_pub_wrapkey(wrapkey, pubkey, &pubkey_len); fprintf(stdout, "Got public key for RSA wrap key 0x%06lx. OK!\n", wrapkey); // Import the public key of the RSA wrap key as a public wrap key // C_CreateObject(RSA Public Key) pub_wrapkey = import_rsa_pub_wrapkey(pubkey, pubkey_len); fprintf(stdout, "Imported RSA public wrap key of size %zu. ID 0x%06lx OK!\n", keysize, pub_wrapkey); find_pub_rsa_wrapkey(pub_wrapkey, keysize); // Wrap EC key material then import it again as an RSA wrapped key // C_WrapKey, C_UnwrapKey uint8_t wrapped_key[2048] = {0}; CK_ULONG wrapped_key_len = sizeof(wrapped_key); get_wrapped_data(pub_wrapkey, *eckey, wrapped_key, &wrapped_key_len, true); fprintf(stdout, "Got wrapped EC key material. %lu bytes. OK!\n", wrapped_key_len); imported_eckey = import_wrapped_data(wrapkey, wrapped_key, wrapped_key_len, true, CKK_EC); fprintf(stdout, "Imported unwrapped EC key material. 0x%06lx. OK!\n", imported_eckey); do_ecdsa_sign(imported_eckey); fprintf(stdout, "Signed using imported EC key. OK!\n"); // Wrap EC key object then import it again as an RSA wrapped object // C_WrapKey, C_UnwrapKey memset(wrapped_key, 0, sizeof(wrapped_key)); wrapped_key_len = sizeof(wrapped_key); get_wrapped_data(pub_wrapkey, *eckey, wrapped_key, &wrapped_key_len, false); fprintf(stdout, "Got wrapped EC key object. %lu bytes. OK!\n", wrapped_key_len); destroy_object(p11, session, *eckey); fprintf(stdout, "Removed EC key object. OK!\n"); *eckey = import_wrapped_data(wrapkey, wrapped_key, wrapped_key_len, false, CKK_EC); fprintf(stdout, "Imported unwrapped EC key object. OK!\n"); do_ecdsa_sign(*eckey); fprintf(stdout, "Signed using imported EC object. OK!\n"); // Wrap AES key material then import it again as an RSA wrapped key // C_WrapKey, C_UnwrapKey memset(wrapped_key, 0, sizeof(wrapped_key)); wrapped_key_len = sizeof(wrapped_key); get_wrapped_data(pub_wrapkey, *aeskey, wrapped_key, &wrapped_key_len, true); fprintf(stdout, "Got wrapped AES key material. %lu bytes. OK!\n", wrapped_key_len); imported_aeskey = import_wrapped_data(wrapkey, wrapped_key, wrapped_key_len, true, CKK_AES); fprintf(stdout, "Imported unwrapped AES key material. 0x%06lx. OK!\n", imported_aeskey); do_aesecb_encryption(imported_aeskey); fprintf(stdout, "Encrypted using imported AES key. OK!\n"); // Wrap AES key object then import it again as an RSA wrapped object // C_WrapKey, C_UnwrapKey memset(wrapped_key, 0, sizeof(wrapped_key)); wrapped_key_len = sizeof(wrapped_key); get_wrapped_data(pub_wrapkey, *aeskey, wrapped_key, &wrapped_key_len, false); fprintf(stdout, "Got wrapped AES key object. %lu bytes. OK!\n", wrapped_key_len); destroy_object(p11, session, *aeskey); fprintf(stdout, "Removed AES key object. OK!\n"); *aeskey = import_wrapped_data(wrapkey, wrapped_key, wrapped_key_len, false, CKK_AES); fprintf(stdout, "Imported unwrapped AES key object. OK!\n"); do_aesecb_encryption(*aeskey); fprintf(stdout, "Signed using imported AES object. OK!\n"); // Delete test keys destroy_object(p11, session, imported_eckey); destroy_object(p11, session, imported_aeskey); destroy_object(p11, session, pub_wrapkey); } static bool is_asymwrap_supported(void) { CK_SESSION_INFO info; CK_RV r; if ((r = p11->C_GetSessionInfo(session, &info)) != CKR_OK) { fprintf(stderr, "C_GetSessionInfo (r = %lu)\n", r); return CKR_FUNCTION_FAILED; } CK_MECHANISM_TYPE m[128]; CK_ULONG n = sizeof(m) / sizeof(m[0]); if ((r = p11->C_GetMechanismList(info.slotID, m, &n)) != CKR_OK) { fprintf(stderr, "C_GetMechanismList (r = %lu)\n", r); return CKR_FUNCTION_FAILED; } for (CK_ULONG i = 0; i < n; i++) { if (m[i] == CKM_YUBICO_RSA_WRAP) { return true; } } return false; } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: /path/to/yubihsm_pkcs11/module\n"); exit(EXIT_FAILURE); } void *handle = open_module(argv[1]); p11 = get_function_list(handle); session = open_session(p11); print_session_state(p11, session); if (!is_asymwrap_supported()) { goto clean; } generate_not_rsa_wrapkey(); generate_rsa_wrapkey_with_attributes(); const char *keys[] = {rsa2048, rsa3072, rsa4096}; size_t keysizes[] = {2048, 3072, 4096}; // Generate EC key to wrap CK_OBJECT_HANDLE ec_pubkey, ec_privkey, aes_key; generate_ec_keys(&ec_pubkey, &ec_privkey); generate_aes_key(&aes_key); for (int i = 0; i < 3; i++) { CK_OBJECT_HANDLE wrapkey; generate_rsa_wrapkey(keysizes[i], &wrapkey); assert(wrapkey != 0); test_asym_wrapkey(&ec_privkey, &aes_key, wrapkey, keysizes[i]); destroy_object(p11, session, wrapkey); wrapkey = 0; import_rsa_wrapkey(keys[i], keysizes[i], &wrapkey); assert(wrapkey != 0); test_asym_wrapkey(&ec_privkey, &aes_key, wrapkey, keysizes[i]); destroy_object(p11, session, wrapkey); } destroy_object(p11, session, ec_privkey); destroy_object(p11, session, aes_key); printf("OK!\n"); clean: close_session(p11, session); close_module(handle); return (EXIT_SUCCESS); } yubihsm-shell-2.7.3/pkcs11/tests/aes_encrypt_test.c0000644000175000017500000004364315167357110021271 0ustar aveenaveen/* * Copyright 2021-2022 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #undef NDEBUG #include #include #include #include #include "../pkcs11y.h" #include "common.h" #define FAIL(fmt, ...) \ do { \ fprintf(stderr, "%s:%d (%s): " fmt "\n", __FILE__, __LINE__, __func__, \ __VA_ARGS__); \ } while (0) #define nitems(a) (sizeof(a) / sizeof(a[0])) // Disabling automatic formatting so that clang-format does not reflow // the plaintext blocks. Each row corresponds to a whole block. // clang-format off #define PLAINTEXT_LENGTH (4 * 16) static uint8_t plaintext[PLAINTEXT_LENGTH] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, }; // clang-format on #define TEST_ECB(key, ptlen, ct) \ { CKM_AES_ECB, key, sizeof(key) - 1, ptlen, ct, sizeof(ct) - 1 } #define TEST_CBC(key, ptlen, ct) \ { CKM_AES_CBC, key, sizeof(key) - 1, ptlen, ct, sizeof(ct) - 1 } #define TEST_CBC_PAD(key, ptlen, ct) \ { CKM_AES_CBC_PAD, key, sizeof(key) - 1, ptlen, ct, sizeof(ct) - 1 } struct test { CK_MECHANISM_TYPE mechanism; uint8_t key[32 + 1]; uint8_t keylen; size_t plaintext_len; uint8_t ciphertext[sizeof(plaintext) + 16 + 1]; size_t ciphertext_len; }; static uint8_t iv[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }; // CKM_AES_{ECB,CBC} test vectors from NIST. // CKM_AES_CBC_PAD calculated out-of-band. static struct test tests[] = { TEST_ECB("\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", PLAINTEXT_LENGTH, "\x3a\xd7\x7b\xb4\x0d\x7a\x36\x60\xa8\x9e\xca\xf3\x24\x66\xef\x97" "\xf5\xd3\xd5\x85\x03\xb9\x69\x9d\xe7\x85\x89\x5a\x96\xfd\xba\xaf" "\x43\xb1\xcd\x7f\x59\x8e\xce\x23\x88\x1b\x00\xe3\xed\x03\x06\x88" "\x7b\x0c\x78\x5e\x27\xe8\xad\x3f\x82\x23\x20\x71\x04\x72\x5d\xd4"), TEST_ECB("\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", PLAINTEXT_LENGTH, "\xbd\x33\x4f\x1d\x6e\x45\xf2\x5f\xf7\x12\xa2\x14\x57\x1f\xa5\xcc" "\x97\x41\x04\x84\x6d\x0a\xd3\xad\x77\x34\xec\xb3\xec\xee\x4e\xef" "\xef\x7a\xfd\x22\x70\xe2\xe6\x0a\xdc\xe0\xba\x2f\xac\xe6\x44\x4e" "\x9a\x4b\x41\xba\x73\x8d\x6c\x72\xfb\x16\x69\x16\x03\xc1\x8e\x0e"), TEST_ECB("\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", PLAINTEXT_LENGTH, "\xf3\xee\xd1\xbd\xb5\xd2\xa0\x3c\x06\x4b\x5a\x7e\x3d\xb1\x81\xf8" "\x59\x1c\xcb\x10\xd4\x10\xed\x26\xdc\x5b\xa7\x4a\x31\x36\x28\x70" "\xb6\xed\x21\xb9\x9c\xa6\xf4\xf9\xf1\x53\xe7\xb1\xbe\xaf\xed\x1d" "\x23\x30\x4b\x7a\x39\xf9\xf3\xff\x06\x7d\x8d\x8f\x9e\x24\xec\xc7"), TEST_CBC("\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", PLAINTEXT_LENGTH, "\x76\x49\xab\xac\x81\x19\xb2\x46\xce\xe9\x8e\x9b\x12\xe9\x19\x7d" "\x50\x86\xcb\x9b\x50\x72\x19\xee\x95\xdb\x11\x3a\x91\x76\x78\xb2" "\x73\xbe\xd6\xb8\xe3\xc1\x74\x3b\x71\x16\xe6\x9e\x22\x22\x95\x16" "\x3f\xf1\xca\xa1\x68\x1f\xac\x09\x12\x0e\xca\x30\x75\x86\xe1\xa7"), TEST_CBC("\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", PLAINTEXT_LENGTH, "\x4f\x02\x1d\xb2\x43\xbc\x63\x3d\x71\x78\x18\x3a\x9f\xa0\x71\xe8" "\xb4\xd9\xad\xa9\xad\x7d\xed\xf4\xe5\xe7\x38\x76\x3f\x69\x14\x5a" "\x57\x1b\x24\x20\x12\xfb\x7a\xe0\x7f\xa9\xba\xac\x3d\xf1\x02\xe0" "\x08\xb0\xe2\x79\x88\x59\x88\x81\xd9\x20\xa9\xe6\x4f\x56\x15\xcd"), TEST_CBC("\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", PLAINTEXT_LENGTH, "\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6" "\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d\x67\x9f\x77\x7b\xc6\x70\x2c\x7d" "\x39\xf2\x33\x69\xa9\xd9\xba\xcf\xa5\x30\xe2\x63\x04\x23\x14\x61" "\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc\xda\x6c\x19\x07\x8c\x6a\x9d\x1b"), TEST_CBC_PAD( "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", PLAINTEXT_LENGTH - 15, "\x76\x49\xab\xac\x81\x19\xb2\x46\xce\xe9\x8e\x9b\x12\xe9\x19\x7d" "\x50\x86\xcb\x9b\x50\x72\x19\xee\x95\xdb\x11\x3a\x91\x76\x78\xb2" "\x73\xbe\xd6\xb8\xe3\xc1\x74\x3b\x71\x16\xe6\x9e\x22\x22\x95\x16" "\x29\xe0\x8a\x17\xfd\xdd\xdd\xe8\x6d\xa9\xbc\xaf\x31\xe0\x28\xd8"), TEST_CBC_PAD( "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", PLAINTEXT_LENGTH - 1, "\x4f\x02\x1d\xb2\x43\xbc\x63\x3d\x71\x78\x18\x3a\x9f\xa0\x71\xe8" "\xb4\xd9\xad\xa9\xad\x7d\xed\xf4\xe5\xe7\x38\x76\x3f\x69\x14\x5a" "\x57\x1b\x24\x20\x12\xfb\x7a\xe0\x7f\xa9\xba\xac\x3d\xf1\x02\xe0" "\x89\x7e\x29\x85\x3a\x69\x34\xfd\x58\x9f\xc9\x3e\x7a\xf0\x37\x49"), TEST_CBC_PAD( "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", PLAINTEXT_LENGTH, "\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6" "\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d\x67\x9f\x77\x7b\xc6\x70\x2c\x7d" "\x39\xf2\x33\x69\xa9\xd9\xba\xcf\xa5\x30\xe2\x63\x04\x23\x14\x61" "\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc\xda\x6c\x19\x07\x8c\x6a\x9d\x1b" "\x3f\x46\x17\x96\xd6\xb0\xd6\xb2\xe0\xc2\xa7\x2b\x4d\x80\xe6\x44"), }; static CK_BBOOL g_true = TRUE; static CK_RV create_aes_key(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session, CK_BYTE_PTR key, CK_ULONG len, CK_OBJECT_HANDLE *handle) { CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE type = CKK_AES; CK_ATTRIBUTE templ[] = {{CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &type, sizeof(type)}, {CKA_ENCRYPT, &g_true, sizeof(g_true)}, {CKA_DECRYPT, &g_true, sizeof(g_true)}, {CKA_VALUE, key, len}}; return p11->C_CreateObject(session, templ, nitems(templ), handle); } typedef CK_RV (*InitFunc)(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE); typedef CK_RV (*SingleFunc)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR); typedef CK_RV (*FinalFunc)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); typedef SingleFunc UpdateFunc; typedef size_t (*CalculateOutputSize)(size_t, size_t); static int do_test_single_part(InitFunc init, SingleFunc single, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE handle, CK_MECHANISM mechanism, const uint8_t *input, size_t inlen, const uint8_t *output, size_t outlen) { uint8_t buffer[PLAINTEXT_LENGTH + 16]; CK_ULONG len; CK_RV rv; if (inlen > sizeof(buffer) || outlen > sizeof(buffer)) { FAIL("%s", "input or expected output data too large"); return -1; } // Initialize the operation. if ((rv = init(session, &mechanism, handle)) != CKR_OK) { FAIL("init failed (rv=0x%lx)", rv); return -1; } memcpy(buffer, input, inlen); // Test querying output size. len = 0; if ((rv = single(session, buffer, inlen, NULL, &len)) != CKR_OK || len < outlen) { FAIL("single size query failed (rv=0x%lx, %lu, %zu)", rv, len, outlen); return -1; } // Test CKR_BUFFER_TOO_SMALL. len = outlen - 1; if ((rv = single(session, buffer, inlen, buffer, &len)) != CKR_BUFFER_TOO_SMALL || len < outlen) { FAIL("single did not return CKR_BUFFER_TOO_SMALL (rv=0x%lx, %lu, %zu)", rv, len, outlen); return -1; } // If the function call was supposed to modify the contents of certain // memory addresses on the host computer, these memory addresses may // have been modified, despite the failure of the function. // PKCS#11 version 2.4; section 5 memcpy(buffer, input, inlen); // Test actual operation. if ((rv = single(session, buffer, inlen, buffer, &len)) != CKR_OK || len != outlen) { FAIL("single failed (rv=0x%lx, %lu, %zu)", rv, len, outlen); return -1; } // Verify expected data. if (memcmp(buffer, output, outlen)) { FAIL("%s", "memcmp failed"); return -1; } return 0; } static int test_single_part(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE handle, struct test *test) { CK_MECHANISM mechanism = {test->mechanism, NULL, 0}; if (mechanism.mechanism != CKM_AES_ECB) { mechanism.pParameter = iv; mechanism.ulParameterLen = sizeof(iv); } if (do_test_single_part(p11->C_EncryptInit, p11->C_Encrypt, session, handle, mechanism, plaintext, test->plaintext_len, test->ciphertext, test->ciphertext_len) != 0) { FAIL("%s", "single part encryption failed"); return -1; } if (do_test_single_part(p11->C_DecryptInit, p11->C_Decrypt, session, handle, mechanism, test->ciphertext, test->ciphertext_len, plaintext, test->plaintext_len) != 0) { FAIL("%s", "single part decryption failed"); return -1; } return CKR_OK; } #define BUFFER_OFFSET(b, p) ((size_t)((p) - (b))) /* assumes p >= b*/ static int do_test_multiple_part(InitFunc init, UpdateFunc update, FinalFunc finalize, CalculateOutputSize calc_output_size, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE handle, CK_MECHANISM mechanism, const uint8_t *input, size_t inlen, const uint8_t *output, size_t outlen) { uint8_t buffer[PLAINTEXT_LENGTH + 16]; CK_ULONG len; CK_RV rv; if (inlen > sizeof(buffer) || outlen > sizeof(buffer)) { FAIL("%s", "input or expected output data too large"); return -1; } // Initialize the operation. if ((rv = init(session, &mechanism, handle)) != CKR_OK) { FAIL("init failed (rv=0x%lx)", rv); return -1; } memcpy(buffer, input, inlen); CK_BYTE_PTR cin = buffer, cout = buffer; while (inlen != 0) { CK_ULONG chunksiz = inlen > 3 ? 3 : inlen; // Verify output size. size_t pending = calc_output_size(BUFFER_OFFSET(buffer, cin + chunksiz), BUFFER_OFFSET(buffer, cout)); // Query the output size. len = 0; if ((rv = update(session, cin, chunksiz, NULL, &len)) != CKR_OK || len != pending) { FAIL("update size query failed (rv=0x%lx, %lu, %zu)", rv, len, pending); return -1; } // Check the CKR_BUFFER_TOO_SMALL case. if (len != 0) { CK_ULONG too_small = len - 1; if ((rv = update(session, cin, chunksiz, cout, &too_small)) != CKR_BUFFER_TOO_SMALL || too_small != len) { FAIL("update did not return CKR_BUFFER_TOO_SMALL (rv=0x%lx, %lu, %lu)", rv, too_small, len); return -1; } } // Perform the actual update. len = sizeof(buffer) - BUFFER_OFFSET(buffer, cout); if ((rv = update(session, cin, chunksiz, cout, &len)) != CKR_OK) { FAIL("update failed (rv=0x%lx)", rv); return -1; } cin += chunksiz; cout += len; inlen -= chunksiz; } size_t remain = outlen - BUFFER_OFFSET(buffer, cout); // Check that querying size works. len = 0; if ((rv = finalize(session, NULL, &len)) != CKR_OK || len < remain) { FAIL("finalize size query failed (rv=0x%lx, %lu, %zu)", rv, len, remain); return -1; } // Check the CKR_BUFFER_TOO_SMALL case. if (remain != 0) { CK_ULONG too_small = remain - 1; if ((rv = finalize(session, cout, &too_small)) != CKR_BUFFER_TOO_SMALL || too_small != remain) { FAIL("finalize did not return CKR_BUFFER_TOO_SMALL (rv=0x%lx, %lu, %zu)", rv, too_small, remain); return -1; } } // Finalize the operation. len = sizeof(buffer) - BUFFER_OFFSET(buffer, cout); if ((rv = finalize(session, cout, &len)) != CKR_OK) { FAIL("finalize failed (rv=0x%lx)", rv); return -1; } // Check against the expected ciphertext. cout += len; if (BUFFER_OFFSET(buffer, cout) != outlen) { FAIL("finalize output length does not match (%zu != %zu)", BUFFER_OFFSET(buffer, cout), outlen); return -1; } if (memcmp(buffer, output, outlen)) { FAIL("%s", "memcmp failed"); return -1; } return 0; } static size_t simple_output_size(size_t in, size_t out) { size_t pending = in - out; pending /= 16; pending *= 16; return pending; } static size_t pad_output_size(size_t in, size_t out) { size_t pending = in - out; return pending <= 16 ? 0 : simple_output_size(in, out); } static CK_RV test_multiple_part(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE handle, struct test *test) { CK_MECHANISM mechanism = {test->mechanism, NULL, 0}; if (mechanism.mechanism != CKM_AES_ECB) { mechanism.pParameter = iv; mechanism.ulParameterLen = sizeof(iv); } if (do_test_multiple_part(p11->C_EncryptInit, p11->C_EncryptUpdate, p11->C_EncryptFinal, simple_output_size, session, handle, mechanism, plaintext, test->plaintext_len, test->ciphertext, test->ciphertext_len) != 0) { FAIL("%s", "multiple part encryption failed"); return -1; } if (do_test_multiple_part(p11->C_DecryptInit, p11->C_DecryptUpdate, p11->C_DecryptFinal, mechanism.mechanism == CKM_AES_CBC_PAD ? pad_output_size : simple_output_size, session, handle, mechanism, test->ciphertext, test->ciphertext_len, plaintext, test->plaintext_len) != 0) { FAIL("%s", "multiple part decryption failed"); return -1; } return CKR_OK; } static int run_test(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session, struct test *test) { CK_OBJECT_HANDLE handle = 0; int rv; if (create_aes_key(p11, session, test->key, test->keylen, &handle) != CKR_OK) { FAIL("%s", "Could not create AES key"); return -1; } if ((rv = test_single_part(p11, session, handle, test)) != 0 || (rv = test_multiple_part(p11, session, handle, test)) != 0) goto end; end: destroy_object(p11, session, handle); return rv; } static CK_RV is_aes_supported(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session) { CK_SESSION_INFO info; CK_RV r; if ((r = p11->C_GetSessionInfo(session, &info)) != CKR_OK) { fprintf(stderr, "C_GetSessionInfo (r = %lu)\n", r); return CKR_FUNCTION_FAILED; } CK_MECHANISM_TYPE m[128]; CK_ULONG n = nitems(m); if ((r = p11->C_GetMechanismList(info.slotID, m, &n)) != CKR_OK) { fprintf(stderr, "C_GetMechanismList (r = %lu)\n", r); return CKR_FUNCTION_FAILED; } unsigned int x = 0; for (CK_ULONG i = 0; i < n; i++) { if (m[i] == CKM_AES_ECB) x |= 0x1; else if (m[i] == CKM_AES_CBC) x |= 0x2; else if (m[i] == CKM_AES_CBC_PAD) x |= 0x4; } if ((x >> 1) && (x >> 1) != 0x3) { fprintf(stderr, "CKM_AES_CBC_PAD and CKM_AES_CBC_PAD are toggled together\n"); return CKR_FUNCTION_FAILED; } if (x != 0x7) { fprintf(stderr, "CKM_AES_{ECB,CBC} disabled or unsupported\n"); return CKR_MECHANISM_INVALID; } return CKR_OK; } static const char *mechstr(CK_MECHANISM_TYPE mech) { switch (mech) { case CKM_AES_ECB: return "CKM_AES_ECB"; case CKM_AES_CBC: return "CKM_AES_CBC"; case CKM_AES_CBC_PAD: return "CKM_AES_CBC_PAD"; default: return "unknown"; } } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: /path/to/yubihsm_pkcs11/module\n"); exit(EXIT_FAILURE); } void *handle = open_module(argv[1]); CK_FUNCTION_LIST_3_0_PTR p11 = get_function_list(handle); CK_SESSION_HANDLE session = open_session(p11); print_session_state(p11, session); int st = EXIT_SUCCESS; CK_RV rv = is_aes_supported(p11, session); if (rv == CKR_MECHANISM_INVALID) { st = 64; /* arbitrarily chosen */ goto out; } else if (rv != CKR_OK) { st = EXIT_FAILURE; goto out; } for (size_t i = 0; i < nitems(tests); i++) { fprintf(stderr, "Running test %zu (%s, AES%d)... ", i, mechstr(tests[i].mechanism), tests[i].keylen * 8); if (run_test(p11, session, &tests[i]) != 0) { fprintf(stderr, "FAIL\n"); st = EXIT_FAILURE; } else { fprintf(stderr, "OK\n"); } } out: close_session(p11, session); close_module(handle); return st; } yubihsm-shell-2.7.3/pkcs11/tests/ecdh_derive_test.c0000644000175000017500000010130115167357110021200 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include "../pkcs11y.h" #include "common.h" #define BUFSIZE 1024 CK_BYTE P224_PARAMS[] = {0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x21}; CK_BYTE P256_PARAMS[] = {0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; CK_BYTE P384_PARAMS[] = {0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22}; CK_BYTE P521_PARAMS[] = {0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23}; CK_BYTE BP256_PARAMS[] = {0x06, 0x09, 0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07}; static CK_FUNCTION_LIST_3_0_PTR p11; static CK_SESSION_HANDLE session; char *CURVES[] = {"secp224r1", "prime256v1", "secp384r1", "secp521r1", "brainpoolP256r1"}; CK_BYTE *CURVE_PARAMS[] = {P224_PARAMS, P256_PARAMS, P384_PARAMS, P521_PARAMS, BP256_PARAMS}; CK_ULONG CURVE_LENS[] = {sizeof(P224_PARAMS), sizeof(P256_PARAMS), sizeof(P384_PARAMS), sizeof(P521_PARAMS), sizeof(BP256_PARAMS)}; int CURVE_COUNT = sizeof(CURVE_PARAMS) / sizeof(CURVE_PARAMS[0]); static void success(const char *message) { printf("%s. OK\n", message); } static void fail(const char *message) { printf("%s. FAIL!\n", message); } static void generate_keypair_yh(CK_BYTE *curve, CK_ULONG curve_len, CK_OBJECT_HANDLE_PTR publicKeyPtr, CK_OBJECT_HANDLE_PTR privateKeyPtr) { CK_MECHANISM mechanism = {CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0}; CK_BBOOL ck_true = CK_TRUE; CK_BBOOL ck_false = CK_FALSE; CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY; CK_OBJECT_CLASS privkey_class = CKO_PRIVATE_KEY; CK_KEY_TYPE key_type = CKK_EC; char *label = "ecdhtest"; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_CLASS, &pubkey_class, sizeof(pubkey_class)}, {CKA_TOKEN, &ck_false, sizeof(ck_false)}, {CKA_LABEL, label, strlen(label)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_EC_PARAMS, curve, curve_len}, {CKA_VERIFY, &ck_true, sizeof(ck_true)} }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_CLASS, &privkey_class, sizeof(privkey_class)}, {CKA_TOKEN, &ck_true, sizeof(ck_true)}, {CKA_LABEL, label, strlen(label)}, {CKA_DERIVE, &ck_true, sizeof(ck_true)} }; if ((p11->C_GenerateKeyPair(session, &mechanism, publicKeyTemplate, 6, privateKeyTemplate, 4, publicKeyPtr, privateKeyPtr)) != CKR_OK) { fail("Failed to generate EC key pair on YubiHSM"); exit(EXIT_FAILURE); } success("Generated EC key pair on YubiHSM"); } static EVP_PKEY *generate_keypair_openssl(const char *curve) { EVP_PKEY *pkey = NULL; EC_KEY *eckey = NULL; OpenSSL_add_all_algorithms(); int eccgrp = OBJ_txt2nid(curve); eckey = EC_KEY_new_by_curve_name(eccgrp); if (!(EC_KEY_generate_key(eckey))) { fail("Failed to generate EC keypair with openssl"); } else { pkey = EVP_PKEY_new(); if (!EVP_PKEY_assign_EC_KEY(pkey, eckey)) { fail("Failed to assign ECC key to EVP_PKEY structure"); } } return pkey; } static CK_ULONG get_yhsize(CK_OBJECT_HANDLE object) { CK_ULONG len; if ((p11->C_GetObjectSize(session, object, &len)) != CKR_OK) { printf("Failed to get size of object 0x%lx from yubihsm-pkcs11. FAIL\n", object); return 0; } return len; } static CK_ULONG get_yhvalue(CK_OBJECT_HANDLE object, unsigned char *value, CK_ULONG object_size) { if (object_size > 0) { CK_ATTRIBUTE template[] = {{CKA_VALUE, value, object_size}}; if ((p11->C_GetAttributeValue(session, object, template, 1)) == CKR_OK) { return object_size; } else { printf("Failed to retrieve object value from yubihsm-pkcs11. 0x%lx\n", object); } } return 0; } static bool yh_derive(unsigned char *peerkey_bytes, int peerkey_len, CK_OBJECT_HANDLE privkey, char *label, CK_OBJECT_HANDLE_PTR ecdh_key) { CK_ECDH1_DERIVE_PARAMS params; params.kdf = CKD_NULL; params.pSharedData = NULL; params.ulSharedDataLen = 0; params.pPublicData = peerkey_bytes; params.ulPublicDataLen = peerkey_len; CK_MECHANISM mechanism = {CKM_ECDH1_DERIVE, (void *) ¶ms, sizeof(params)}; CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; CK_ATTRIBUTE derivedKeyTemplate[] = {{CKA_CLASS, &key_class, sizeof(key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_LABEL, label, strlen(label)}}; if ((p11->C_DeriveKey(session, &mechanism, privkey, derivedKeyTemplate, 3, ecdh_key)) != CKR_OK) { return false; } return true; } static bool yh_derive_ecdh(CK_OBJECT_HANDLE priv_key, EVP_PKEY *peer_keypair, CK_OBJECT_HANDLE_PTR ecdh_key, char *label, bool print_fail) { EC_KEY *peerkey = EVP_PKEY_get1_EC_KEY(peer_keypair); unsigned char *peerkey_bytes = NULL; int peerkey_len = i2o_ECPublicKey(peerkey, &peerkey_bytes); if (peerkey_len < 0) { fail("Failed to extract public key from EC keypair generated with openssl"); return false; } EC_KEY_free(peerkey); if (!yh_derive(peerkey_bytes, peerkey_len, priv_key, label, ecdh_key)) { if (print_fail) { fail("Failed to derive ECDH key on yubihsm-pkcs11"); } OPENSSL_free(peerkey_bytes); return false; } OPENSSL_free(peerkey_bytes); return true; } static size_t openssl_derive(EVP_PKEY *private_key, EVP_PKEY *peer_key, unsigned char **ecdh_key) { /* Create the context for the shared secret derivation */ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(private_key, NULL); if (!ctx) { fail("Failed to create new openssl context"); return 0; } size_t len = 0; /* Initialize derivation function*/ if (EVP_PKEY_derive_init(ctx) != 1) { fail("Failed to initialize openssl contex"); goto c_free; } /* Set the peer public key */ if (EVP_PKEY_derive_set_peer(ctx, peer_key) != 1) { fail("Failed to set the peer public key in the openssl context"); goto c_free; } /* Determine buffer length for shared secret */ if (EVP_PKEY_derive(ctx, NULL, &len) != 1) { fail("Failed to determine derived key expected size with openssl"); goto c_free; } /* Create the buffer */ *ecdh_key = OPENSSL_malloc(len); if (*ecdh_key == NULL) { fail("Failed to allocate the buffer to hold the ECDH key derived with " "openssl"); len = 0; goto c_free; } /* Derive the shared secret */ if ((EVP_PKEY_derive(ctx, *ecdh_key, &len)) != 1) { fail("Failed to derive ECDH key with openssl"); len = 0; goto c_free; } c_free: EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(peer_key); EVP_PKEY_free(private_key); return len; } static unsigned char *openssl_derive_ecdh(EVP_PKEY *private_key, CK_OBJECT_HANDLE peer_key, size_t *ecdh_len) { CK_LONG peerkey_len = get_yhsize(peer_key); if (peerkey_len == 0) { return 0; } unsigned char peerkey_bytes[peerkey_len]; // public key in DER if (get_yhvalue(peer_key, peerkey_bytes, peerkey_len) == 0) { fail("Failed to retrieve public key from yubihsm-pkcs11"); return 0; } const unsigned char *p = peerkey_bytes; EVP_PKEY *pkey = d2i_PUBKEY(NULL, &p, peerkey_len); unsigned char *derivekey_openssl = NULL; *ecdh_len = openssl_derive(private_key, pkey, &derivekey_openssl); if (*ecdh_len == 0) { fail("Failed to derive key with openssl"); } return derivekey_openssl; } static bool test_ecdh_value(const char *curve, CK_OBJECT_HANDLE yh_privkey, CK_OBJECT_HANDLE yh_pubkey, CK_OBJECT_HANDLE_PTR ecdh1) { // Generate keypair with openssl EVP_PKEY *openssl_keypair = generate_keypair_openssl(curve); if (openssl_keypair == NULL) { return false; } // Derive with yubihsm yh_derive_ecdh(yh_privkey, openssl_keypair, ecdh1, "ecdh1", true); // Derive with openssl size_t ecdh_openssl_len = 0; unsigned char *ecdh_openssl = openssl_derive_ecdh(openssl_keypair, yh_pubkey, &ecdh_openssl_len); if (ecdh_openssl_len == 0) { fail("Failed to derive key with openssl"); return false; } // Compare sizes CK_ULONG ecdh1_len = get_yhsize(*ecdh1); if (ecdh1_len != ecdh_openssl_len) { fail( "ECDH keys derived with yubihsm-pkcs11 and with openssl do not have the " "same size"); return false; } // Compare values unsigned char ecdh1_bytes[BUFSIZE]; // public key in DER if (get_yhvalue(*ecdh1, ecdh1_bytes, ecdh1_len) == 0) { fail("Failed to retrieve derived key from yubihsm-pkcs11"); return false; } bool equal = true; for (unsigned int i = 0; i < ecdh_openssl_len; i++) { if (ecdh1_bytes[i] != ecdh_openssl[i]) { equal = false; break; } } OPENSSL_free(ecdh_openssl); if (!equal) { fail( "ECDH keys derived with yubihsm-pkcs11 and with openssl do not have the " "same value"); return false; } return true; } static bool test_duplicate_ecdh(const char *curve, CK_OBJECT_HANDLE yh_privkey, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3) { EVP_PKEY *openssl_keypair = generate_keypair_openssl(curve); if (openssl_keypair == NULL) { return false; } if (!yh_derive_ecdh(yh_privkey, openssl_keypair, ecdh2, "ecdh2", true)) { EVP_PKEY_free(openssl_keypair); return false; } if (!yh_derive_ecdh(yh_privkey, openssl_keypair, ecdh3, "ecdh3", true)) { EVP_PKEY_free(openssl_keypair); return false; } EVP_PKEY_free(openssl_keypair); size_t ecdh1_len = get_yhsize(*ecdh2); size_t ecdh2_len = get_yhsize(*ecdh3); if (ecdh1_len == 0 || ecdh2_len == 0) { return false; } if (ecdh1_len != ecdh2_len) { fail( "2 ECDH keys derived from the same base keys do not have the same size"); return false; } unsigned char ecdh1_value[BUFSIZE], ecdh2_value[BUFSIZE]; if (get_yhvalue(*ecdh2, ecdh1_value, ecdh1_len) == 0) { return false; } if (get_yhvalue(*ecdh3, ecdh2_value, ecdh2_len) == 0) { return false; } bool equal = true; for (unsigned int i = 0; i < ecdh1_len; i++) { if (ecdh1_value[i] != ecdh2_value[i]) { equal = false; break; } } if (!equal) { fail( "ECDH keys derived from the same base keys do not have the same value"); return false; } return true; } static bool test_faulty_ecdh(const char *curve1, const char *curve2, CK_OBJECT_HANDLE_PTR yh_privkey, CK_OBJECT_HANDLE_PTR ecdh_key) { // Derive from keys of different curves EVP_PKEY *openssl_keypair = generate_keypair_openssl(curve2); if (openssl_keypair == NULL) { return false; } CK_OBJECT_HANDLE faulty_ecdh; if (yh_derive_ecdh(*yh_privkey, openssl_keypair, &faulty_ecdh, "", false)) { fail("Was able to derive ECDH key from EC keys of different curves"); EVP_PKEY_free(openssl_keypair); return false; } EVP_PKEY_free(openssl_keypair); // Derive key from another derived key EVP_PKEY *key_openssl2 = generate_keypair_openssl(curve1); if (yh_derive_ecdh(*ecdh_key, key_openssl2, &faulty_ecdh, "", false)) { fail("Was able to derive ECDH key using another ECDH key"); EVP_PKEY_free(key_openssl2); return false; } EVP_PKEY_free(key_openssl2); // Derive key using the wrong mechanism CK_MECHANISM mechanism = {CKM_EC_KEY_PAIR_GEN, NULL, 0}; CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; CK_ATTRIBUTE template[] = { {CKA_CLASS, &key_class, sizeof(key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, }; CK_RV rv = p11->C_DeriveKey(session, &mechanism, *yh_privkey, template, 2, &faulty_ecdh); if (rv != CKR_MECHANISM_INVALID) { fail("Expected CKR_MECHANISM_INVALID when invalid mechanism is " "specified"); return false; } return true; } /* This checks the same attributes that validate_ecdh_attributes() does but * makes sure the input buffer are too small for all of them and then * checks that we return the correct values in this case. */ static bool check_attributes_buffer_too_small(CK_OBJECT_HANDLE key_id) { CK_OBJECT_CLASS key_class; CK_KEY_TYPE key_type; CK_BBOOL is_local; CK_BBOOL is_token; CK_BBOOL is_destroyable; CK_BBOOL is_extractable; CK_BBOOL is_never_extractable; CK_BBOOL is_sensitive; CK_BBOOL is_always_sensitive; CK_BBOOL is_modifiable; CK_BBOOL is_copyable; CK_BBOOL is_sign; CK_BBOOL is_sign_recover; CK_BBOOL is_always_authenticated; CK_BBOOL is_unwrap; CK_BBOOL is_wrap; CK_BBOOL is_wrap_with_trusted; CK_BBOOL is_verify; CK_BBOOL is_encrypt; CK_BBOOL is_derive; CK_BYTE publicValue[1]; char label[1] = {0}; size_t label_len = sizeof(label) - 1; CK_BYTE id[2] = {0}; CK_ATTRIBUTE template[] = {{CKA_CLASS, &key_class, sizeof(key_class) - 1}, {CKA_ID, &id, sizeof(id) - 1}, {CKA_KEY_TYPE, &key_type, sizeof(key_type) - 1}, {CKA_LOCAL, &is_local, sizeof(is_local) - 1}, {CKA_TOKEN, &is_token, sizeof(is_token) - 1}, {CKA_DESTROYABLE, &is_destroyable, sizeof(is_destroyable) - 1}, {CKA_EXTRACTABLE, &is_extractable, sizeof(is_extractable) - 1}, {CKA_NEVER_EXTRACTABLE, &is_never_extractable, sizeof(is_never_extractable) - 1}, {CKA_SENSITIVE, &is_sensitive, sizeof(is_sensitive) - 1}, {CKA_ALWAYS_SENSITIVE, &is_always_sensitive, sizeof(is_always_sensitive) - 1}, {CKA_MODIFIABLE, &is_modifiable, sizeof(is_modifiable) - 1}, {CKA_COPYABLE, &is_copyable, sizeof(is_copyable) - 1}, {CKA_SIGN, &is_sign, sizeof(is_sign) - 1}, {CKA_SIGN_RECOVER, &is_sign_recover, sizeof(is_sign_recover) - 1}, {CKA_ALWAYS_AUTHENTICATE, &is_always_authenticated, sizeof(is_always_authenticated) - 1}, {CKA_UNWRAP, &is_unwrap, sizeof(is_unwrap) - 1}, {CKA_WRAP, &is_wrap, sizeof(is_wrap) - 1}, {CKA_WRAP_WITH_TRUSTED, &is_wrap_with_trusted, sizeof(is_wrap_with_trusted) - 1}, {CKA_VERIFY, &is_verify, sizeof(is_verify) - 1}, {CKA_ENCRYPT, &is_encrypt, sizeof(is_encrypt) - 1}, {CKA_DERIVE, &is_derive, sizeof(is_derive) - 1}, {CKA_VALUE, &publicValue, sizeof(publicValue) - 1}, {CKA_LABEL, label, label_len}}; CK_ULONG attribute_count = 23; CK_RV rv = p11->C_GetAttributeValue(session, key_id, template, attribute_count); if (rv != CKR_BUFFER_TOO_SMALL) { fail("Should have returned buffer too small!"); return false; } for (CK_ULONG i = 0; i < attribute_count; ++i) { if (template[i].ulValueLen != CK_UNAVAILABLE_INFORMATION) { fail("ulValueLen should be CK_UNAVAILABLE_INFORMATION."); return false; } } return true; } static bool validate_ecdh_attributes(CK_OBJECT_HANDLE key_id, char *expected_label) { CK_OBJECT_CLASS key_class; CK_KEY_TYPE key_type; CK_BBOOL is_local; CK_BBOOL is_token; CK_BBOOL is_destroyable; CK_BBOOL is_extractable; CK_BBOOL is_never_extractable; CK_BBOOL is_sensitive; CK_BBOOL is_always_sensitive; CK_BBOOL is_modifiable; CK_BBOOL is_copyable; CK_BBOOL is_sign; CK_BBOOL is_sign_recover; CK_BBOOL is_always_authenticated; CK_BBOOL is_unwrap; CK_BBOOL is_wrap; CK_BBOOL is_wrap_with_trusted; CK_BBOOL is_verify; CK_BBOOL is_encrypt; CK_BBOOL is_derive; CK_BYTE publicValue[128]; char label[41] = {0}; size_t label_len = sizeof(label) - 1; CK_ATTRIBUTE template[] = {{CKA_CLASS, &key_class, sizeof(key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_LOCAL, &is_local, sizeof(is_local)}, {CKA_TOKEN, &is_token, sizeof(is_token)}, {CKA_DESTROYABLE, &is_destroyable, sizeof(is_destroyable)}, {CKA_EXTRACTABLE, &is_extractable, sizeof(is_extractable)}, {CKA_NEVER_EXTRACTABLE, &is_never_extractable, sizeof(is_never_extractable)}, {CKA_SENSITIVE, &is_sensitive, sizeof(is_sensitive)}, {CKA_ALWAYS_SENSITIVE, &is_always_sensitive, sizeof(is_always_sensitive)}, {CKA_MODIFIABLE, &is_modifiable, sizeof(is_modifiable)}, {CKA_COPYABLE, &is_copyable, sizeof(is_copyable)}, {CKA_SIGN, &is_sign, sizeof(is_sign)}, {CKA_SIGN_RECOVER, &is_sign_recover, sizeof(is_sign_recover)}, {CKA_ALWAYS_AUTHENTICATE, &is_always_authenticated, sizeof(is_always_authenticated)}, {CKA_UNWRAP, &is_unwrap, sizeof(is_unwrap)}, {CKA_WRAP, &is_wrap, sizeof(is_wrap)}, {CKA_WRAP_WITH_TRUSTED, &is_wrap_with_trusted, sizeof(is_wrap_with_trusted)}, {CKA_VERIFY, &is_verify, sizeof(is_verify)}, {CKA_ENCRYPT, &is_encrypt, sizeof(is_encrypt)}, {CKA_DERIVE, &is_derive, sizeof(is_derive)}, {CKA_VALUE, &publicValue, sizeof(publicValue)}, {CKA_LABEL, label, label_len}}; CK_ULONG attribute_count = 22; CK_RV rv = p11->C_GetAttributeValue(session, key_id, template, attribute_count); if (rv != CKR_OK) { fail("Failed to retrieve ECDH key attributes from yubihsm-pkcs11"); return false; } if (key_class != CKO_SECRET_KEY) { fail("Derived ECDH key class is not CKO_SECRET_KEY"); return false; } if (key_type != CKK_GENERIC_SECRET) { fail("Derived ECDH key type is not CKK_GENERIC_SECRET"); return false; } if (is_local != CK_FALSE) { fail("Derived ECDH key LOCAL attribute is not CK_FALSE"); return false; } if (is_token != CK_FALSE) { fail("Derived ECDH key TOKEN attribute is not CK_FALSE"); return false; } if (is_destroyable != CK_TRUE) { fail("Derived ECDH key DESTROYABLE attribute is not CK_TRUE"); return false; } if (is_extractable != CK_TRUE) { fail("Derived ECDH key EXTRACTABLE attribute is not CK_TRUE"); return false; } if (is_never_extractable != CK_FALSE) { fail("Derived ECDH key NEVER_EXTRACTABLE attribute is not CK_FALSE"); return false; } if (is_sensitive != CK_FALSE) { fail("Derived ECDH key SENSITIVE attribute is not CK_FALSE"); return false; } if (is_always_sensitive != CK_FALSE) { fail("Derived ECDH key ALWAYS_SENSITIVE attribute is not CK_FALSE"); return false; } if (is_modifiable != CK_FALSE) { fail("Derived ECDH key MODIFIABLE attribute is not CK_FALSE"); return false; } if (is_copyable != CK_FALSE) { fail("Derived ECDH key COPYABLE attribute is not CK_FALSE"); return false; } if (is_sign != CK_FALSE) { fail("Derived ECDH key SIGN attribute is not CK_FALSE"); return false; } if (is_sign_recover != CK_FALSE) { fail("Derived ECDH key SIGN_RECOVER attribute is not CK_FALSE"); return false; } if (is_always_authenticated != CK_FALSE) { fail("Derived ECDH key ALWAYS_AUTHENTICATED attribute is not CK_FALSE"); return false; } if (is_unwrap != CK_FALSE) { fail("Derived ECDH key UNWRAP attribute is not CK_FALSE"); return false; } if (is_wrap != CK_FALSE) { fail("Derived ECDH key WRAP attribute is not CK_FALSE"); return false; } if (is_wrap_with_trusted != CK_FALSE) { fail("Derived ECDH key WRAP_WITH_TRUSTED attribute is not CK_FALSE"); return false; } if (is_verify != CK_FALSE) { fail("Derived ECDH key VERIFY attribute is not CK_FALSE"); return false; } if (is_encrypt != CK_FALSE) { fail("Derived ECDH key ENCRYPT attribute is not CK_FALSE"); return false; } if (is_derive != CK_FALSE) { fail("Derived ECDH key DERIVE attribute is not CK_FALSE"); return false; } if (strcmp(label, expected_label) != 0) { fail("Derived ECDH key does not have the expected label"); return false; } return true; } static bool find(CK_ATTRIBUTE template[], CK_ULONG attribute_count, CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3, int expected_ecdh_count) { bool ret = true; if ((p11->C_FindObjectsInit(session, template, attribute_count)) != CKR_OK) { fail("Failed to initialize search function"); return false; } else { int max_items_count = 256 + 255; CK_OBJECT_HANDLE found_objects[max_items_count]; CK_ULONG total_objects_found; if ((p11->C_FindObjects(session, found_objects, max_items_count, &total_objects_found)) == CKR_OK) { if ((expected_ecdh_count > 0) && (total_objects_found == 0)) { fail("Not enough objects were found"); ret = false; } else { int found = 0; for (size_t i = 0; i < total_objects_found; i++) { if (found_objects[i] == *ecdh1 || found_objects[i] == *ecdh2 || found_objects[i] == *ecdh3) { found++; } } if (found != expected_ecdh_count) { fail("Target object were not found or were found when they should " "not have"); ret = false; } } } else { fail("Search operation failed"); ret = false; } if ((p11->C_FindObjectsFinal(session)) != CKR_OK) { fail("Failed to finalize search function"); ret = false; } } return ret; } static bool find_secret_keys(CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3) { CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; CK_ATTRIBUTE template[] = { {CKA_CLASS, &secret_key_class, sizeof(secret_key_class)}}; return find(template, 1, ecdh1, ecdh2, ecdh3, 3); } static bool find_public_keys(CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3) { CK_OBJECT_CLASS public_key_class = CKO_PUBLIC_KEY; CK_ATTRIBUTE template[] = { {CKA_CLASS, &public_key_class, sizeof(public_key_class)}}; return find(template, 1, ecdh1, ecdh2, ecdh3, 0); } static bool find_secret_extractable_keys(CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3, int expected_count) { CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; CK_BBOOL ck_true = CK_TRUE; CK_ATTRIBUTE template[] = {{CKA_CLASS, &secret_key_class, sizeof(secret_key_class)}, {CKA_EXTRACTABLE, &ck_true, sizeof(ck_true)}}; return find(template, 2, ecdh1, ecdh2, ecdh3, expected_count); } static bool find_secret_unextractable_keys(CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3) { CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; CK_BBOOL ck_false = CK_FALSE; CK_ATTRIBUTE template[] = {{CKA_CLASS, &secret_key_class, sizeof(secret_key_class)}, {CKA_EXTRACTABLE, &ck_false, sizeof(ck_false)}}; return find(template, 2, ecdh1, ecdh2, ecdh3, 0); } static bool find_secret_extractable_keys_wrong_label(CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3) { CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; CK_BBOOL ck_true = CK_TRUE; char *label = "ecdhtest"; CK_ATTRIBUTE template[] = {{CKA_CLASS, &secret_key_class, sizeof(secret_key_class)}, {CKA_EXTRACTABLE, &ck_true, sizeof(ck_true)}, {CKA_LABEL, label, strlen(label)}}; return find(template, 3, ecdh1, ecdh2, ecdh3, 0); } static bool find_secret_key_with_id(CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3, CK_OBJECT_HANDLE_PTR key) { CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; CK_ATTRIBUTE template[] = {{CKA_CLASS, &secret_key_class, sizeof(secret_key_class)}, {CKA_ID, key, sizeof(*key)}}; return find(template, 2, ecdh1, ecdh2, ecdh3, 0); } static bool find_secret_key_right_label(CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3) { CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY; char *label = "ecdh2"; CK_ATTRIBUTE template[] = {{CKA_CLASS, &secret_key_class, sizeof(secret_key_class)}, {CKA_LABEL, label, strlen(label)}}; return find(template, 2, ecdh1, ecdh2, ecdh3, 1); } static bool find_public_key_right_label(CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3) { CK_OBJECT_CLASS public_key_class = CKO_PUBLIC_KEY; CK_ATTRIBUTE template[] = {{CKA_CLASS, &public_key_class, sizeof(public_key_class)}, {CKA_LABEL, "ecdh2", strlen("ecdh2")}}; return find(template, 2, ecdh1, ecdh2, ecdh3, 0); } static bool find_empty_template(CK_OBJECT_HANDLE_PTR ecdh1, CK_OBJECT_HANDLE_PTR ecdh2, CK_OBJECT_HANDLE_PTR ecdh3) { CK_ATTRIBUTE *template = NULL; return find(template, 0, ecdh1, ecdh2, ecdh3, 3); } static bool test_decrypt(CK_OBJECT_HANDLE_PTR ecdh) { CK_MECHANISM rsa_mechanism = {CKM_RSA_PKCS, NULL, 0}; if ((p11->C_DecryptInit(session, &rsa_mechanism, *ecdh)) != CKR_KEY_TYPE_INCONSISTENT) { fail("Initializing decryption did not return the error code " "CKR_KEY_TYPE_INCONSISTENT"); return false; } return true; } static bool test_sign(CK_OBJECT_HANDLE_PTR ecdh) { CK_MECHANISM rsa_mechanism = {CKM_RSA_PKCS, NULL, 0}; if ((p11->C_SignInit(session, &rsa_mechanism, *ecdh)) != CKR_FUNCTION_NOT_SUPPORTED) { fail("Initializing signing did not return the error code " "CKR_FUNCTION_NOT_SUPPORTED"); return false; } return true; } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: /path/to/yubihsm_pkcs11/module\n"); exit(EXIT_FAILURE); } void *handle = open_module(argv[1]); p11 = get_function_list(handle); session = open_session(p11); print_session_state(p11, session); int exit_status = EXIT_SUCCESS; CK_OBJECT_HANDLE yh_pubkey, yh_privkey; for (int i = 0; i < CURVE_COUNT; i++) { printf("\n/////// Testing curve %s\n", CURVES[i]); generate_keypair_yh(CURVE_PARAMS[i], CURVE_LENS[i], &yh_pubkey, &yh_privkey); CK_OBJECT_HANDLE ecdh1, ecdh2, ecdh3; printf("Testing the value of ECDH key derived by yubihsm-pkcs11... "); if (test_ecdh_value(CURVES[i], yh_privkey, yh_pubkey, &ecdh1)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf( "Testing that 2 ECDH keys derived from the same base keys are equal... "); if (test_duplicate_ecdh(CURVES[i], yh_privkey, &ecdh2, &ecdh3)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Testing deriving ECDH keys with faulty parameters... "); if (test_faulty_ecdh(CURVES[i], i == 0 ? CURVES[i + 1] : CURVES[i - 1], &yh_privkey, &ecdh1)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Validating ECDH attributes... "); if (validate_ecdh_attributes(ecdh1, "ecdh1")) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Validating ECDH attributes... but with too small buffers..."); if (check_attributes_buffer_too_small(ecdh1)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } // ------- Start C_FindObjects functions test printf("Finding ECDH keys: secret keys... "); if (find_secret_keys(&ecdh1, &ecdh2, &ecdh3)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Finding ECDH keys: public keys... "); if (find_public_keys(&ecdh1, &ecdh2, &ecdh3)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Finding ECDH keys: secret, extractable keys... "); if (find_secret_extractable_keys(&ecdh1, &ecdh2, &ecdh3, 3)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Finding ECDH keys: secret, un-extractable keys... "); if (find_secret_unextractable_keys(&ecdh1, &ecdh2, &ecdh3)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Finding ECDH keys: secret, extractable keys with wrong label... "); if (find_secret_extractable_keys_wrong_label(&ecdh1, &ecdh2, &ecdh3)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Finding ECDH keys: secret key with specific ID... "); if (find_secret_key_with_id(&ecdh1, &ecdh2, &ecdh3, &yh_privkey)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Finding ECDH keys: secret key with right label... "); if (find_secret_key_right_label(&ecdh1, &ecdh2, &ecdh3)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Finding ECDH keys: public key with right label... "); if (find_public_key_right_label(&ecdh1, &ecdh2, &ecdh3)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Finding ECDH keys: use empty template... "); if (find_empty_template(&ecdh1, &ecdh2, &ecdh3)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } // ------- End C_FindObjects functions test printf("Destroying ECDH key 1... "); destroy_object(p11, session, ecdh1); if (find_secret_extractable_keys(&ecdh1, &ecdh2, &ecdh3, 2)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Destroying ECDH key 2... "); destroy_object(p11, session, ecdh3); if (find_secret_extractable_keys(&ecdh1, &ecdh2, &ecdh3, 1)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Testing decryption... "); if (test_decrypt(&ecdh2)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Testing signing... "); if (test_sign(&ecdh2)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } printf("Destroying ECDH key 3... "); destroy_object(p11, session, ecdh2); if (find_secret_extractable_keys(&ecdh1, &ecdh2, &ecdh3, 0)) { printf("OK!\n"); } else { printf("FAIL!\n"); exit_status = EXIT_FAILURE; goto c_clean; } destroy_object(p11, session, yh_privkey); } c_clean: if (exit_status == EXIT_FAILURE) { destroy_object(p11, session, yh_privkey); } close_session(p11, session); close_module(handle); return (exit_status); } yubihsm-shell-2.7.3/pkcs11/tests/rsa_enc_test.c0000644000175000017500000002032615167357110020360 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include #include "../pkcs11y.h" #include "common.h" #define BUFSIZE 1024 static CK_FUNCTION_LIST_3_0_PTR p11; static CK_SESSION_HANDLE session; static void import_rsa_key(int keylen, RSA *rsak, CK_OBJECT_HANDLE_PTR keyid) { CK_BYTE e[] = {0x01, 0x00, 0x01}; CK_BYTE *p, *q, *dp, *dq, *qinv; int len = keylen / 16; p = malloc(len); q = malloc(len); dp = malloc(len); dq = malloc(len); qinv = malloc(len); CK_ULONG class_k = CKO_PRIVATE_KEY; CK_ULONG kt = CKK_RSA; CK_BYTE id[] = {0, 0}; // unsigned char *px; CK_BBOOL dec_capability = CK_TRUE; CK_ATTRIBUTE privateKeyTemplate[] = {{CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_ID, &id, sizeof(id)}, {CKA_DECRYPT, &dec_capability, sizeof(dec_capability)}, {CKA_PUBLIC_EXPONENT, e, sizeof(e)}, {CKA_PRIME_1, p, len}, {CKA_PRIME_2, q, len}, {CKA_EXPONENT_1, dp, len}, {CKA_EXPONENT_2, dq, len}, {CKA_COEFFICIENT, qinv, len}}; BIGNUM *e_bn = BN_bin2bn(e, 3, NULL); if (e_bn == NULL) exit(EXIT_FAILURE); assert(RSA_generate_key_ex(rsak, keylen, e_bn, NULL) == 1); const BIGNUM *bp, *bq, *biqmp, *bdmp1, *bdmq1; RSA_get0_factors(rsak, &bp, &bq); RSA_get0_crt_params(rsak, &bdmp1, &bdmq1, &biqmp); BN_bn2binpad(bp, p, len); BN_bn2binpad(bq, q, len); BN_bn2binpad(bdmp1, dp, len); BN_bn2binpad(bdmq1, dq, len); BN_bn2binpad(biqmp, qinv, len); assert(p11->C_CreateObject(session, privateKeyTemplate, 10, keyid) == CKR_OK); BN_free(e_bn); free(p); free(q); free(dp); free(dq); free(qinv); } static void test_rsa_encrypt(CK_OBJECT_HANDLE privkey, CK_OBJECT_HANDLE pubkey, RSA *rsak, CK_MECHANISM_TYPE mech_type, int padding, CK_ULONG expected_enc_len) { CK_BYTE data[32] = {0}; CK_ULONG data_len = sizeof(data); CK_BYTE enc[1024] = {0}; CK_ULONG enc_len; CK_BYTE dec[512] = {0}; CK_BYTE dec_internal[512] = {0}; CK_ULONG dec_internal_len; CK_RSA_PKCS_OAEP_PARAMS params = {CKM_SHA_1, CKG_MGF1_SHA1, 0, 0, 0}; CK_MECHANISM mech = {mech_type, ¶ms, sizeof(params)}; if (mech_type == CKM_RSA_PKCS) { mech.pParameter = NULL; mech.ulParameterLen = 0; } if (RAND_bytes(data, data_len) <= 0) exit(EXIT_FAILURE); // Encrypt assert(p11->C_EncryptInit(session, &mech, pubkey) == CKR_OK); enc_len = 0; assert(p11->C_Encrypt(session, data, data_len, NULL, &enc_len) == CKR_OK); assert(enc_len == expected_enc_len); assert(p11->C_Encrypt(session, data, data_len, enc, &enc_len) == CKR_OK); assert(enc_len == expected_enc_len); CK_ULONG err; CK_ULONG dec_len = (CK_ULONG) RSA_private_decrypt((int) enc_len, (unsigned char *) enc, (unsigned char *) dec, rsak, padding); if ((err = ERR_get_error())) { ERR_load_crypto_strings(); fprintf(stderr, "RSA_private_decrypt:[%lu](%s)\n", err, ERR_error_string(err, NULL)); } assert(dec_len == data_len); assert(memcmp(dec, data, data_len) == 0); assert(p11->C_DecryptInit(session, &mech, privkey) == CKR_OK); dec_internal_len = 0; assert(p11->C_Decrypt(session, enc, enc_len, NULL, &dec_internal_len) == CKR_OK); assert(p11->C_Decrypt(session, enc, enc_len, dec_internal, &dec_internal_len) == CKR_OK); assert(dec_internal_len == data_len); assert(memcmp(dec_internal, data, data_len) == 0); // Encrypt Update assert(p11->C_EncryptInit(session, &mech, pubkey) == CKR_OK); enc_len = 0; assert(p11->C_EncryptUpdate(session, data, 10, NULL, &enc_len) == CKR_OK); assert(p11->C_EncryptUpdate(session, data, 10, enc, &enc_len) == CKR_OK); enc_len = 0; assert(p11->C_EncryptUpdate(session, data + 10, 22, NULL, &enc_len) == CKR_OK); assert(p11->C_EncryptUpdate(session, data + 10, 22, enc, &enc_len) == CKR_OK); enc_len = 0; assert(p11->C_EncryptFinal(session, NULL, &enc_len) == CKR_OK); assert(enc_len == expected_enc_len); assert(p11->C_EncryptFinal(session, enc, &enc_len) == CKR_OK); assert(enc_len == expected_enc_len); dec_len = (CK_ULONG) RSA_private_decrypt(enc_len, enc, dec, rsak, padding); if ((err = ERR_get_error())) { ERR_load_crypto_strings(); fprintf(stderr, "RSA_private_decrypt:[%lu](%s)\n", err, ERR_error_string(err, NULL)); } assert(dec_len == data_len); assert(memcmp(dec, data, data_len) == 0); // Decrypt Update assert(p11->C_DecryptInit(session, &mech, privkey) == CKR_OK); dec_internal_len = sizeof(dec_internal); assert(p11->C_DecryptUpdate(session, enc, 10, dec_internal, &dec_internal_len) == CKR_OK); assert(dec_internal_len == 0); dec_internal_len = sizeof(dec_internal); assert(p11->C_DecryptUpdate(session, enc + 10, enc_len - 10, dec_internal, &dec_internal_len) == CKR_OK); assert(dec_internal_len == 0); dec_internal_len = sizeof(dec_internal); assert(p11->C_DecryptFinal(session, dec_internal, &dec_internal_len) == CKR_OK); assert(dec_internal_len == data_len); assert(memcmp(dec_internal, data, data_len) == 0); } static void test_encrypt_RSA(int keysize, CK_ULONG expected_enc_len) { RSA *rsak = RSA_new(); CK_OBJECT_HANDLE keyid; import_rsa_key(keysize, rsak, &keyid); if (keyid == 0) exit(EXIT_FAILURE); CK_BYTE id[] = {0, 0}; CK_MECHANISM_TYPE mechs[32]; CK_ATTRIBUTE attrs[] = { {CKA_ALLOWED_MECHANISMS, mechs, sizeof(mechs)}, {CKA_ID, &id, sizeof(id)} }; assert(p11->C_GetAttributeValue(session, keyid, attrs, 2) == CKR_OK); assert(attrs[0].ulValueLen == 2 * sizeof(CK_MECHANISM_TYPE)); assert(mechs[0] == CKM_RSA_PKCS); assert(mechs[1] == CKM_RSA_PKCS_OAEP); CK_OBJECT_CLASS key_class = CKO_PUBLIC_KEY; CK_KEY_TYPE key_type = CKK_RSA; CK_ATTRIBUTE findKeyTemplate[] = {{CKA_CLASS, &key_class, sizeof(key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_ID, &id, sizeof(id)}}; CK_OBJECT_HANDLE objs[1]; CK_ULONG n_objs = 0; assert(p11->C_FindObjectsInit(session, findKeyTemplate, 3) == CKR_OK); assert(p11->C_FindObjects(session, objs, 1, &n_objs) == CKR_OK); assert(p11->C_FindObjectsFinal(session) == CKR_OK); assert(n_objs == 1); printf("RSA %d : RSA_PKCS1_PADDING\n", keysize); test_rsa_encrypt(keyid, objs[0], rsak, CKM_RSA_PKCS, RSA_PKCS1_PADDING, expected_enc_len); printf("RSA %d : RSA_PKCS1_OAEP_PADDING\n", keysize); test_rsa_encrypt(keyid, objs[0], rsak, CKM_RSA_PKCS_OAEP, RSA_PKCS1_OAEP_PADDING, expected_enc_len); RSA_free(rsak); destroy_object(p11, session, keyid); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: /path/to/yubihsm_pkcs11/module\n"); exit(EXIT_FAILURE); } void *handle = open_module(argv[1]); p11 = get_function_list(handle); session = open_session(p11); print_session_state(p11, session); test_encrypt_RSA(2048, 256); test_encrypt_RSA(3072, 384); test_encrypt_RSA(4096, 512); close_session(p11, session); close_module(handle); return (EXIT_SUCCESS); } yubihsm-shell-2.7.3/pkcs11/tests/pss_sign_test.c0000644000175000017500000001472715167357110020603 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include "../pkcs11y.h" #include "common.h" #define BUFSIZE 1024 static CK_FUNCTION_LIST_3_0_PTR p11; static CK_SESSION_HANDLE session; static void import_rsa_key(int keylen, RSA *rsak, CK_OBJECT_HANDLE_PTR keyid) { CK_BYTE e[] = {0x01, 0x00, 0x01}; CK_BYTE *p, *q, *dp, *dq, *qinv; int len = keylen / 16; p = malloc(len); q = malloc(len); dp = malloc(len); dq = malloc(len); qinv = malloc(len); CK_ULONG class_k = CKO_PRIVATE_KEY; CK_ULONG kt = CKK_RSA; CK_BYTE id[] = {0, 0}; CK_BBOOL sign_capability = CK_TRUE; CK_ATTRIBUTE privateKeyTemplate[] = {{CKA_CLASS, &class_k, sizeof(class_k)}, {CKA_KEY_TYPE, &kt, sizeof(kt)}, {CKA_ID, &id, sizeof(id)}, {CKA_SIGN, &sign_capability, sizeof(sign_capability)}, {CKA_PUBLIC_EXPONENT, e, sizeof(e)}, {CKA_PRIME_1, p, len}, {CKA_PRIME_2, q, len}, {CKA_EXPONENT_1, dp, len}, {CKA_EXPONENT_2, dq, len}, {CKA_COEFFICIENT, qinv, len}}; BIGNUM *e_bn = BN_bin2bn(e, 3, NULL); if (e_bn == NULL) exit(EXIT_FAILURE); assert(RSA_generate_key_ex(rsak, keylen, e_bn, NULL) == 1); const BIGNUM *bp, *bq, *biqmp, *bdmp1, *bdmq1; RSA_get0_factors(rsak, &bp, &bq); RSA_get0_crt_params(rsak, &bdmp1, &bdmq1, &biqmp); BN_bn2binpad(bp, p, len); BN_bn2binpad(bq, q, len); BN_bn2binpad(bdmp1, dp, len); BN_bn2binpad(bdmq1, dq, len); BN_bn2binpad(biqmp, qinv, len); assert(p11->C_CreateObject(session, privateKeyTemplate, 10, keyid) == CKR_OK); BN_free(e_bn); free(p); free(q); free(dp); free(dq); free(qinv); } static CK_MECHANISM_TYPE get_hash_mechanism(CK_MECHANISM_TYPE mech) { switch (mech) { case CKM_SHA1_RSA_PKCS_PSS: return CKM_SHA_1; case CKM_SHA256_RSA_PKCS_PSS: return CKM_SHA256; case CKM_SHA384_RSA_PKCS_PSS: return CKM_SHA384; case CKM_SHA512_RSA_PKCS_PSS: return CKM_SHA512; default: return 0; } } static CK_RSA_PKCS_MGF_TYPE get_mgf_algo(CK_MECHANISM_TYPE mech) { switch (mech) { case CKM_SHA1_RSA_PKCS_PSS: return CKG_MGF1_SHA1; case CKM_SHA256_RSA_PKCS_PSS: return CKG_MGF1_SHA256; case CKM_SHA384_RSA_PKCS_PSS: return CKG_MGF1_SHA384; case CKM_SHA512_RSA_PKCS_PSS: return CKG_MGF1_SHA512; default: return 0; } } static const EVP_MD *get_md_type(CK_MECHANISM_TYPE mech) { switch (mech) { case CKM_SHA_1: case CKM_SHA1_RSA_PKCS_PSS: case CKG_MGF1_SHA1: return EVP_sha1(); case CKM_SHA256: case CKM_SHA256_RSA_PKCS_PSS: case CKG_MGF1_SHA256: return EVP_sha256(); case CKM_SHA384: case CKM_SHA384_RSA_PKCS_PSS: case CKG_MGF1_SHA384: return EVP_sha384(); case CKM_SHA512: case CKM_SHA512_RSA_PKCS_PSS: case CKG_MGF1_SHA512: return EVP_sha512(); default: return NULL; } } static void test_sign_pss(CK_OBJECT_HANDLE keyid, CK_MECHANISM_TYPE mech_type, RSA *rsak) { CK_RSA_PKCS_PSS_PARAMS pss_params = {get_hash_mechanism(mech_type), get_mgf_algo(mech_type), EVP_MD_size(get_md_type(mech_type))}; CK_MECHANISM mech = {mech_type, &pss_params, sizeof(pss_params)}; CK_BYTE *data = malloc(pss_params.sLen); if (RAND_bytes(data, pss_params.sLen) <= 0) { exit(EXIT_FAILURE); } // Sign assert(p11->C_SignInit(session, &mech, keyid) == CKR_OK); CK_ULONG sig_len = 0; assert(p11->C_Sign(session, data, pss_params.sLen, NULL, &sig_len) == CKR_OK); CK_BYTE *sig = malloc(sig_len); assert(p11->C_Sign(session, data, pss_params.sLen, sig, &sig_len) == CKR_OK); // Verify signature if (rsak != NULL) { CK_BYTE *pss_buf = malloc(sig_len); assert((CK_ULONG) RSA_public_decrypt(sig_len, sig, pss_buf, rsak, RSA_NO_PADDING) == sig_len); EVP_MD_CTX *md_ctx = EVP_MD_CTX_create(); assert(EVP_DigestInit_ex(md_ctx, get_md_type(mech_type), NULL) == 1); assert(EVP_DigestUpdate(md_ctx, data, pss_params.sLen) == 1); CK_BYTE digest_data[256] = {0}; unsigned int digest_data_len = sizeof(digest_data); assert(EVP_DigestFinal_ex(md_ctx, digest_data, &digest_data_len) == 1); EVP_MD_CTX_destroy(md_ctx); assert(RSA_verify_PKCS1_PSS_mgf1(rsak, digest_data, get_md_type(pss_params.hashAlg), get_md_type(pss_params.mgf), pss_buf, pss_params.sLen) == 1); free(pss_buf); } free(sig); free(data); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: /path/to/yubihsm_pkcs11/module\n"); exit(EXIT_FAILURE); } void *handle = open_module(argv[1]); p11 = get_function_list(handle); session = open_session(p11); print_session_state(p11, session); int keysizes[3] = {2048, 3072, 4096}; for (int i = 0; i < 3; i++) { RSA *rsak = RSA_new(); CK_OBJECT_HANDLE keyid; import_rsa_key(keysizes[i], rsak, &keyid); if (keyid == 0) { exit(EXIT_FAILURE); } test_sign_pss(keyid, CKM_SHA1_RSA_PKCS_PSS, rsak); test_sign_pss(keyid, CKM_SHA256_RSA_PKCS_PSS, rsak); test_sign_pss(keyid, CKM_SHA384_RSA_PKCS_PSS, rsak); test_sign_pss(keyid, CKM_SHA512_RSA_PKCS_PSS, rsak); RSA_free(rsak); destroy_object(p11, session, keyid); } printf("OK!\n"); close_session(p11, session); close_module(handle); return (EXIT_SUCCESS); } yubihsm-shell-2.7.3/pkcs11/tests/engine_tests.sh0000755000175000017500000001140715167357110020571 0ustar aveenaveen#!/usr/bin/env bash # # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set -eo pipefail p11="`pwd`/../yubihsm_pkcs11.so" os=`uname -s` arch=`uname -m` if [ "x$arch" = "xarmv7l" ]; then arch="arm" abi="gnueabihf" else abi="gnu" fi if [ "x$os" = "xFreeBSD" ]; then if [ -f "/usr/local/lib/engines/pkcs11.so" ]; then engine="/usr/local/lib/engines/pkcs11.so" else echo "No engine found for $os-$arch" exit 0 fi ssl_cnf="/etc/ssl/openssl.cnf" elif [ "x$os" = "xLinux" ]; then if [ -f "/usr/lib/ssl/engines/pkcs11.so" ]; then engine="/usr/lib/ssl/engines/pkcs11.so" elif [ -f "/usr/lib/ssl/engines/libpkcs11.so" ]; then engine="/usr/lib/ssl/engines/libpkcs11.so" elif [ -f "/usr/lib/ssl/engines/engine_pkcs11.so" ]; then engine="/usr/lib/ssl/engines/engine_pkcs11.so" elif [ -f "/usr/lib/$arch-linux-$abi/engines-1.1/pkcs11.so" ]; then engine="/usr/lib/$arch-linux-$abi/engines-1.1/pkcs11.so" else echo "No engine found for $os-$arch" exit 0 fi ssl_cnf="/etc/ssl/openssl.cnf" else echo "$os-$arch is not supported" exit 0 fi if [ ! -f $engine ]; then echo "No engine found at $engine for $os-$arch" exit 1 fi if [ -z ${DEFAULT_CONNECTOR_URL} ]; then DEFAULT_CONNECTOR_URL="http://localhost:12345" fi dir=`mktemp -d /tmp/yubihsmtest.XXXXXX` trap 'rm -rf "$dir"' INT TERM EXIT cat > $dir/engine.conf <<-EOF openssl_conf = openssl_init EOF cat $ssl_cnf >> $dir/engine.conf cat >> $dir/engine.conf <<-EOF [openssl_init] engines = engine_section [engine_section] pkcs11 = pkcs11_section [pkcs11_section] engine_id = pkcs11 dynamic_path = $engine MODULE_PATH = $p11 PIN = 0001password init = 0 EOF cat > $dir/p11.conf <<-EOF connector = ${DEFAULT_CONNECTOR_URL} EOF export YUBIHSM_PKCS11_CONF=$dir/p11.conf export OPENSSL_CONF=$dir/engine.conf test_rsa_sig() { local bits=$1 local label=`openssl rand -engine pkcs11 -base64 16` pkcs11-tool --module=$p11 --keypairgen --key-type rsa:${bits} --label="$label" --login --pin 0001password pkcs11-tool --module=$p11 --read-object --label="$label" -l --pin 0001password -y pubkey --output-file=$dir/pubkey.der dd if=/dev/urandom of=$dir/data bs=1 count=32 openssl dgst -engine pkcs11 -keyform engine -sha256 -sign label_${label} -out $dir/sign $dir/data openssl dgst -keyform der -sha256 -verify $dir/pubkey.der -signature $dir/sign $dir/data pkcs11-tool --module=$p11 --delete-object --label="$label" -l --pin 0001password -y privkey } test_ecdsa_sig() { local curve=$1 local label=`openssl rand -engine pkcs11 -base64 16` pkcs11-tool --module=$p11 --keypairgen --key-type EC:${curve} --label="$label" --login --pin 0001password pkcs11-tool --module=$p11 --read-object --label="$label" -l --pin 0001password -y pubkey --output-file=$dir/pubkey.der dd if=/dev/urandom of=$dir/data bs=1 count=32 openssl dgst -engine pkcs11 -keyform engine -sha256 -sign label_${label} -out $dir/sign $dir/data openssl dgst -keyform der -sha256 -verify $dir/pubkey.der -signature $dir/sign $dir/data pkcs11-tool --module=$p11 --delete-object --label="$label" -l --pin 0001password -y privkey } test_ecdh_derive() { local curve=$1 local label=`openssl rand -engine pkcs11 -base64 16` pkcs11-tool --module=$p11 --keypairgen --key-type EC:${curve} --label="$label" --usage-derive --login --pin 0001password pkcs11-tool --module=$p11 --read-object --label="$label" -l --pin 0001password -y pubkey --output-file=$dir/pubkey.der openssl ecparam -name $curve -genkey -noout -out $dir/${curve}-priv.pem openssl ec -in $dir/${curve}-priv.pem -pubout -outform DER -out $dir/${curve}.der openssl pkeyutl -inkey $dir/${curve}-priv.pem -derive -peerkey $dir/pubkey.der -peerform der | openssl dgst -out $dir/${curve}-internal openssl pkeyutl -engine pkcs11 -keyform engine -inkey label_${label} -derive -peerkey $dir/${curve}.der -peerform der | openssl dgst -out $dir/${curve}-pkcs11 cmp $dir/${curve}-internal $dir/${curve}-pkcs11 pkcs11-tool --module=$p11 --delete-object --label="$label" -l --pin 0001password -y privkey } test_rsa_sig 2048 for curve in secp224r1 prime256v1 secp256k1 secp384r1 secp521r1; do test_ecdsa_sig $curve if ! openssl version | grep -q "OpenSSL 1.0"; then # OpenSSL gets engine support for ECDH from version 1.1 test_ecdh_derive $curve fi done yubihsm-shell-2.7.3/pkcs11/tests/CMakeLists.txt0000644000175000017500000002376215167357110020312 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # find_program (BASH_PROGRAM bash) add_test( NAME engine_tests COMMAND ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/engine_tests.sh ) set( SKIPPED_TESTS Slot.NoInit PKCS11Test.EnumerateMechanisms # YH requires login for C_GenerateRandom ReadOnlySessionTest.GenerateRandom ReadOnlySessionTest.GenerateRandomNone ReadOnlySessionTest.UserLoginWrongPIN ReadOnlySessionTest.SOLoginFail ReadOnlySessionTest.CreateKeyPairObjects ReadOnlySessionTest.CreateSecretKeyAttributes ReadOnlySessionTest.SignVerifyRecover ReadOnlySessionTest.GenerateKeyInvalid ReadOnlySessionTest.GenerateKeyPairInvalid ReadOnlySessionTest.WrapUnwrap ReadOnlySessionTest.WrapInvalid ReadOnlySessionTest.UnwrapInvalid ReadWriteSessionTest.CreateCopyDestroyObject ReadWriteSessionTest.SetLatchingAttribute ReadWriteSessionTest.FindObjectSubset ReadWriteSessionTest.ReadOnlySessionSOLoginFail ReadWriteSessionTest.SOLogin ReadWriteSessionTest.TookanAttackA1 ReadWriteSessionTest.TookanAttackA3 ReadWriteSessionTest.TookanAttackA4 ReadWriteSessionTest.TookanAttackA5a ReadWriteSessionTest.TookanAttackA5b ReadWriteSessionTest.PublicExponent4Bytes ReadWriteSessionTest.ExtractKeys ReadWriteSessionTest.AsymmetricTokenKeyPair RWUserSessionTest.SOLoginFail DataObjectTest.CopyDestroyObjectInvalid DataObjectTest.GetMultipleAttributes DataObjectTest.GetSetAttributeInvalid RWSOSessionTest.SOSessionFail RWSOSessionTest.UserLoginFail RWEitherSessionTest.TookanAttackA2 KeyPairTest.EncryptDecrypt Ciphers/SecretKeyTest.EncryptDecrypt/0 Ciphers/SecretKeyTest.EncryptDecrypt/1 Ciphers/SecretKeyTest.EncryptDecrypt/2 Ciphers/SecretKeyTest.EncryptDecrypt/3 Ciphers/SecretKeyTest.EncryptFailDecrypt/0 Ciphers/SecretKeyTest.EncryptFailDecrypt/1 Ciphers/SecretKeyTest.EncryptFailDecrypt/2 Ciphers/SecretKeyTest.EncryptFailDecrypt/3 Ciphers/SecretKeyTest.EncryptDecryptGetSpace/0 Ciphers/SecretKeyTest.EncryptDecryptGetSpace/1 Ciphers/SecretKeyTest.EncryptDecryptGetSpace/2 Ciphers/SecretKeyTest.EncryptDecryptGetSpace/3 Ciphers/SecretKeyTest.EncryptDecryptParts/0 Ciphers/SecretKeyTest.EncryptDecryptParts/1 Ciphers/SecretKeyTest.EncryptDecryptParts/2 Ciphers/SecretKeyTest.EncryptDecryptParts/3 Ciphers/SecretKeyTest.EncryptDecryptInitInvalid/0 Ciphers/SecretKeyTest.EncryptDecryptInitInvalid/1 Ciphers/SecretKeyTest.EncryptDecryptInitInvalid/2 Ciphers/SecretKeyTest.EncryptDecryptInitInvalid/3 Ciphers/SecretKeyTest.EncryptErrors/0 Ciphers/SecretKeyTest.EncryptErrors/1 Ciphers/SecretKeyTest.EncryptErrors/2 Ciphers/SecretKeyTest.EncryptErrors/3 Ciphers/SecretKeyTest.DecryptErrors/0 Ciphers/SecretKeyTest.DecryptErrors/1 Ciphers/SecretKeyTest.DecryptErrors/2 Ciphers/SecretKeyTest.DecryptErrors/3 Ciphers/SecretKeyTest.EncryptUpdateErrors/0 Ciphers/SecretKeyTest.EncryptUpdateErrors/1 Ciphers/SecretKeyTest.EncryptUpdateErrors/2 Ciphers/SecretKeyTest.EncryptUpdateErrors/3 Ciphers/SecretKeyTest.EncryptModePolicing1/0 Ciphers/SecretKeyTest.EncryptModePolicing1/1 Ciphers/SecretKeyTest.EncryptModePolicing1/2 Ciphers/SecretKeyTest.EncryptModePolicing1/3 Ciphers/SecretKeyTest.EncryptModePolicing2/0 Ciphers/SecretKeyTest.EncryptModePolicing2/1 Ciphers/SecretKeyTest.EncryptModePolicing2/2 Ciphers/SecretKeyTest.EncryptModePolicing2/3 Ciphers/SecretKeyTest.EncryptInvalidIV/0 Ciphers/SecretKeyTest.EncryptInvalidIV/1 Ciphers/SecretKeyTest.EncryptInvalidIV/2 Ciphers/SecretKeyTest.EncryptInvalidIV/3 Ciphers/SecretKeyTest.DecryptInvalidIV/0 Ciphers/SecretKeyTest.DecryptInvalidIV/1 Ciphers/SecretKeyTest.DecryptInvalidIV/2 Ciphers/SecretKeyTest.DecryptInvalidIV/3 Ciphers/SecretKeyTest.DecryptInvalidIV/3 Ciphers/SecretKeyTest.DecryptUpdateErrors/0 Ciphers/SecretKeyTest.DecryptUpdateErrors/1 Ciphers/SecretKeyTest.DecryptUpdateErrors/2 Ciphers/SecretKeyTest.DecryptUpdateErrors/3 Ciphers/SecretKeyTest.EncryptFinalImmediate/0 Ciphers/SecretKeyTest.EncryptFinalImmediate/1 Ciphers/SecretKeyTest.EncryptFinalImmediate/2 Ciphers/SecretKeyTest.EncryptFinalImmediate/3 Ciphers/SecretKeyTest.EncryptFinalErrors1/0 Ciphers/SecretKeyTest.EncryptFinalErrors1/1 Ciphers/SecretKeyTest.EncryptFinalErrors1/2 Ciphers/SecretKeyTest.EncryptFinalErrors1/3 Ciphers/SecretKeyTest.EncryptFinalErrors2/0 Ciphers/SecretKeyTest.EncryptFinalErrors2/1 Ciphers/SecretKeyTest.EncryptFinalErrors2/2 Ciphers/SecretKeyTest.EncryptFinalErrors2/3 Ciphers/SecretKeyTest.DecryptFinalErrors1/0 Ciphers/SecretKeyTest.DecryptFinalErrors1/1 Ciphers/SecretKeyTest.DecryptFinalErrors1/2 Ciphers/SecretKeyTest.DecryptFinalErrors1/3 Ciphers/SecretKeyTest.DecryptFinalErrors2/0 Ciphers/SecretKeyTest.DecryptFinalErrors2/1 Ciphers/SecretKeyTest.DecryptFinalErrors2/2 Ciphers/SecretKeyTest.DecryptFinalErrors2/3 Digests/DigestTest.DigestKey/0 Digests/DigestTest.DigestKey/1 Digests/DigestTest.DigestKey/2 Digests/DigestTest.DigestKey/3 Digests/DigestTest.DigestKey/4 Digests/DigestTest.DigestKeyInvalid/0 Digests/DigestTest.DigestKeyInvalid/1 Digests/DigestTest.DigestKeyInvalid/2 Digests/DigestTest.DigestKeyInvalid/3 Digests/DigestTest.DigestKeyInvalid/4 Signatures/SignTest.SignVerify/0 Signatures/SignTest.SignFailVerifyWrong/0 Signatures/SignTest.SignFailVerifyShort/0 Duals/DualSecretKeyTest.DigestEncrypt/0 Duals/DualSecretKeyTest.DigestEncrypt/1 Duals/DualSecretKeyTest.DigestEncrypt/2 Duals/DualSecretKeyTest.DigestEncrypt/3 Duals/DualSecretKeyTest.DigestEncrypt/4 Duals/DualSecretKeyTest.DigestEncrypt/5 Init.InitArgsBadReserved ) string(REPLACE ";" ":" SKIPPED_TESTS_STR "${SKIPPED_TESTS}") if (DEFINED ENV{PKCS11TEST_PATH}) if (NOT EXISTS $ENV{PKCS11TEST_PATH}/pkcs11test) message(FATAL_ERROR "PKCS11TEST_PATH defined, but $ENV{PKCS11TEST_PATH}/pkcs11test doesn't exist") endif () else () message(WARNING "PKCS11TEST_PATH not defined, assuming that pkcs11test is in PATH") endif () message(STATUS "Using PKCS11_TESTER: $ENV{PKCS11TEST_PATH}/pkcs11test") if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(LIBEXT "dylib") elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") set(LIBEXT "so") elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(LIBEXT "so") elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") set(LIBEXT "dll") endif () add_test( NAME pkcs11test COMMAND ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/pkcs11test.sh ) set_property( TEST pkcs11test APPEND PROPERTY ENVIRONMENT SKIPPED_TESTS=${SKIPPED_TESTS_STR}) set_property( TEST pkcs11test APPEND PROPERTY ENVIRONMENT BINDIR=${CMAKE_BINARY_DIR}) set_property( TEST pkcs11test APPEND PROPERTY ENVIRONMENT LIBEXT=${LIBEXT}) set ( SOURCE_ECDH_DERIVE ecdh_derive_test.c common.c ) set ( SOURCE_ECDH_SP800 ecdh_sp800_test.c common.c ) set ( SOURCE_AES_ENCRYPT aes_encrypt_test.c common.c ) set ( SOURCE_RSA_ENC_TEST rsa_enc_test.c common.c ) set ( SOURCE_RSA_PSS_SIGN_TEST pss_sign_test.c common.c ) set ( SOURCE_ASYM_WRAP_TEST asym_wrap_test.c common.c ) set ( SOURCE_PKCS11_INTERFACES_TEST pkcs11_interfaces_test.c common.c ) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") add_executable (aes_encrypt_test ${SOURCE_AES_ENCRYPT}) add_executable (ecdh_derive_test ${SOURCE_ECDH_DERIVE}) add_executable (ecdh_sp800_test ${SOURCE_ECDH_SP800}) target_link_libraries( aes_encrypt_test "-ldl") add_test ( NAME aes_encrypt_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/aes_encrypt_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT} ) set_tests_properties(aes_encrypt_test PROPERTIES SKIP_RETURN_CODE 64) target_link_libraries ( ecdh_derive_test ${LIBCRYPTO_LDFLAGS} "-ldl") target_link_libraries ( ecdh_sp800_test ${LIBCRYPTO_LDFLAGS} "-ldl") add_test ( NAME ecdh_derive_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/ecdh_derive_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT} ) add_test ( NAME ecdh_sp800_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/ecdh_sp800_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT} ) if (NOT ${LIBCRYPTO_VERSION} VERSION_LESS 1.1) add_executable (rsa_enc_test ${SOURCE_RSA_ENC_TEST}) target_link_libraries ( rsa_enc_test ${LIBCRYPTO_LDFLAGS} "-ldl") add_test ( NAME rsa_enc_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/rsa_enc_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT} ) add_executable (pss_sign_test ${SOURCE_RSA_PSS_SIGN_TEST}) target_link_libraries ( pss_sign_test ${LIBCRYPTO_LDFLAGS} "-ldl") add_test ( NAME pss_sign_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pss_sign_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT} ) add_executable (asym_wrap_test ${SOURCE_ASYM_WRAP_TEST}) target_link_libraries ( asym_wrap_test ${LIBCRYPTO_LDFLAGS} "-ldl") add_test ( NAME asym_wrap_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/asym_wrap_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT} ) add_executable (pkcs11_interfaces_test ${SOURCE_PKCS11_INTERFACES_TEST}) target_link_libraries ( pkcs11_interfaces_test "-ldl") add_test ( NAME pkcs11_interfaces_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pkcs11_interfaces_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT} ) endif(NOT ${LIBCRYPTO_VERSION} VERSION_LESS 1.1) endif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") yubihsm-shell-2.7.3/pkcs11/tests/common.c0000644000175000017500000000663315167357110017204 0ustar aveenaveen/* * Copyright 2021 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include "common.h" void *open_module(const char *path) { void *handle = dlopen(path, RTLD_NOW | RTLD_GLOBAL); assert(handle != NULL); return handle; } void close_module(void *handle) { assert(handle != NULL); int r = dlclose(handle); assert(r == 0); } CK_FUNCTION_LIST_3_0_PTR get_function_list(void *handle) { CK_C_GetInterface fn; *(void **) (&fn) = dlsym(handle, "C_GetInterface"); assert(fn != NULL); CK_INTERFACE_PTR interface; CK_RV rv = fn(NULL, NULL, &interface, 0); assert(rv == CKR_OK); return interface->pFunctionList; } CK_SESSION_HANDLE open_session(CK_FUNCTION_LIST_3_0_PTR p11) { CK_SESSION_HANDLE session; CK_C_INITIALIZE_ARGS initArgs; memset(&initArgs, 0, sizeof(initArgs)); const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } char config[256]; assert(strlen(connector_url) + strlen("connector=") < 256); snprintf(config, sizeof(config), "connector=%s", connector_url); initArgs.pReserved = (void *) config; CK_RV rv = p11->C_Initialize(&initArgs); assert(rv == CKR_OK); rv = p11->C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session); assert(rv == CKR_OK); char password[] = "0001password"; rv = p11->C_Login(session, CKU_USER, (CK_UTF8CHAR_PTR) password, (CK_ULONG) strlen(password)); assert(rv == CKR_OK); printf("Session open and authenticated\n"); return session; } void close_session(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session) { CK_RV rv = p11->C_Logout(session); assert(rv == CKR_OK); rv = p11->C_CloseSession(session); assert(rv == CKR_OK); rv = p11->C_Finalize(NULL); assert(rv == CKR_OK); } void print_session_state(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session) { CK_SESSION_INFO pInfo; CK_RV rv = p11->C_GetSessionInfo(session, &pInfo); assert(rv == CKR_OK); CK_STATE state = pInfo.state; printf("session state: "); switch (state) { case 0: printf("read-only public session\n"); break; case 1: printf("read-only user functions\n"); break; case 2: printf("read-write public session\n"); break; case 3: printf("read-write user functions\n"); break; case 4: printf("read-write so functions\n"); break; default: printf("unknown state\n"); break; } } bool destroy_object(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key) { if ((p11->C_DestroyObject(session, key)) != CKR_OK) { printf("WARN. Failed to destroy object 0x%lx on HSM. FAIL\n", key); return false; } return true; } yubihsm-shell-2.7.3/pkcs11/tests/ecdh_sp800_test.c0000644000175000017500000004075515167357110020613 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include "../pkcs11y.h" #include "common.h" #define BUFSIZE 1024 CK_BYTE P224_PARAMS[] = {0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x21}; CK_BYTE P256_PARAMS[] = {0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; CK_BYTE P384_PARAMS[] = {0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22}; CK_BYTE P521_PARAMS[] = {0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23}; static CK_FUNCTION_LIST_3_0_PTR p11; static CK_SESSION_HANDLE session; char *CURVES[] = {"secp224r1", "prime256v1", "secp384r1", "secp521r1"}; CK_BYTE *CURVE_PARAMS[] = {P224_PARAMS, P256_PARAMS, P384_PARAMS, P521_PARAMS}; CK_ULONG CURVE_LENS[] = {sizeof(P224_PARAMS), sizeof(P256_PARAMS), sizeof(P384_PARAMS), sizeof(P521_PARAMS)}; int CURVE_COUNT = sizeof(CURVE_PARAMS) / sizeof(CURVE_PARAMS[0]); size_t CURVE_ECDH_LEN[] = {28, 32, 48, 66}; static void success(const char *message) { printf("%s. OK\n", message); } static void fail(const char *message) { printf("%s. FAIL!\n", message); } static void increment_ctr(uint8_t *ctr, size_t len) { while (len > 0) { if (++ctr[--len]) { break; } } } static void generate_keypair_yh(CK_BYTE *curve, CK_ULONG curve_len, CK_OBJECT_HANDLE_PTR publicKeyPtr, CK_OBJECT_HANDLE_PTR privateKeyPtr) { CK_MECHANISM mechanism = {CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0}; CK_BBOOL ck_true = CK_TRUE; CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY; CK_OBJECT_CLASS privkey_class = CKO_PRIVATE_KEY; CK_KEY_TYPE key_type = CKK_EC; char *label = "ecdhtest"; CK_ATTRIBUTE publicKeyTemplate[] = {{CKA_CLASS, &pubkey_class, sizeof(pubkey_class)}, {CKA_VERIFY, &ck_true, sizeof(ck_true)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_LABEL, label, strlen(label)}, {CKA_EC_PARAMS, curve, curve_len}}; CK_ATTRIBUTE privateKeyTemplate[] = {{CKA_CLASS, &privkey_class, sizeof(privkey_class)}, {CKA_LABEL, label, strlen(label)}, {CKA_DERIVE, &ck_true, sizeof(ck_true)}}; if ((p11->C_GenerateKeyPair(session, &mechanism, publicKeyTemplate, 5, privateKeyTemplate, 3, publicKeyPtr, privateKeyPtr)) != CKR_OK) { fail("Failed to generate EC key pair on YubiHSM"); exit(EXIT_FAILURE); } success("Generated EC key pair on YubiHSM"); } static EVP_PKEY *generate_keypair_openssl(const char *curve) { EVP_PKEY *pkey = NULL; EC_KEY *eckey = NULL; int eccgrp = OBJ_txt2nid(curve); eckey = EC_KEY_new_by_curve_name(eccgrp); if (!(EC_KEY_generate_key(eckey))) { fail("Failed to generate EC keypair with openssl"); } pkey = EVP_PKEY_new(); if (!EVP_PKEY_assign_EC_KEY(pkey, eckey)) { fail("Failed to assign ECC key to EVP_PKEY structure"); } return pkey; } static CK_ULONG get_yhsize(CK_OBJECT_HANDLE object) { CK_ULONG len; if ((p11->C_GetObjectSize(session, object, &len)) != CKR_OK) { printf("Failed to get size of object 0x%lx from yubihsm-pkcs11. FAIL\n", object); return 0; } return len; } static CK_ULONG get_yhvalue(CK_OBJECT_HANDLE object, unsigned char *value, CK_ULONG object_size) { if (object_size > 0) { CK_ATTRIBUTE template[] = {{CKA_VALUE, value, object_size}}; if ((p11->C_GetAttributeValue(session, object, template, sizeof(template) / sizeof(template[0]))) == CKR_OK) { return object_size; } else { printf("Failed to retrieve object value from yubihsm-pkcs11. 0x%lx\n", object); } } return 0; } static CK_RV yh_derive(unsigned char *peerkey_bytes, int peerkey_len, CK_OBJECT_HANDLE privkey, CK_ULONG kdf, char *label, CK_OBJECT_HANDLE_PTR ecdh_key, CK_ULONG value_len, CK_ULONG ecdh_len) { CK_ECDH1_DERIVE_PARAMS params; params.kdf = kdf; params.pSharedData = NULL; params.ulSharedDataLen = 0; params.pPublicData = peerkey_bytes; params.ulPublicDataLen = peerkey_len; CK_MECHANISM mechanism = {CKM_ECDH1_DERIVE, ¶ms, sizeof(params)}; CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; CK_ATTRIBUTE derivedKeyTemplate[] = {{CKA_CLASS, &key_class, sizeof(key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_VALUE_LEN, &value_len, sizeof(value_len)}, {CKA_LABEL, label, strlen(label)}}; CK_RV rv = CKR_OK; rv = p11->C_DeriveKey(session, &mechanism, privkey, derivedKeyTemplate, sizeof(derivedKeyTemplate) / sizeof(derivedKeyTemplate[0]), ecdh_key); if (rv != CKR_OK) { return rv; } CK_ULONG actual_len = get_yhsize(*ecdh_key); if ((ecdh_len != actual_len)) { printf("Derived ECDH is not the expected length. Expected %lu. Found %lu\n", ecdh_len, actual_len); rv = CKR_FUNCTION_FAILED; } return rv; } static unsigned int do_hash(const EVP_MD *md, uint8_t *hashed, unsigned char *raw_derived, size_t raw_derived_len) { EVP_MD_CTX *mdctx = NULL; unsigned int len = 0; mdctx = EVP_MD_CTX_create(); if (mdctx == NULL) { fail("Failed to create Hash context"); return 0; } if (EVP_DigestInit_ex(mdctx, md, NULL) == 0) { fail("Failed to initialize digest"); goto h_free; } if (EVP_DigestUpdate(mdctx, raw_derived, raw_derived_len) != 1) { fail("Failed to update digest"); goto h_free; } if (EVP_DigestFinal_ex(mdctx, hashed, &len) != 1) { fail("Failed to finalize digest"); len = 0; goto h_free; } h_free: if (mdctx != NULL) { EVP_MD_CTX_destroy(mdctx); } return len; } static size_t openssl_derive(CK_ULONG kdf, EVP_PKEY *private_key, EVP_PKEY *peer_key, unsigned char **ecdh_key, CK_ULONG expected_ecdh_len) { /* Create the context for the shared secret derivation */ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(private_key, NULL); if (!ctx) { fail("Failed to create new openssl context"); return 0; } EVP_MD_CTX *mdctx = NULL; size_t len = 0; /* Initialize derivation function*/ if (EVP_PKEY_derive_init(ctx) != 1) { fail("Failed to initialize openssl contex"); goto c_free; } /* Set the peer public key */ if (EVP_PKEY_derive_set_peer(ctx, peer_key) != 1) { fail("Failed to set the peer public key in the openssl context"); goto c_free; } /* Determine buffer length for shared secret */ if (EVP_PKEY_derive(ctx, NULL, &len) != 1) { fail("Failed to determine derived key expected size with openssl"); goto c_free; } /* Create the buffer */ unsigned char *derived = OPENSSL_malloc(len); if (derived == NULL) { fail("Failed to allocate the buffer to hold the ECDH key derived with " "openssl"); len = 0; goto c_free; } /* Derive the shared secret */ if ((EVP_PKEY_derive(ctx, derived, &len)) != 1) { fail("Failed to derive ECDH key with openssl"); len = 0; goto c_free; } *ecdh_key = malloc(BUFSIZE); if (*ecdh_key == NULL) { fail("Failed to allocate the buffer to hold the ECDH key derived with " "openssl"); len = 0; goto c_free; } size_t output_bits = 0; const EVP_MD *md = NULL; switch (kdf) { case CKD_NULL: memcpy(*ecdh_key, derived, len); goto c_truncate; case CKD_SHA1_KDF_SP800: md = EVP_sha1(); output_bits = 160; break; case CKD_SHA256_KDF_SP800: md = EVP_sha256(); output_bits = 256; break; case CKD_SHA384_KDF_SP800: md = EVP_sha384(); output_bits = 384; break; case CKD_SHA512_KDF_SP800: md = EVP_sha512(); output_bits = 384; break; } size_t l = expected_ecdh_len * 8; size_t reps = 1 + l / output_bits; uint8_t res[BUFSIZE] = {0}; size_t res_len = 0; size_t ctr_len = 4; uint8_t k[BUFSIZE] = {0}; size_t k_len = len + ctr_len; memset(k, 0, ctr_len); memcpy(k + ctr_len, derived, len); size_t hashed_len = 0; for (size_t i = 0; i < reps; i++) { increment_ctr(k, ctr_len); hashed_len = do_hash(md, res + res_len, k, k_len); if (hashed_len == 0) { fail("Failed to apply hash function"); len = 0; goto c_free; } res_len += hashed_len; } if (expected_ecdh_len > res_len) { fail("Derived key is too short"); len = 0; goto c_free; } memcpy(*ecdh_key, res, expected_ecdh_len); memset((*ecdh_key) + expected_ecdh_len, 0, BUFSIZE - expected_ecdh_len); len = expected_ecdh_len; c_truncate: if (expected_ecdh_len < len) { size_t offset = len - expected_ecdh_len; memmove(*ecdh_key, *ecdh_key + offset, expected_ecdh_len); len = expected_ecdh_len; } c_free: if (len == 0) { free(*ecdh_key); } EVP_PKEY_CTX_free(ctx); if (mdctx != NULL) { EVP_MD_CTX_destroy(mdctx); } EVP_PKEY_free(peer_key); EVP_PKEY_free(private_key); return len; } static unsigned char *openssl_derive_ecdh(CK_ULONG kdf, EVP_PKEY *private_key, CK_OBJECT_HANDLE peer_key, CK_ULONG expected_ecdh_len, size_t *ecdh_len) { CK_LONG peerkey_len = get_yhsize(peer_key); if (peerkey_len == 0) { fail("Failed to get peer key size"); return 0; } unsigned char peerkey_bytes[peerkey_len]; // public key in DER if (get_yhvalue(peer_key, peerkey_bytes, peerkey_len) == 0) { fail("Failed to retrieve public key from yubihsm-pkcs11"); return 0; } const unsigned char *p = peerkey_bytes; EVP_PKEY *pkey = d2i_PUBKEY(NULL, &p, peerkey_len); if (pkey == NULL) { fail("Failed to parse device public key with OpenSSL"); return NULL; } unsigned char *derivekey_openssl = malloc(BUFSIZE); *ecdh_len = openssl_derive(kdf, private_key, pkey, &derivekey_openssl, expected_ecdh_len); if (*ecdh_len == 0) { fail("Failed to derive key with openssl"); } return derivekey_openssl; } static void run_test(void *handle, const char *curve, CK_ULONG kdf, CK_OBJECT_HANDLE yh_privkey, CK_OBJECT_HANDLE yh_pubkey, CK_ULONG value_len, CK_ULONG ecdh_len, CK_RV exp_res) { printf("EC key %s, KDF 0x%lx, value_len %lu. derived ECDH length: %lu. " "Expected error code: 0x%lx....", curve, kdf, value_len, ecdh_len, exp_res); unsigned char *peerkey_bytes = NULL; // Generate keypair with openssl EVP_PKEY *peer_keypair = generate_keypair_openssl(curve); if (peer_keypair == NULL) { fail("Failed to generate keypair with OpenSSL"); goto clean_on_fail; } EC_KEY *peerkey = EVP_PKEY_get1_EC_KEY(peer_keypair); int peerkey_len = i2o_ECPublicKey(peerkey, &peerkey_bytes); if (peerkey_len < 0) { fail("Failed to extract public key from EC keypair generated with openssl"); goto clean_on_fail; } EC_KEY_free(peerkey); // Derive with yubihsm CK_OBJECT_HANDLE yh_ecdh_key; CK_RV rv = yh_derive(peerkey_bytes, peerkey_len, yh_privkey, kdf, "ecdh", &yh_ecdh_key, value_len, ecdh_len); if (rv != exp_res) { fail("Wrong error code was returned"); goto clean_on_fail; } OPENSSL_free(peerkey_bytes); // If testing error handling, no need to test further if (exp_res != CKR_OK) { printf("OK!\n"); return; } // Derive with openssl size_t ecdh_openssl_len = 0; unsigned char *ecdh_openssl = openssl_derive_ecdh(kdf, peer_keypair, yh_pubkey, ecdh_len, &ecdh_openssl_len); if (ecdh_openssl_len == 0) { fail("Failed to derive key with openssl"); goto clean_on_fail; } // Compare sizes CK_ULONG ecdh1_len = get_yhsize(yh_ecdh_key); if (ecdh1_len != ecdh_openssl_len) { fail( "ECDH keys derived with yubihsm-pkcs11 and with openssl do not have the " "same size"); goto clean_on_fail; } // Compare values unsigned char ecdh1_bytes[BUFSIZE]; // public key in DER if (get_yhvalue(yh_ecdh_key, ecdh1_bytes, ecdh1_len) == 0) { fail("Failed to retrieve derived key from yubihsm-pkcs11"); goto clean_on_fail; } bool equal = true; for (unsigned int i = 0; i < ecdh_openssl_len; i++) { if (ecdh1_bytes[i] != ecdh_openssl[i]) { equal = false; break; } } OPENSSL_free(ecdh_openssl); if (!equal) { fail( "ECDH keys derived with yubihsm-pkcs11 and with openssl do not have the " "same value"); goto clean_on_fail; } printf("OK!\n"); return; clean_on_fail: if (peerkey_bytes != NULL) { OPENSSL_free(peerkey_bytes); } close_session(p11, session); close_module(handle); exit(EXIT_FAILURE); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: /path/to/yubihsm_pkcs11/module\n"); exit(EXIT_FAILURE); } void *handle = open_module(argv[1]); p11 = get_function_list(handle); session = open_session(p11); print_session_state(p11, session); int exit_status = EXIT_SUCCESS; CK_OBJECT_HANDLE yh_pubkey[4], yh_privkey[4]; for (int i = 0; i < CURVE_COUNT; i++) { generate_keypair_yh(CURVE_PARAMS[i], CURVE_LENS[i], &yh_pubkey[i], &yh_privkey[i]); } printf("\n"); for (int i = 0; i < CURVE_COUNT; i++) { run_test(handle, CURVES[i], CKD_NULL, yh_privkey[i], yh_pubkey[i], 128 / 8, 128 / 8, CKR_OK); run_test(handle, CURVES[i], CKD_NULL, yh_privkey[i], yh_pubkey[i], 192 / 8, 192 / 8, CKR_OK); } run_test(handle, CURVES[0], CKD_NULL, yh_privkey[0], yh_pubkey[0], 256 / 8, 256 / 8, CKR_DATA_LEN_RANGE); run_test(handle, CURVES[1], CKD_NULL, yh_privkey[1], yh_pubkey[1], 256 / 8, 256 / 8, CKR_OK); run_test(handle, CURVES[2], CKD_NULL, yh_privkey[2], yh_pubkey[2], 256 / 8, 256 / 8, CKR_OK); run_test(handle, CURVES[3], CKD_NULL, yh_privkey[3], yh_pubkey[3], 256 / 8, 256 / 8, CKR_OK); CK_ULONG key_lens[3] = {128, 192, 256}; for (int i = 0; i < CURVE_COUNT; i++) { for (size_t j = 0; j < 3; j++) { run_test(handle, CURVES[i], CKD_SHA1_KDF_SP800, yh_privkey[i], yh_pubkey[i], key_lens[j] / 8, key_lens[j] / 8, CKR_OK); run_test(handle, CURVES[i], CKD_SHA256_KDF_SP800, yh_privkey[i], yh_pubkey[i], key_lens[j] / 8, key_lens[j] / 8, CKR_OK); run_test(handle, CURVES[i], CKD_SHA384_KDF_SP800, yh_privkey[i], yh_pubkey[i], key_lens[j] / 8, key_lens[j] / 8, CKR_OK); run_test(handle, CURVES[i], CKD_SHA512_KDF_SP800, yh_privkey[i], yh_pubkey[i], key_lens[j] / 8, key_lens[j] / 8, CKR_OK); } run_test(handle, CURVES[i], CKD_NULL, yh_privkey[i], yh_pubkey[i], 0, CURVE_ECDH_LEN[i], CKR_OK); run_test(handle, CURVES[i], CKD_SHA1_KDF_SP800, yh_privkey[i], yh_pubkey[i], 0, 20, CKR_OK); run_test(handle, CURVES[i], CKD_SHA256_KDF_SP800, yh_privkey[i], yh_pubkey[i], 0, 32, CKR_OK); run_test(handle, CURVES[i], CKD_SHA384_KDF_SP800, yh_privkey[i], yh_pubkey[i], 0, 48, CKR_OK); run_test(handle, CURVES[i], CKD_SHA512_KDF_SP800, yh_privkey[i], yh_pubkey[i], 0, 64, CKR_OK); } run_test(handle, CURVES[0], CKD_NULL, yh_privkey[0], yh_pubkey[0], 1024, 0, CKR_ATTRIBUTE_VALUE_INVALID); printf("\n"); for (int i = 0; i < CURVE_COUNT; i++) { if (destroy_object(p11, session, yh_privkey[i])) { success("Deleted key from YubiHSM"); } } close_session(p11, session); close_module(handle); return (exit_status); } yubihsm-shell-2.7.3/pkcs11/tests/pkcs11_interfaces_test.c0000644000175000017500000000734715167357110022263 0ustar aveenaveen/* * Copyright 2024 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include "../pkcs11y.h" #include "common.h" CK_VOID_PTR funcs; static CK_C_GetInterface get_interface_function(void *handle) { CK_C_GetInterface fn; *(void **) (&fn) = dlsym(handle, "C_GetInterface"); assert(fn != NULL); return fn; } static void get_default_functions(void *handle) { funcs = get_function_list(handle); } static void get_named_functions(void *handle) { CK_C_GetInterface fn = get_interface_function(handle); CK_INTERFACE_PTR interface; assert(fn((CK_UTF8CHAR_PTR)"PKCS 11", NULL, &interface, 0) == CKR_OK); funcs = interface->pFunctionList; } static void get_versioned_functions(void *handle, CK_BYTE major, CK_BYTE minor) { CK_C_GetInterface fn = get_interface_function(handle); CK_INTERFACE_PTR interface; CK_VERSION version; version.major=major; version.minor=minor; assert(fn(NULL,&version,&interface,0) == CKR_OK); funcs = interface->pFunctionList; } static void test_lib_info(CK_ULONG vmajor, CK_ULONG vminor) { const CK_CHAR_PTR MANUFACTURER_ID = (const CK_CHAR_PTR)"Yubico (www.yubico.com)"; const CK_CHAR_PTR PKCS11_DESCRIPTION = (const CK_CHAR_PTR)"YubiHSM PKCS#11 Library"; CK_C_INITIALIZE_ARGS initArgs; memset(&initArgs, 0, sizeof(initArgs)); const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } char config[256] = {0}; assert(strlen(connector_url) + strlen("connector=") < 256); snprintf(config, sizeof(config), "connector=%s", connector_url); initArgs.pReserved = (void *) config; assert(((CK_FUNCTION_LIST_3_0*)funcs)->C_Initialize(&initArgs) == CKR_OK); CK_INFO info; assert(((CK_FUNCTION_LIST_3_0*)funcs)->C_GetInfo(&info) == CKR_OK); assert(strncmp((const char*)info.manufacturerID, (const char*)MANUFACTURER_ID, strlen((const char*)MANUFACTURER_ID)) == 0); assert(info.cryptokiVersion.major == vmajor); assert(info.cryptokiVersion.minor == vminor); assert(info.libraryVersion.major == VERSION_MAJOR); assert(info.libraryVersion.minor == ((VERSION_MINOR * 10) + VERSION_PATCH)); assert(strncmp((const char*)info.libraryDescription, (const char*)PKCS11_DESCRIPTION, strlen((const char*)PKCS11_DESCRIPTION)) == 0); assert(((CK_FUNCTION_LIST_3_0*)funcs)->C_Finalize(NULL) == CKR_OK); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: /path/to/yubihsm_pkcs11/module\n"); exit(EXIT_FAILURE); } void *handle = open_module(argv[1]); get_default_functions(handle); test_lib_info(CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR); assert(((CK_FUNCTION_LIST_3_0*)funcs)->C_SignMessage(0, NULL, 0, NULL, 0, NULL, NULL) == CKR_FUNCTION_NOT_SUPPORTED); get_versioned_functions(handle, CRYPTOKI_LEGACY_VERSION_MAJOR, CRYPTOKI_LEGACY_VERSION_MINOR); test_lib_info(CRYPTOKI_LEGACY_VERSION_MAJOR, CRYPTOKI_LEGACY_VERSION_MINOR); get_versioned_functions(handle, CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR); test_lib_info(CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR); get_named_functions(handle); test_lib_info(CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR); return EXIT_SUCCESS; } yubihsm-shell-2.7.3/pkcs11/tests/pkcs11test.sh0000755000175000017500000000210015167357110020072 0ustar aveenaveen#!/usr/bin/bash # # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set -e if [ -z $PKCS11TEST_PATH ]; then bin="pkcs11test" else bin="${PKCS11TEST_PATH}/pkcs11test" fi dir=`mktemp -d /tmp/yubihsmtest.XXXXXX` trap 'rm -rf "$dir"' INT TERM EXIT if [ -z ${DEFAULT_CONNECTOR_URL} ]; then DEFAULT_CONNECTOR_URL="http://localhost:12345" fi cat > $dir/p11.conf <<-EOF connector = ${DEFAULT_CONNECTOR_URL} EOF export YUBIHSM_PKCS11_CONF=$dir/p11.conf env $bin -myubihsm_pkcs11.${LIBEXT} -l${BINDIR}/pkcs11 -u0001password --gtest_filter=-${SKIPPED_TESTS} yubihsm-shell-2.7.3/pkcs11/tests/common.h0000644000175000017500000000224715167357110017206 0ustar aveenaveen/* * Copyright 2021 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YUBIHSM_PKCS11_TESTS_COMMON_H #define YUBIHSM_PKCS11_TESTS_COMMON_H #include #include "../pkcs11y.h" void *open_module(const char *path); void close_module(void *handle); CK_FUNCTION_LIST_3_0_PTR get_function_list(void *handle); CK_SESSION_HANDLE open_session(CK_FUNCTION_LIST_3_0_PTR p11); void close_session(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session); void print_session_state(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session); bool destroy_object(CK_FUNCTION_LIST_3_0_PTR p11, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key); #endif yubihsm-shell-2.7.3/pkcs11/pkcs11f.h0000644000175000017500000010403115167357110016016 0ustar aveenaveen/* * PKCS #11 Specification Version 3.1 * Committee Specification Draft 01 * 16 February 2022 * Copyright (c) OASIS Open 2022. All Rights Reserved. * Source: * https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/csd01/include/pkcs11-v3.1/ * Latest stage of narrative specification: * https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html TC * IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php */ /* Copyright (c) OASIS Open 2016, 2019. All Rights Reserved./ * /Distributed under the terms of the OASIS IPR Policy, * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others. */ /* Latest version of the specification: * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html */ /* This header file contains pretty much everything about all the * Cryptoki function prototypes. Because this information is * used for more than just declaring function prototypes, the * order of the functions appearing herein is important, and * should not be altered. */ /* General-purpose */ /* C_Initialize initializes the Cryptoki library. */ CK_PKCS11_FUNCTION_INFO(C_Initialize) #ifdef CK_NEED_ARG_LIST (CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets * cast to CK_C_INITIALIZE_ARGS_PTR * and dereferenced */ ); #endif /* C_Finalize indicates that an application is done with the * Cryptoki library. */ CK_PKCS11_FUNCTION_INFO(C_Finalize) #ifdef CK_NEED_ARG_LIST (CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */ ); #endif /* C_GetInfo returns general information about Cryptoki. */ CK_PKCS11_FUNCTION_INFO(C_GetInfo) #ifdef CK_NEED_ARG_LIST (CK_INFO_PTR pInfo /* location that receives information */ ); #endif /* C_GetFunctionList returns the function list. */ CK_PKCS11_FUNCTION_INFO(C_GetFunctionList) #ifdef CK_NEED_ARG_LIST (CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to * function list */ ); #endif /* Slot and token management */ /* C_GetSlotList obtains a list of slots in the system. */ CK_PKCS11_FUNCTION_INFO(C_GetSlotList) #ifdef CK_NEED_ARG_LIST (CK_BBOOL tokenPresent, /* only slots with tokens */ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */ CK_ULONG_PTR pulCount /* receives number of slots */ ); #endif /* C_GetSlotInfo obtains information about a particular slot in * the system. */ CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo) #ifdef CK_NEED_ARG_LIST (CK_SLOT_ID slotID, /* the ID of the slot */ CK_SLOT_INFO_PTR pInfo /* receives the slot information */ ); #endif /* C_GetTokenInfo obtains information about a particular token * in the system. */ CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo) #ifdef CK_NEED_ARG_LIST (CK_SLOT_ID slotID, /* ID of the token's slot */ CK_TOKEN_INFO_PTR pInfo /* receives the token information */ ); #endif /* C_GetMechanismList obtains a list of mechanism types * supported by a token. */ CK_PKCS11_FUNCTION_INFO(C_GetMechanismList) #ifdef CK_NEED_ARG_LIST (CK_SLOT_ID slotID, /* ID of token's slot */ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */ CK_ULONG_PTR pulCount /* gets # of mechs. */ ); #endif /* C_GetMechanismInfo obtains information about a particular * mechanism possibly supported by a token. */ CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo) #ifdef CK_NEED_ARG_LIST (CK_SLOT_ID slotID, /* ID of the token's slot */ CK_MECHANISM_TYPE type, /* type of mechanism */ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */ ); #endif /* C_InitToken initializes a token. */ CK_PKCS11_FUNCTION_INFO(C_InitToken) #ifdef CK_NEED_ARG_LIST (CK_SLOT_ID slotID, /* ID of the token's slot */ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */ CK_ULONG ulPinLen, /* length in bytes of the PIN */ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */ ); #endif /* C_InitPIN initializes the normal user's PIN. */ CK_PKCS11_FUNCTION_INFO(C_InitPIN) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */ CK_ULONG ulPinLen /* length in bytes of the PIN */ ); #endif /* C_SetPIN modifies the PIN of the user who is logged in. */ CK_PKCS11_FUNCTION_INFO(C_SetPIN) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */ CK_ULONG ulOldLen, /* length of the old PIN */ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */ CK_ULONG ulNewLen /* length of the new PIN */ ); #endif /* Session management */ /* C_OpenSession opens a session between an application and a * token. */ CK_PKCS11_FUNCTION_INFO(C_OpenSession) #ifdef CK_NEED_ARG_LIST (CK_SLOT_ID slotID, /* the slot's ID */ CK_FLAGS flags, /* from CK_SESSION_INFO */ CK_VOID_PTR pApplication, /* passed to callback */ CK_NOTIFY Notify, /* callback function */ CK_SESSION_HANDLE_PTR phSession /* gets session handle */ ); #endif /* C_CloseSession closes a session between an application and a * token. */ CK_PKCS11_FUNCTION_INFO(C_CloseSession) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession /* the session's handle */ ); #endif /* C_CloseAllSessions closes all sessions with a token. */ CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions) #ifdef CK_NEED_ARG_LIST (CK_SLOT_ID slotID /* the token's slot */ ); #endif /* C_GetSessionInfo obtains information about the session. */ CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_SESSION_INFO_PTR pInfo /* receives session info */ ); #endif /* C_GetOperationState obtains the state of the cryptographic operation * in a session. */ CK_PKCS11_FUNCTION_INFO(C_GetOperationState) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pOperationState, /* gets state */ CK_ULONG_PTR pulOperationStateLen /* gets state length */ ); #endif /* C_SetOperationState restores the state of the cryptographic * operation in a session. */ CK_PKCS11_FUNCTION_INFO(C_SetOperationState) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pOperationState, /* holds state */ CK_ULONG ulOperationStateLen, /* holds state length */ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */ ); #endif /* C_Login logs a user into a token. */ CK_PKCS11_FUNCTION_INFO(C_Login) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_USER_TYPE userType, /* the user type */ CK_UTF8CHAR_PTR pPin, /* the user's PIN */ CK_ULONG ulPinLen /* the length of the PIN */ ); #endif /* C_Logout logs a user out from a token. */ CK_PKCS11_FUNCTION_INFO(C_Logout) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession /* the session's handle */ ); #endif /* Object management */ /* C_CreateObject creates a new object. */ CK_PKCS11_FUNCTION_INFO(C_CreateObject) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */ CK_ULONG ulCount, /* attributes in template */ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */ ); #endif /* C_CopyObject copies an object, creating a new object for the * copy. */ CK_PKCS11_FUNCTION_INFO(C_CopyObject) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_OBJECT_HANDLE hObject, /* the object's handle */ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */ CK_ULONG ulCount, /* attributes in template */ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */ ); #endif /* C_DestroyObject destroys an object. */ CK_PKCS11_FUNCTION_INFO(C_DestroyObject) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_OBJECT_HANDLE hObject /* the object's handle */ ); #endif /* C_GetObjectSize gets the size of an object in bytes. */ CK_PKCS11_FUNCTION_INFO(C_GetObjectSize) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_OBJECT_HANDLE hObject, /* the object's handle */ CK_ULONG_PTR pulSize /* receives size of object */ ); #endif /* C_GetAttributeValue obtains the value of one or more object * attributes. */ CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_OBJECT_HANDLE hObject, /* the object's handle */ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */ CK_ULONG ulCount /* attributes in template */ ); #endif /* C_SetAttributeValue modifies the value of one or more object * attributes. */ CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_OBJECT_HANDLE hObject, /* the object's handle */ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */ CK_ULONG ulCount /* attributes in template */ ); #endif /* C_FindObjectsInit initializes a search for token and session * objects that match a template. */ CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */ CK_ULONG ulCount /* attrs in search template */ ); #endif /* C_FindObjects continues a search for token and session * objects that match a template, obtaining additional object * handles. */ CK_PKCS11_FUNCTION_INFO(C_FindObjects) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */ CK_ULONG ulMaxObjectCount, /* max handles to get */ CK_ULONG_PTR pulObjectCount /* actual # returned */ ); #endif /* C_FindObjectsFinal finishes a search for token and session * objects. */ CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession /* the session's handle */ ); #endif /* Encryption and decryption */ /* C_EncryptInit initializes an encryption operation. */ CK_PKCS11_FUNCTION_INFO(C_EncryptInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */ CK_OBJECT_HANDLE hKey /* handle of encryption key */ ); #endif /* C_Encrypt encrypts single-part data. */ CK_PKCS11_FUNCTION_INFO(C_Encrypt) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pData, /* the plaintext data */ CK_ULONG ulDataLen, /* bytes of plaintext */ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */ ); #endif /* C_EncryptUpdate continues a multiple-part encryption * operation. */ CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pPart, /* the plaintext data */ CK_ULONG ulPartLen, /* plaintext data len */ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */ ); #endif /* C_EncryptFinal finishes a multiple-part encryption * operation. */ CK_PKCS11_FUNCTION_INFO(C_EncryptFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session handle */ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */ ); #endif /* C_DecryptInit initializes a decryption operation. */ CK_PKCS11_FUNCTION_INFO(C_DecryptInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */ CK_OBJECT_HANDLE hKey /* handle of decryption key */ ); #endif /* C_Decrypt decrypts encrypted data in a single part. */ CK_PKCS11_FUNCTION_INFO(C_Decrypt) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pEncryptedData, /* ciphertext */ CK_ULONG ulEncryptedDataLen, /* ciphertext length */ CK_BYTE_PTR pData, /* gets plaintext */ CK_ULONG_PTR pulDataLen /* gets p-text size */ ); #endif /* C_DecryptUpdate continues a multiple-part decryption * operation. */ CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pEncryptedPart, /* encrypted data */ CK_ULONG ulEncryptedPartLen, /* input length */ CK_BYTE_PTR pPart, /* gets plaintext */ CK_ULONG_PTR pulPartLen /* p-text size */ ); #endif /* C_DecryptFinal finishes a multiple-part decryption * operation. */ CK_PKCS11_FUNCTION_INFO(C_DecryptFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pLastPart, /* gets plaintext */ CK_ULONG_PTR pulLastPartLen /* p-text size */ ); #endif /* Message digesting */ /* C_DigestInit initializes a message-digesting operation. */ CK_PKCS11_FUNCTION_INFO(C_DigestInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */ ); #endif /* C_Digest digests data in a single part. */ CK_PKCS11_FUNCTION_INFO(C_Digest) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pData, /* data to be digested */ CK_ULONG ulDataLen, /* bytes of data to digest */ CK_BYTE_PTR pDigest, /* gets the message digest */ CK_ULONG_PTR pulDigestLen /* gets digest length */ ); #endif /* C_DigestUpdate continues a multiple-part message-digesting * operation. */ CK_PKCS11_FUNCTION_INFO(C_DigestUpdate) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pPart, /* data to be digested */ CK_ULONG ulPartLen /* bytes of data to be digested */ ); #endif /* C_DigestKey continues a multi-part message-digesting * operation, by digesting the value of a secret key as part of * the data already digested. */ CK_PKCS11_FUNCTION_INFO(C_DigestKey) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_OBJECT_HANDLE hKey /* secret key to digest */ ); #endif /* C_DigestFinal finishes a multiple-part message-digesting * operation. */ CK_PKCS11_FUNCTION_INFO(C_DigestFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pDigest, /* gets the message digest */ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */ ); #endif /* Signing and MACing */ /* C_SignInit initializes a signature (private key encryption) * operation, where the signature is (will be) an appendix to * the data, and plaintext cannot be recovered from the * signature. */ CK_PKCS11_FUNCTION_INFO(C_SignInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ CK_OBJECT_HANDLE hKey /* handle of signature key */ ); #endif /* C_Sign signs (encrypts with private key) data in a single * part, where the signature is (will be) an appendix to the * data, and plaintext cannot be recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_Sign) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pData, /* the data to sign */ CK_ULONG ulDataLen, /* count of bytes to sign */ CK_BYTE_PTR pSignature, /* gets the signature */ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ); #endif /* C_SignUpdate continues a multiple-part signature operation, * where the signature is (will be) an appendix to the data, * and plaintext cannot be recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_SignUpdate) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pPart, /* the data to sign */ CK_ULONG ulPartLen /* count of bytes to sign */ ); #endif /* C_SignFinal finishes a multiple-part signature operation, * returning the signature. */ CK_PKCS11_FUNCTION_INFO(C_SignFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pSignature, /* gets the signature */ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ); #endif /* C_SignRecoverInit initializes a signature operation, where * the data can be recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ CK_OBJECT_HANDLE hKey /* handle of the signature key */ ); #endif /* C_SignRecover signs data in a single operation, where the * data can be recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_SignRecover) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pData, /* the data to sign */ CK_ULONG ulDataLen, /* count of bytes to sign */ CK_BYTE_PTR pSignature, /* gets the signature */ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ); #endif /* Verifying signatures and MACs */ /* C_VerifyInit initializes a verification operation, where the * signature is an appendix to the data, and plaintext cannot * cannot be recovered from the signature (e.g. DSA). */ CK_PKCS11_FUNCTION_INFO(C_VerifyInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ CK_OBJECT_HANDLE hKey /* verification key */ ); #endif /* C_Verify verifies a signature in a single-part operation, * where the signature is an appendix to the data, and plaintext * cannot be recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_Verify) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pData, /* signed data */ CK_ULONG ulDataLen, /* length of signed data */ CK_BYTE_PTR pSignature, /* signature */ CK_ULONG ulSignatureLen /* signature length*/ ); #endif /* C_VerifyUpdate continues a multiple-part verification * operation, where the signature is an appendix to the data, * and plaintext cannot be recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pPart, /* signed data */ CK_ULONG ulPartLen /* length of signed data */ ); #endif /* C_VerifyFinal finishes a multiple-part verification * operation, checking the signature. */ CK_PKCS11_FUNCTION_INFO(C_VerifyFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pSignature, /* signature to verify */ CK_ULONG ulSignatureLen /* signature length */ ); #endif /* C_VerifyRecoverInit initializes a signature verification * operation, where the data is recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ CK_OBJECT_HANDLE hKey /* verification key */ ); #endif /* C_VerifyRecover verifies a signature in a single-part * operation, where the data is recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_VerifyRecover) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pSignature, /* signature to verify */ CK_ULONG ulSignatureLen, /* signature length */ CK_BYTE_PTR pData, /* gets signed data */ CK_ULONG_PTR pulDataLen /* gets signed data len */ ); #endif /* Dual-function cryptographic operations */ /* C_DigestEncryptUpdate continues a multiple-part digesting * and encryption operation. */ CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pPart, /* the plaintext data */ CK_ULONG ulPartLen, /* plaintext length */ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ ); #endif /* C_DecryptDigestUpdate continues a multiple-part decryption and * digesting operation. */ CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pEncryptedPart, /* ciphertext */ CK_ULONG ulEncryptedPartLen, /* ciphertext length */ CK_BYTE_PTR pPart, /* gets plaintext */ CK_ULONG_PTR pulPartLen /* gets plaintext len */ ); #endif /* C_SignEncryptUpdate continues a multiple-part signing and * encryption operation. */ CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pPart, /* the plaintext data */ CK_ULONG ulPartLen, /* plaintext length */ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ ); #endif /* C_DecryptVerifyUpdate continues a multiple-part decryption and * verify operation. */ CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_BYTE_PTR pEncryptedPart, /* ciphertext */ CK_ULONG ulEncryptedPartLen, /* ciphertext length */ CK_BYTE_PTR pPart, /* gets plaintext */ CK_ULONG_PTR pulPartLen /* gets p-text length */ ); #endif /* Key management */ /* C_GenerateKey generates a secret key, creating a new key * object. */ CK_PKCS11_FUNCTION_INFO(C_GenerateKey) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* key generation mech. */ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */ CK_ULONG ulCount, /* # of attrs in template */ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */ ); #endif /* C_GenerateKeyPair generates a public-key/private-key pair, * creating new key objects. */ CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session handle */ CK_MECHANISM_PTR pMechanism, /* key-gen mech. */ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template for pub. key */ CK_ULONG ulPublicKeyAttributeCount, /* # pub. attrs. */ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template for priv. key */ CK_ULONG ulPrivateKeyAttributeCount, /* # priv. attrs. */ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. key handle */ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets priv. key handle */ ); #endif /* C_WrapKey wraps (i.e., encrypts) a key. */ CK_PKCS11_FUNCTION_INFO(C_WrapKey) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */ CK_OBJECT_HANDLE hKey, /* key to be wrapped */ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */ ); #endif /* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new * key object. */ CK_PKCS11_FUNCTION_INFO(C_UnwrapKey) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */ CK_BYTE_PTR pWrappedKey, /* the wrapped key */ CK_ULONG ulWrappedKeyLen, /* wrapped key len */ CK_ATTRIBUTE_PTR pTemplate, /* new key template */ CK_ULONG ulAttributeCount, /* template length */ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ ); #endif /* C_DeriveKey derives a key from a base key, creating a new key * object. */ CK_PKCS11_FUNCTION_INFO(C_DeriveKey) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* session's handle */ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */ CK_OBJECT_HANDLE hBaseKey, /* base key */ CK_ATTRIBUTE_PTR pTemplate, /* new key template */ CK_ULONG ulAttributeCount, /* template length */ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ ); #endif /* Random number generation */ /* C_SeedRandom mixes additional seed material into the token's * random number generator. */ CK_PKCS11_FUNCTION_INFO(C_SeedRandom) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pSeed, /* the seed material */ CK_ULONG ulSeedLen /* length of seed material */ ); #endif /* C_GenerateRandom generates random data. */ CK_PKCS11_FUNCTION_INFO(C_GenerateRandom) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR RandomData, /* receives the random data */ CK_ULONG ulRandomLen /* # of bytes to generate */ ); #endif /* Parallel function management */ /* C_GetFunctionStatus is a legacy function; it obtains an * updated status of a function running in parallel with an * application. */ CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession /* the session's handle */ ); #endif /* C_CancelFunction is a legacy function; it cancels a function * running in parallel. */ CK_PKCS11_FUNCTION_INFO(C_CancelFunction) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession /* the session's handle */ ); #endif /* C_WaitForSlotEvent waits for a slot event (token insertion, * removal, etc.) to occur. */ CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent) #ifdef CK_NEED_ARG_LIST (CK_FLAGS flags, /* blocking/nonblocking flag */ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */ ); #endif #ifndef CK_PKCS11_2_0_ONLY /* C_GetInterfaceList returns all the interfaces supported by the module*/ CK_PKCS11_FUNCTION_INFO(C_GetInterfaceList) #ifdef CK_NEED_ARG_LIST (CK_INTERFACE_PTR pInterfacesList, /* returned interfaces */ CK_ULONG_PTR pulCount /* number of interfaces returned */ ); #endif /* C_GetInterface returns a specific interface from the module. */ CK_PKCS11_FUNCTION_INFO(C_GetInterface) #ifdef CK_NEED_ARG_LIST (CK_UTF8CHAR_PTR pInterfaceName, /* name of the interface */ CK_VERSION_PTR pVersion, /* version of the interface */ CK_INTERFACE_PTR_PTR ppInterface, /* returned interface */ CK_FLAGS flags /* flags controlling the semantics * of the interface */ ); #endif CK_PKCS11_FUNCTION_INFO(C_LoginUser) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_USER_TYPE userType, /* the user type */ CK_UTF8CHAR_PTR pPin, /* the user's PIN */ CK_ULONG ulPinLen, /* the length of the PIN */ CK_UTF8CHAR_PTR pUsername, /* the user's name */ CK_ULONG ulUsernameLen /*the length of the user's name */ ); #endif CK_PKCS11_FUNCTION_INFO(C_SessionCancel) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_FLAGS flags /* flags control which sessions are cancelled */ ); #endif CK_PKCS11_FUNCTION_INFO(C_MessageEncryptInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */ CK_OBJECT_HANDLE hKey /* handle of encryption key */ ); #endif CK_PKCS11_FUNCTION_INFO(C_EncryptMessage) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ CK_ULONG ulAssociatedDataLen, /* AEAD Associated data length */ CK_BYTE_PTR pPlaintext, /* plain text */ CK_ULONG ulPlaintextLen, /* plain text length */ CK_BYTE_PTR pCiphertext, /* gets cipher text */ CK_ULONG_PTR pulCiphertextLen /* gets cipher text length */ ); #endif CK_PKCS11_FUNCTION_INFO(C_EncryptMessageBegin) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ CK_ULONG ulAssociatedDataLen /* AEAD Associated data length */ ); #endif CK_PKCS11_FUNCTION_INFO(C_EncryptMessageNext) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pPlaintextPart, /* plain text */ CK_ULONG ulPlaintextPartLen, /* plain text length */ CK_BYTE_PTR pCiphertextPart, /* gets cipher text */ CK_ULONG_PTR pulCiphertextPartLen, /* gets cipher text length */ CK_FLAGS flags /* multi mode flag */ ); #endif CK_PKCS11_FUNCTION_INFO(C_MessageEncryptFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession /* the session's handle */ ); #endif CK_PKCS11_FUNCTION_INFO(C_MessageDecryptInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */ CK_OBJECT_HANDLE hKey /* handle of decryption key */ ); #endif CK_PKCS11_FUNCTION_INFO(C_DecryptMessage) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ CK_ULONG ulAssociatedDataLen, /* AEAD Associated data length */ CK_BYTE_PTR pCiphertext, /* cipher text */ CK_ULONG ulCiphertextLen, /* cipher text length */ CK_BYTE_PTR pPlaintext, /* gets plain text */ CK_ULONG_PTR pulPlaintextLen /* gets plain text length */ ); #endif CK_PKCS11_FUNCTION_INFO(C_DecryptMessageBegin) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ CK_ULONG ulAssociatedDataLen /* AEAD Associated data length */ ); #endif CK_PKCS11_FUNCTION_INFO(C_DecryptMessageNext) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pCiphertextPart, /* cipher text */ CK_ULONG ulCiphertextPartLen, /* cipher text length */ CK_BYTE_PTR pPlaintextPart, /* gets plain text */ CK_ULONG_PTR pulPlaintextPartLen, /* gets plain text length */ CK_FLAGS flags /* multi mode flag */ ); #endif CK_PKCS11_FUNCTION_INFO(C_MessageDecryptFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession /* the session's handle */ ); #endif CK_PKCS11_FUNCTION_INFO(C_MessageSignInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the signing mechanism */ CK_OBJECT_HANDLE hKey /* handle of signing key */ ); #endif CK_PKCS11_FUNCTION_INFO(C_SignMessage) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pData, /* data to sign */ CK_ULONG ulDataLen, /* data to sign length */ CK_BYTE_PTR pSignature, /* gets signature */ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ); #endif CK_PKCS11_FUNCTION_INFO(C_SignMessageBegin) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen /* length of message specific parameter */ ); #endif CK_PKCS11_FUNCTION_INFO(C_SignMessageNext) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pData, /* data to sign */ CK_ULONG ulDataLen, /* data to sign length */ CK_BYTE_PTR pSignature, /* gets signature */ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ); #endif CK_PKCS11_FUNCTION_INFO(C_MessageSignFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession /* the session's handle */ ); #endif CK_PKCS11_FUNCTION_INFO(C_MessageVerifyInit) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the signing mechanism */ CK_OBJECT_HANDLE hKey /* handle of signing key */ ); #endif CK_PKCS11_FUNCTION_INFO(C_VerifyMessage) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pData, /* data to sign */ CK_ULONG ulDataLen, /* data to sign length */ CK_BYTE_PTR pSignature, /* signature */ CK_ULONG ulSignatureLen /* signature length */ ); #endif CK_PKCS11_FUNCTION_INFO(C_VerifyMessageBegin) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen /* length of message specific parameter */ ); #endif CK_PKCS11_FUNCTION_INFO(C_VerifyMessageNext) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession, /* the session's handle */ CK_VOID_PTR pParameter, /* message specific parameter */ CK_ULONG ulParameterLen, /* length of message specific parameter */ CK_BYTE_PTR pData, /* data to sign */ CK_ULONG ulDataLen, /* data to sign length */ CK_BYTE_PTR pSignature, /* signature */ CK_ULONG ulSignatureLen /* signature length */ ); #endif CK_PKCS11_FUNCTION_INFO(C_MessageVerifyFinal) #ifdef CK_NEED_ARG_LIST (CK_SESSION_HANDLE hSession /* the session's handle */ ); #endif #endif /* CK_PKCS11_2_0_ONLY */ yubihsm-shell-2.7.3/pkcs11/cmdline.ggo0000644000175000017500000000306415167357110016512 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # option "config-file" - "Configuration file to read" string optional default="./yubihsm_pkcs11.conf" option "connector" - "List of connectors to use" string optional multiple option "debug" - "Enable pkcs11 debugging" flag off option "dinout" - "Enable pkcs11 function tracing" flag off option "libdebug" - "Enable libyubihsm debugging" flag off option "debug-file" - "Output file for debugging" string optional default="stderr" option "cacert" - "Cacert to use for HTTPS validation" string optional option "cert" - "HTTPS client certificate to authenticate with" string optional option "key" - "HTTPS client certificate key" string optional option "proxy" - "Proxy server to use for connector" string optional option "noproxy" - "Comma separated list of hosts ignore proxy for" string optional option "timeout" - "Timeout to use for initial connection to connector" int optional default="5" option "device-pubkey" - "List of device public keys allowed for asymmetric authentication" string optional multiple yubihsm-shell-2.7.3/pkcs11/README.adoc0000644000175000017500000001061315167357110016164 0ustar aveenaveen== YubiHSM PKCS#11 Module The YubiHSM PKCS#11 Module is a native library to interact with a YubiHSM 2 device using the link:http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html[PKCS#11 interface]. This library works as a translation layer between `libyubihsm` and software using PKCS#11. For example, a function in this implementation takes the input as specified by PKCS#11, translates it into the input expected by the corresponding function in `libyubihsm`, calls that function and then translates the result into the return value expected by PKCS#11. === Connector Configuration The link:https://developers.yubico.com/YubiHSM2/Component_Reference/yubihsm-connector/[Connector] is a component required by a YubiHSM 2 device that performs the communication between the device and applications using it. A connector can be either an external process communicating over HTTP (by default `http://localhost:12345`), or directly linked in by `libyubihsm` in the case of direct USB access. The PKCS#11 module requires a configuration file containing the URL of the Connector and other configuration options. The default location for that file is the current directory and its default name is `yubihsm_pkcs11.conf`. However, using the environment variable `YUBIHSM_PKCS11_CONF`, one can point to a custom location and name. Below is an example of a `yubihsm_pkcs11.conf` file: [source, cfg] ---- connector=http://localhost:12345 debug libdebug dinout ---- This file will turn on debug messages for the PKCS#11 module (`debug`), `libyubihsm` (`libdebug`) and functions call tracing (`dinout`) A full list of the configuration options can be found on the link:https://developers.yubico.com/YubiHSM2/Component_Reference/PKCS_11/[developers website]. ==== Initialization Arguments One of the possible parameters given to the PKCS#11 `C_Initialize` function, `pReserved`, can also be used to provide configuration options to the module. While this is technically in violation of the PKCS#11 specifications which requires that field to be set to `NULL`, some application such as OpenSSL support this behavior. An example of using this technique can be found on the link:https://developers.yubico.com/YubiHSM2/Component_Reference/PKCS_11/[developers website]. === Logging In All interesting operations available through the PKCS#11 interface require a logged-in session. One peculiarity of the YubiHSM PKCS#11 module is that the user PIN _MUST_ be prefixed with the ID (16 bits, in hexadecimal, zero padded if required) of the Authentication Key that should be used to perform the login operation. For example, to use the default Authentication Key with ID `1` and password `password`, the user PIN would then be `0001password`. To be compliant with PKCS#11 standards, the Authentication Key password _MUST_ be at least `8` characters long. === PKCS#11 Attributes There are a number of settable attributes defined by PKCS#11 that do not accurately translate to YubiHSM 2 Capabilities and are therefore treated as always having a fixed value. A list of those attributes and their values can be found on the link:https://developers.yubico.com/YubiHSM2/Component_Reference/PKCS_11/[developers website]. === Capabilities and Domains Objects created via the PKCS#11 module inherit the Domains of the Authentication Key used to establish the session. The Domains can not be changed or modified via the PKCS#11 module. A table mapping PKCS#11 objects to YubiHSM 2 Capabilities can be found on the link:https://developers.yubico.com/YubiHSM2/Component_Reference/PKCS_11/[developers website]. === PKCS#11 Objects Not all PKCS#11 Object Types are implemented. A list of what is implemented is available link:https://developers.yubico.com/YubiHSM2/Component_Reference/PKCS_11/[here]. === Examples ==== C Code Example Code examples of how to use the PKCS#11 module from C programs can be found in the test link:tests/ecdh_derive_test.c ==== Pkcs11-tool Example To derive an ECDH key using a public key in the file `peer.key` and a private key in the YubiHSM 2 with OpenSC `pkcs11-tool`, the following command can be used: [source, sh] ---- pkcs11-tool -vvv --module yubihsm_pkcs11.so --derive -i peer.key --id 64 --login --pin 0001password ---- The private key in YubiHSM 2 has Object ID `0x0064` and the public key in `peer.key` is expected to be in DER format. By default, this command will expect to find a `yubihsm_pkcs11.conf` file in the current directory. yubihsm-shell-2.7.3/pkcs11/pkcs11t.h0000644000175000017500000023252015167357110016041 0ustar aveenaveen/* * PKCS #11 Specification Version 3.1 * Committee Specification Draft 01 * 16 February 2022 * Copyright (c) OASIS Open 2022. All Rights Reserved. * Source: * https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/csd01/include/pkcs11-v3.1/ * Latest stage of narrative specification: * https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html TC * IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php */ /* Copyright (c) OASIS Open 2016, 2019. All Rights Reserved./ * /Distributed under the terms of the OASIS IPR Policy, * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others. */ /* Latest version of the specification: * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html */ /* See top of pkcs11.h for information about the macros that * must be defined and the structure-packing conventions that * must be set before including this file. */ #ifndef _PKCS11T_H_ #define _PKCS11T_H_ 1 #define CRYPTOKI_VERSION_MAJOR 3 #define CRYPTOKI_VERSION_MINOR 1 #define CRYPTOKI_VERSION_AMENDMENT 0 #define CK_TRUE 1 #define CK_FALSE 0 #ifndef CK_DISABLE_TRUE_FALSE #ifndef FALSE #define FALSE CK_FALSE #endif #ifndef TRUE #define TRUE CK_TRUE #endif #endif /* an unsigned 8-bit value */ typedef unsigned char CK_BYTE; /* an unsigned 8-bit character */ typedef CK_BYTE CK_CHAR; /* an 8-bit UTF-8 character */ typedef CK_BYTE CK_UTF8CHAR; /* a BYTE-sized Boolean flag */ typedef CK_BYTE CK_BBOOL; /* an unsigned value, at least 32 bits long */ typedef unsigned long int CK_ULONG; /* a signed value, the same size as a CK_ULONG */ typedef long int CK_LONG; /* at least 32 bits; each bit is a Boolean flag */ typedef CK_ULONG CK_FLAGS; /* some special values for certain CK_ULONG variables */ #define CK_UNAVAILABLE_INFORMATION (~0UL) #define CK_EFFECTIVELY_INFINITE 0UL typedef CK_BYTE CK_PTR CK_BYTE_PTR; typedef CK_CHAR CK_PTR CK_CHAR_PTR; typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR; typedef CK_ULONG CK_PTR CK_ULONG_PTR; typedef void CK_PTR CK_VOID_PTR; /* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */ typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR; /* The following value is always invalid if used as a session * handle or object handle */ #define CK_INVALID_HANDLE 0UL typedef struct CK_VERSION { CK_BYTE major; /* integer portion of version number */ CK_BYTE minor; /* 1/100ths portion of version number */ } CK_VERSION; typedef CK_VERSION CK_PTR CK_VERSION_PTR; typedef struct CK_INFO { CK_VERSION cryptokiVersion; /* Cryptoki interface ver */ CK_UTF8CHAR manufacturerID[32]; /* blank padded */ CK_FLAGS flags; /* must be zero */ CK_UTF8CHAR libraryDescription[32]; /* blank padded */ CK_VERSION libraryVersion; /* version of library */ } CK_INFO; typedef CK_INFO CK_PTR CK_INFO_PTR; /* CK_NOTIFICATION enumerates the types of notifications that * Cryptoki provides to an application */ typedef CK_ULONG CK_NOTIFICATION; #define CKN_SURRENDER 0UL #define CKN_OTP_CHANGED 1UL typedef CK_ULONG CK_SLOT_ID; typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR; /* CK_SLOT_INFO provides information about a slot */ typedef struct CK_SLOT_INFO { CK_UTF8CHAR slotDescription[64]; /* blank padded */ CK_UTF8CHAR manufacturerID[32]; /* blank padded */ CK_FLAGS flags; CK_VERSION hardwareVersion; /* version of hardware */ CK_VERSION firmwareVersion; /* version of firmware */ } CK_SLOT_INFO; /* flags: bit flags that provide capabilities of the slot * Bit Flag Mask Meaning */ #define CKF_TOKEN_PRESENT 0x00000001UL /* a token is there */ #define CKF_REMOVABLE_DEVICE 0x00000002UL /* removable devices*/ #define CKF_HW_SLOT 0x00000004UL /* hardware slot */ typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR; /* CK_TOKEN_INFO provides information about a token */ typedef struct CK_TOKEN_INFO { CK_UTF8CHAR label[32]; /* blank padded */ CK_UTF8CHAR manufacturerID[32]; /* blank padded */ CK_UTF8CHAR model[16]; /* blank padded */ CK_CHAR serialNumber[16]; /* blank padded */ CK_FLAGS flags; /* see below */ CK_ULONG ulMaxSessionCount; /* max open sessions */ CK_ULONG ulSessionCount; /* sess. now open */ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */ CK_ULONG ulRwSessionCount; /* R/W sess. now open */ CK_ULONG ulMaxPinLen; /* in bytes */ CK_ULONG ulMinPinLen; /* in bytes */ CK_ULONG ulTotalPublicMemory; /* in bytes */ CK_ULONG ulFreePublicMemory; /* in bytes */ CK_ULONG ulTotalPrivateMemory; /* in bytes */ CK_ULONG ulFreePrivateMemory; /* in bytes */ CK_VERSION hardwareVersion; /* version of hardware */ CK_VERSION firmwareVersion; /* version of firmware */ CK_CHAR utcTime[16]; /* time */ } CK_TOKEN_INFO; /* The flags parameter is defined as follows: * Bit Flag Mask Meaning */ #define CKF_RNG 0x00000001UL /* has random # generator */ #define CKF_WRITE_PROTECTED 0x00000002UL /* token is write-protected */ #define CKF_LOGIN_REQUIRED 0x00000004UL /* user must login */ #define CKF_USER_PIN_INITIALIZED 0x00000008UL /* normal user's PIN is set */ /* CKF_RESTORE_KEY_NOT_NEEDED. If it is set, * that means that *every* time the state of cryptographic * operations of a session is successfully saved, all keys * needed to continue those operations are stored in the state */ #define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020UL /* CKF_CLOCK_ON_TOKEN. If it is set, that means * that the token has some sort of clock. The time on that * clock is returned in the token info structure */ #define CKF_CLOCK_ON_TOKEN 0x00000040UL /* CKF_PROTECTED_AUTHENTICATION_PATH. If it is * set, that means that there is some way for the user to login * without sending a PIN through the Cryptoki library itself */ #define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100UL /* CKF_DUAL_CRYPTO_OPERATIONS. If it is true, * that means that a single session with the token can perform * dual simultaneous cryptographic operations (digest and * encrypt; decrypt and digest; sign and encrypt; and decrypt * and sign) */ #define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200UL /* CKF_TOKEN_INITIALIZED. If it is true, the * token has been initialized using C_InitializeToken or an * equivalent mechanism outside the scope of PKCS #11. * Calling C_InitializeToken when this flag is set will cause * the token to be reinitialized. */ #define CKF_TOKEN_INITIALIZED 0x00000400UL /* CKF_SECONDARY_AUTHENTICATION. If it is * true, the token supports secondary authentication for * private key objects. */ #define CKF_SECONDARY_AUTHENTICATION 0x00000800UL /* CKF_USER_PIN_COUNT_LOW. If it is true, an * incorrect user login PIN has been entered at least once * since the last successful authentication. */ #define CKF_USER_PIN_COUNT_LOW 0x00010000UL /* CKF_USER_PIN_FINAL_TRY. If it is true, * supplying an incorrect user PIN will it to become locked. */ #define CKF_USER_PIN_FINAL_TRY 0x00020000UL /* CKF_USER_PIN_LOCKED. If it is true, the * user PIN has been locked. User login to the token is not * possible. */ #define CKF_USER_PIN_LOCKED 0x00040000UL /* CKF_USER_PIN_TO_BE_CHANGED. If it is true, * the user PIN value is the default value set by token * initialization or manufacturing, or the PIN has been * expired by the card. */ #define CKF_USER_PIN_TO_BE_CHANGED 0x00080000UL /* CKF_SO_PIN_COUNT_LOW. If it is true, an * incorrect SO login PIN has been entered at least once since * the last successful authentication. */ #define CKF_SO_PIN_COUNT_LOW 0x00100000UL /* CKF_SO_PIN_FINAL_TRY. If it is true, * supplying an incorrect SO PIN will it to become locked. */ #define CKF_SO_PIN_FINAL_TRY 0x00200000UL /* CKF_SO_PIN_LOCKED. If it is true, the SO * PIN has been locked. SO login to the token is not possible. */ #define CKF_SO_PIN_LOCKED 0x00400000UL /* CKF_SO_PIN_TO_BE_CHANGED. If it is true, * the SO PIN value is the default value set by token * initialization or manufacturing, or the PIN has been * expired by the card. */ #define CKF_SO_PIN_TO_BE_CHANGED 0x00800000UL #define CKF_ERROR_STATE 0x01000000UL typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR; /* CK_SESSION_HANDLE is a Cryptoki-assigned value that * identifies a session */ typedef CK_ULONG CK_SESSION_HANDLE; typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR; /* CK_USER_TYPE enumerates the types of Cryptoki users */ typedef CK_ULONG CK_USER_TYPE; /* Security Officer */ #define CKU_SO 0UL /* Normal user */ #define CKU_USER 1UL /* Context specific */ #define CKU_CONTEXT_SPECIFIC 2UL /* CK_STATE enumerates the session states */ typedef CK_ULONG CK_STATE; #define CKS_RO_PUBLIC_SESSION 0UL #define CKS_RO_USER_FUNCTIONS 1UL #define CKS_RW_PUBLIC_SESSION 2UL #define CKS_RW_USER_FUNCTIONS 3UL #define CKS_RW_SO_FUNCTIONS 4UL /* CK_SESSION_INFO provides information about a session */ typedef struct CK_SESSION_INFO { CK_SLOT_ID slotID; CK_STATE state; CK_FLAGS flags; /* see below */ CK_ULONG ulDeviceError; /* device-dependent error code */ } CK_SESSION_INFO; /* The flags are defined in the following table: * Bit Flag Mask Meaning */ #define CKF_RW_SESSION 0x00000002UL /* session is r/w */ #define CKF_SERIAL_SESSION 0x00000004UL /* no parallel */ typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR; /* CK_OBJECT_HANDLE is a token-specific identifier for an * object */ typedef CK_ULONG CK_OBJECT_HANDLE; typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR; /* CK_OBJECT_CLASS is a value that identifies the classes (or * types) of objects that Cryptoki recognizes. It is defined * as follows: */ typedef CK_ULONG CK_OBJECT_CLASS; /* The following classes of objects are defined: */ #define CKO_DATA 0x00000000UL #define CKO_CERTIFICATE 0x00000001UL #define CKO_PUBLIC_KEY 0x00000002UL #define CKO_PRIVATE_KEY 0x00000003UL #define CKO_SECRET_KEY 0x00000004UL #define CKO_HW_FEATURE 0x00000005UL #define CKO_DOMAIN_PARAMETERS 0x00000006UL #define CKO_MECHANISM 0x00000007UL #define CKO_OTP_KEY 0x00000008UL #define CKO_PROFILE 0x00000009UL #define CKO_VENDOR_DEFINED 0x80000000UL typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR; /* Profile ID's */ #define CKP_INVALID_ID 0x00000000UL #define CKP_BASELINE_PROVIDER 0x00000001UL #define CKP_EXTENDED_PROVIDER 0x00000002UL #define CKP_AUTHENTICATION_TOKEN 0x00000003UL #define CKP_PUBLIC_CERTIFICATES_TOKEN 0x00000004UL #define CKP_COMPLETE_PROVIDER 0x00000005UL #define CKP_HKDF_TLS_TOKEN 0x00000006UL #define CKP_VENDOR_DEFINED 0x80000000UL /* CK_HW_FEATURE_TYPE is a value that identifies the hardware feature type * of an object with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */ typedef CK_ULONG CK_HW_FEATURE_TYPE; /* The following hardware feature types are defined */ #define CKH_MONOTONIC_COUNTER 0x00000001UL #define CKH_CLOCK 0x00000002UL #define CKH_USER_INTERFACE 0x00000003UL #define CKH_VENDOR_DEFINED 0x80000000UL /* CK_KEY_TYPE is a value that identifies a key type */ typedef CK_ULONG CK_KEY_TYPE; /* the following key types are defined: */ #define CKK_RSA 0x00000000UL #define CKK_DSA 0x00000001UL #define CKK_DH 0x00000002UL #define CKK_ECDSA 0x00000003UL /* Deprecated */ #define CKK_EC 0x00000003UL #define CKK_X9_42_DH 0x00000004UL #define CKK_KEA 0x00000005UL #define CKK_GENERIC_SECRET 0x00000010UL #define CKK_RC2 0x00000011UL #define CKK_RC4 0x00000012UL #define CKK_DES 0x00000013UL #define CKK_DES2 0x00000014UL #define CKK_DES3 0x00000015UL #define CKK_CAST 0x00000016UL #define CKK_CAST3 0x00000017UL #define CKK_CAST5 0x00000018UL /* Deprecated */ #define CKK_CAST128 0x00000018UL #define CKK_RC5 0x00000019UL #define CKK_IDEA 0x0000001AUL #define CKK_SKIPJACK 0x0000001BUL #define CKK_BATON 0x0000001CUL #define CKK_JUNIPER 0x0000001DUL #define CKK_CDMF 0x0000001EUL #define CKK_AES 0x0000001FUL #define CKK_BLOWFISH 0x00000020UL #define CKK_TWOFISH 0x00000021UL #define CKK_SECURID 0x00000022UL #define CKK_HOTP 0x00000023UL #define CKK_ACTI 0x00000024UL #define CKK_CAMELLIA 0x00000025UL #define CKK_ARIA 0x00000026UL /* the following definitions were added in the 2.30 header file, * but never defined in the spec. */ #define CKK_MD5_HMAC 0x00000027UL #define CKK_SHA_1_HMAC 0x00000028UL #define CKK_RIPEMD128_HMAC 0x00000029UL #define CKK_RIPEMD160_HMAC 0x0000002AUL #define CKK_SHA256_HMAC 0x0000002BUL #define CKK_SHA384_HMAC 0x0000002CUL #define CKK_SHA512_HMAC 0x0000002DUL #define CKK_SHA224_HMAC 0x0000002EUL #define CKK_SEED 0x0000002FUL #define CKK_GOSTR3410 0x00000030UL #define CKK_GOSTR3411 0x00000031UL #define CKK_GOST28147 0x00000032UL #define CKK_CHACHA20 0x00000033UL #define CKK_POLY1305 0x00000034UL #define CKK_AES_XTS 0x00000035UL #define CKK_SHA3_224_HMAC 0x00000036UL #define CKK_SHA3_256_HMAC 0x00000037UL #define CKK_SHA3_384_HMAC 0x00000038UL #define CKK_SHA3_512_HMAC 0x00000039UL #define CKK_BLAKE2B_160_HMAC 0x0000003aUL #define CKK_BLAKE2B_256_HMAC 0x0000003bUL #define CKK_BLAKE2B_384_HMAC 0x0000003cUL #define CKK_BLAKE2B_512_HMAC 0x0000003dUL #define CKK_SALSA20 0x0000003eUL #define CKK_X2RATCHET 0x0000003fUL #define CKK_EC_EDWARDS 0x00000040UL #define CKK_EC_MONTGOMERY 0x00000041UL #define CKK_HKDF 0x00000042UL #define CKK_SHA512_224_HMAC 0x00000043UL #define CKK_SHA512_256_HMAC 0x00000044UL #define CKK_SHA512_T_HMAC 0x00000045UL #define CKK_HSS 0x00000046UL #define CKK_VENDOR_DEFINED 0x80000000UL /* CK_CERTIFICATE_TYPE is a value that identifies a certificate * type */ typedef CK_ULONG CK_CERTIFICATE_TYPE; #define CK_CERTIFICATE_CATEGORY_UNSPECIFIED 0UL #define CK_CERTIFICATE_CATEGORY_TOKEN_USER 1UL #define CK_CERTIFICATE_CATEGORY_AUTHORITY 2UL #define CK_CERTIFICATE_CATEGORY_OTHER_ENTITY 3UL #define CK_SECURITY_DOMAIN_UNSPECIFIED 0UL #define CK_SECURITY_DOMAIN_MANUFACTURER 1UL #define CK_SECURITY_DOMAIN_OPERATOR 2UL #define CK_SECURITY_DOMAIN_THIRD_PARTY 3UL /* The following certificate types are defined: */ #define CKC_X_509 0x00000000UL #define CKC_X_509_ATTR_CERT 0x00000001UL #define CKC_WTLS 0x00000002UL #define CKC_VENDOR_DEFINED 0x80000000UL /* CK_ATTRIBUTE_TYPE is a value that identifies an attribute * type */ typedef CK_ULONG CK_ATTRIBUTE_TYPE; /* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which * consists of an array of values. */ #define CKF_ARRAY_ATTRIBUTE 0x40000000UL /* The following OTP-related defines relate to the CKA_OTP_FORMAT attribute */ #define CK_OTP_FORMAT_DECIMAL 0UL #define CK_OTP_FORMAT_HEXADECIMAL 1UL #define CK_OTP_FORMAT_ALPHANUMERIC 2UL #define CK_OTP_FORMAT_BINARY 3UL /* The following OTP-related defines relate to the CKA_OTP_..._REQUIREMENT * attributes */ #define CK_OTP_PARAM_IGNORED 0UL #define CK_OTP_PARAM_OPTIONAL 1UL #define CK_OTP_PARAM_MANDATORY 2UL /* The following attribute types are defined: */ #define CKA_CLASS 0x00000000UL #define CKA_TOKEN 0x00000001UL #define CKA_PRIVATE 0x00000002UL #define CKA_LABEL 0x00000003UL #define CKA_UNIQUE_ID 0x00000004UL #define CKA_APPLICATION 0x00000010UL #define CKA_VALUE 0x00000011UL #define CKA_OBJECT_ID 0x00000012UL #define CKA_CERTIFICATE_TYPE 0x00000080UL #define CKA_ISSUER 0x00000081UL #define CKA_SERIAL_NUMBER 0x00000082UL #define CKA_AC_ISSUER 0x00000083UL #define CKA_OWNER 0x00000084UL #define CKA_ATTR_TYPES 0x00000085UL #define CKA_TRUSTED 0x00000086UL #define CKA_CERTIFICATE_CATEGORY 0x00000087UL #define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088UL #define CKA_URL 0x00000089UL #define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008aUL #define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008bUL #define CKA_NAME_HASH_ALGORITHM 0x0000008cUL #define CKA_CHECK_VALUE 0x00000090UL #define CKA_KEY_TYPE 0x00000100UL #define CKA_SUBJECT 0x00000101UL #define CKA_ID 0x00000102UL #define CKA_SENSITIVE 0x00000103UL #define CKA_ENCRYPT 0x00000104UL #define CKA_DECRYPT 0x00000105UL #define CKA_WRAP 0x00000106UL #define CKA_UNWRAP 0x00000107UL #define CKA_SIGN 0x00000108UL #define CKA_SIGN_RECOVER 0x00000109UL #define CKA_VERIFY 0x0000010aUL #define CKA_VERIFY_RECOVER 0x0000010bUL #define CKA_DERIVE 0x0000010cUL #define CKA_START_DATE 0x00000110UL #define CKA_END_DATE 0x00000111UL #define CKA_MODULUS 0x00000120UL #define CKA_MODULUS_BITS 0x00000121UL #define CKA_PUBLIC_EXPONENT 0x00000122UL #define CKA_PRIVATE_EXPONENT 0x00000123UL #define CKA_PRIME_1 0x00000124UL #define CKA_PRIME_2 0x00000125UL #define CKA_EXPONENT_1 0x00000126UL #define CKA_EXPONENT_2 0x00000127UL #define CKA_COEFFICIENT 0x00000128UL #define CKA_PUBLIC_KEY_INFO 0x00000129UL #define CKA_PRIME 0x00000130UL #define CKA_SUBPRIME 0x00000131UL #define CKA_BASE 0x00000132UL #define CKA_PRIME_BITS 0x00000133UL #define CKA_SUBPRIME_BITS 0x00000134UL #define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS #define CKA_VALUE_BITS 0x00000160UL #define CKA_VALUE_LEN 0x00000161UL #define CKA_EXTRACTABLE 0x00000162UL #define CKA_LOCAL 0x00000163UL #define CKA_NEVER_EXTRACTABLE 0x00000164UL #define CKA_ALWAYS_SENSITIVE 0x00000165UL #define CKA_KEY_GEN_MECHANISM 0x00000166UL #define CKA_MODIFIABLE 0x00000170UL #define CKA_COPYABLE 0x00000171UL #define CKA_DESTROYABLE 0x00000172UL #define CKA_ECDSA_PARAMS 0x00000180UL /* Deprecated */ #define CKA_EC_PARAMS 0x00000180UL #define CKA_EC_POINT 0x00000181UL #define CKA_SECONDARY_AUTH 0x00000200UL /* Deprecated */ #define CKA_AUTH_PIN_FLAGS 0x00000201UL /* Deprecated */ #define CKA_ALWAYS_AUTHENTICATE 0x00000202UL #define CKA_WRAP_WITH_TRUSTED 0x00000210UL #define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x00000211UL) #define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x00000212UL) #define CKA_DERIVE_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x00000213UL) #define CKA_OTP_FORMAT 0x00000220UL #define CKA_OTP_LENGTH 0x00000221UL #define CKA_OTP_TIME_INTERVAL 0x00000222UL #define CKA_OTP_USER_FRIENDLY_MODE 0x00000223UL #define CKA_OTP_CHALLENGE_REQUIREMENT 0x00000224UL #define CKA_OTP_TIME_REQUIREMENT 0x00000225UL #define CKA_OTP_COUNTER_REQUIREMENT 0x00000226UL #define CKA_OTP_PIN_REQUIREMENT 0x00000227UL #define CKA_OTP_COUNTER 0x0000022eUL #define CKA_OTP_TIME 0x0000022fUL #define CKA_OTP_USER_IDENTIFIER 0x0000022aUL #define CKA_OTP_SERVICE_IDENTIFIER 0x0000022bUL #define CKA_OTP_SERVICE_LOGO 0x0000022cUL #define CKA_OTP_SERVICE_LOGO_TYPE 0x0000022dUL #define CKA_GOSTR3410_PARAMS 0x00000250UL #define CKA_GOSTR3411_PARAMS 0x00000251UL #define CKA_GOST28147_PARAMS 0x00000252UL #define CKA_HW_FEATURE_TYPE 0x00000300UL #define CKA_RESET_ON_INIT 0x00000301UL #define CKA_HAS_RESET 0x00000302UL #define CKA_PIXEL_X 0x00000400UL #define CKA_PIXEL_Y 0x00000401UL #define CKA_RESOLUTION 0x00000402UL #define CKA_CHAR_ROWS 0x00000403UL #define CKA_CHAR_COLUMNS 0x00000404UL #define CKA_COLOR 0x00000405UL #define CKA_BITS_PER_PIXEL 0x00000406UL #define CKA_CHAR_SETS 0x00000480UL #define CKA_ENCODING_METHODS 0x00000481UL #define CKA_MIME_TYPES 0x00000482UL #define CKA_MECHANISM_TYPE 0x00000500UL #define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501UL #define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502UL #define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503UL #define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x00000600UL) #define CKA_PROFILE_ID 0x00000601UL #define CKA_X2RATCHET_BAG 0x00000602UL #define CKA_X2RATCHET_BAGSIZE 0x00000603UL #define CKA_X2RATCHET_BOBS1STMSG 0x00000604UL #define CKA_X2RATCHET_CKR 0x00000605UL #define CKA_X2RATCHET_CKS 0x00000606UL #define CKA_X2RATCHET_DHP 0x00000607UL #define CKA_X2RATCHET_DHR 0x00000608UL #define CKA_X2RATCHET_DHS 0x00000609UL #define CKA_X2RATCHET_HKR 0x0000060aUL #define CKA_X2RATCHET_HKS 0x0000060bUL #define CKA_X2RATCHET_ISALICE 0x0000060cUL #define CKA_X2RATCHET_NHKR 0x0000060dUL #define CKA_X2RATCHET_NHKS 0x0000060eUL #define CKA_X2RATCHET_NR 0x0000060fUL #define CKA_X2RATCHET_NS 0x00000610UL #define CKA_X2RATCHET_PNS 0x00000611UL #define CKA_X2RATCHET_RK 0x00000612UL /* HSS */ #define CKA_HSS_LEVELS 0x00000617UL #define CKA_HSS_LMS_TYPE 0x00000618UL #define CKA_HSS_LMOTS_TYPE 0x00000619UL #define CKA_HSS_LMS_TYPES 0x0000061aUL #define CKA_HSS_LMOTS_TYPES 0x0000061bUL #define CKA_HSS_KEYS_REMAINING 0x0000061cUL #define CKA_VENDOR_DEFINED 0x80000000UL /* CK_ATTRIBUTE is a structure that includes the type, length * and value of an attribute */ typedef struct CK_ATTRIBUTE { CK_ATTRIBUTE_TYPE type; CK_VOID_PTR pValue; CK_ULONG ulValueLen; /* in bytes */ } CK_ATTRIBUTE; typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR; /* CK_DATE is a structure that defines a date */ typedef struct CK_DATE { CK_CHAR year[4]; /* the year ("1900" - "9999") */ CK_CHAR month[2]; /* the month ("01" - "12") */ CK_CHAR day[2]; /* the day ("01" - "31") */ } CK_DATE; /* CK_MECHANISM_TYPE is a value that identifies a mechanism * type */ typedef CK_ULONG CK_MECHANISM_TYPE; /* the following mechanism types are defined: */ #define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000UL #define CKM_RSA_PKCS 0x00000001UL #define CKM_RSA_9796 0x00000002UL #define CKM_RSA_X_509 0x00000003UL #define CKM_MD2_RSA_PKCS 0x00000004UL #define CKM_MD5_RSA_PKCS 0x00000005UL #define CKM_SHA1_RSA_PKCS 0x00000006UL #define CKM_RIPEMD128_RSA_PKCS 0x00000007UL #define CKM_RIPEMD160_RSA_PKCS 0x00000008UL #define CKM_RSA_PKCS_OAEP 0x00000009UL #define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000aUL #define CKM_RSA_X9_31 0x0000000bUL #define CKM_SHA1_RSA_X9_31 0x0000000cUL #define CKM_RSA_PKCS_PSS 0x0000000dUL #define CKM_SHA1_RSA_PKCS_PSS 0x0000000eUL #define CKM_DSA_KEY_PAIR_GEN 0x00000010UL #define CKM_DSA 0x00000011UL #define CKM_DSA_SHA1 0x00000012UL #define CKM_DSA_SHA224 0x00000013UL #define CKM_DSA_SHA256 0x00000014UL #define CKM_DSA_SHA384 0x00000015UL #define CKM_DSA_SHA512 0x00000016UL #define CKM_DSA_SHA3_224 0x00000018UL #define CKM_DSA_SHA3_256 0x00000019UL #define CKM_DSA_SHA3_384 0x0000001aUL #define CKM_DSA_SHA3_512 0x0000001bUL #define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020UL #define CKM_DH_PKCS_DERIVE 0x00000021UL #define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030UL #define CKM_X9_42_DH_DERIVE 0x00000031UL #define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032UL #define CKM_X9_42_MQV_DERIVE 0x00000033UL #define CKM_SHA256_RSA_PKCS 0x00000040UL #define CKM_SHA384_RSA_PKCS 0x00000041UL #define CKM_SHA512_RSA_PKCS 0x00000042UL #define CKM_SHA256_RSA_PKCS_PSS 0x00000043UL #define CKM_SHA384_RSA_PKCS_PSS 0x00000044UL #define CKM_SHA512_RSA_PKCS_PSS 0x00000045UL #define CKM_SHA224_RSA_PKCS 0x00000046UL #define CKM_SHA224_RSA_PKCS_PSS 0x00000047UL #define CKM_SHA512_224 0x00000048UL #define CKM_SHA512_224_HMAC 0x00000049UL #define CKM_SHA512_224_HMAC_GENERAL 0x0000004aUL #define CKM_SHA512_224_KEY_DERIVATION 0x0000004bUL #define CKM_SHA512_256 0x0000004cUL #define CKM_SHA512_256_HMAC 0x0000004dUL #define CKM_SHA512_256_HMAC_GENERAL 0x0000004eUL #define CKM_SHA512_256_KEY_DERIVATION 0x0000004fUL #define CKM_SHA512_T 0x00000050UL #define CKM_SHA512_T_HMAC 0x00000051UL #define CKM_SHA512_T_HMAC_GENERAL 0x00000052UL #define CKM_SHA512_T_KEY_DERIVATION 0x00000053UL #define CKM_SHA3_256_RSA_PKCS 0x00000060UL #define CKM_SHA3_384_RSA_PKCS 0x00000061UL #define CKM_SHA3_512_RSA_PKCS 0x00000062UL #define CKM_SHA3_256_RSA_PKCS_PSS 0x00000063UL #define CKM_SHA3_384_RSA_PKCS_PSS 0x00000064UL #define CKM_SHA3_512_RSA_PKCS_PSS 0x00000065UL #define CKM_SHA3_224_RSA_PKCS 0x00000066UL #define CKM_SHA3_224_RSA_PKCS_PSS 0x00000067UL #define CKM_RC2_KEY_GEN 0x00000100UL #define CKM_RC2_ECB 0x00000101UL #define CKM_RC2_CBC 0x00000102UL #define CKM_RC2_MAC 0x00000103UL #define CKM_RC2_MAC_GENERAL 0x00000104UL #define CKM_RC2_CBC_PAD 0x00000105UL #define CKM_RC4_KEY_GEN 0x00000110UL #define CKM_RC4 0x00000111UL #define CKM_DES_KEY_GEN 0x00000120UL #define CKM_DES_ECB 0x00000121UL #define CKM_DES_CBC 0x00000122UL #define CKM_DES_MAC 0x00000123UL #define CKM_DES_MAC_GENERAL 0x00000124UL #define CKM_DES_CBC_PAD 0x00000125UL #define CKM_DES2_KEY_GEN 0x00000130UL #define CKM_DES3_KEY_GEN 0x00000131UL #define CKM_DES3_ECB 0x00000132UL #define CKM_DES3_CBC 0x00000133UL #define CKM_DES3_MAC 0x00000134UL #define CKM_DES3_MAC_GENERAL 0x00000135UL #define CKM_DES3_CBC_PAD 0x00000136UL #define CKM_DES3_CMAC_GENERAL 0x00000137UL #define CKM_DES3_CMAC 0x00000138UL #define CKM_CDMF_KEY_GEN 0x00000140UL #define CKM_CDMF_ECB 0x00000141UL #define CKM_CDMF_CBC 0x00000142UL #define CKM_CDMF_MAC 0x00000143UL #define CKM_CDMF_MAC_GENERAL 0x00000144UL #define CKM_CDMF_CBC_PAD 0x00000145UL #define CKM_DES_OFB64 0x00000150UL #define CKM_DES_OFB8 0x00000151UL #define CKM_DES_CFB64 0x00000152UL #define CKM_DES_CFB8 0x00000153UL #define CKM_MD2 0x00000200UL #define CKM_MD2_HMAC 0x00000201UL #define CKM_MD2_HMAC_GENERAL 0x00000202UL #define CKM_MD5 0x00000210UL #define CKM_MD5_HMAC 0x00000211UL #define CKM_MD5_HMAC_GENERAL 0x00000212UL #define CKM_SHA_1 0x00000220UL #define CKM_SHA_1_HMAC 0x00000221UL #define CKM_SHA_1_HMAC_GENERAL 0x00000222UL #define CKM_RIPEMD128 0x00000230UL #define CKM_RIPEMD128_HMAC 0x00000231UL #define CKM_RIPEMD128_HMAC_GENERAL 0x00000232UL #define CKM_RIPEMD160 0x00000240UL #define CKM_RIPEMD160_HMAC 0x00000241UL #define CKM_RIPEMD160_HMAC_GENERAL 0x00000242UL #define CKM_SHA256 0x00000250UL #define CKM_SHA256_HMAC 0x00000251UL #define CKM_SHA256_HMAC_GENERAL 0x00000252UL #define CKM_SHA224 0x00000255UL #define CKM_SHA224_HMAC 0x00000256UL #define CKM_SHA224_HMAC_GENERAL 0x00000257UL #define CKM_SHA384 0x00000260UL #define CKM_SHA384_HMAC 0x00000261UL #define CKM_SHA384_HMAC_GENERAL 0x00000262UL #define CKM_SHA512 0x00000270UL #define CKM_SHA512_HMAC 0x00000271UL #define CKM_SHA512_HMAC_GENERAL 0x00000272UL #define CKM_SECURID_KEY_GEN 0x00000280UL #define CKM_SECURID 0x00000282UL #define CKM_HOTP_KEY_GEN 0x00000290UL #define CKM_HOTP 0x00000291UL #define CKM_ACTI 0x000002a0UL #define CKM_ACTI_KEY_GEN 0x000002a1UL #define CKM_SHA3_256 0x000002b0UL #define CKM_SHA3_256_HMAC 0x000002b1UL #define CKM_SHA3_256_HMAC_GENERAL 0x000002b2UL #define CKM_SHA3_256_KEY_GEN 0x000002b3UL #define CKM_SHA3_224 0x000002b5UL #define CKM_SHA3_224_HMAC 0x000002b6UL #define CKM_SHA3_224_HMAC_GENERAL 0x000002b7UL #define CKM_SHA3_224_KEY_GEN 0x000002b8UL #define CKM_SHA3_384 0x000002c0UL #define CKM_SHA3_384_HMAC 0x000002c1UL #define CKM_SHA3_384_HMAC_GENERAL 0x000002c2UL #define CKM_SHA3_384_KEY_GEN 0x000002c3UL #define CKM_SHA3_512 0x000002d0UL #define CKM_SHA3_512_HMAC 0x000002d1UL #define CKM_SHA3_512_HMAC_GENERAL 0x000002d2UL #define CKM_SHA3_512_KEY_GEN 0x000002d3UL #define CKM_CAST_KEY_GEN 0x00000300UL #define CKM_CAST_ECB 0x00000301UL #define CKM_CAST_CBC 0x00000302UL #define CKM_CAST_MAC 0x00000303UL #define CKM_CAST_MAC_GENERAL 0x00000304UL #define CKM_CAST_CBC_PAD 0x00000305UL #define CKM_CAST3_KEY_GEN 0x00000310UL #define CKM_CAST3_ECB 0x00000311UL #define CKM_CAST3_CBC 0x00000312UL #define CKM_CAST3_MAC 0x00000313UL #define CKM_CAST3_MAC_GENERAL 0x00000314UL #define CKM_CAST3_CBC_PAD 0x00000315UL /* Note that CAST128 and CAST5 are the same algorithm */ #define CKM_CAST5_KEY_GEN 0x00000320UL #define CKM_CAST128_KEY_GEN 0x00000320UL #define CKM_CAST5_ECB 0x00000321UL #define CKM_CAST128_ECB 0x00000321UL #define CKM_CAST5_CBC 0x00000322UL /* Deprecated */ #define CKM_CAST128_CBC 0x00000322UL #define CKM_CAST5_MAC 0x00000323UL /* Deprecated */ #define CKM_CAST128_MAC 0x00000323UL #define CKM_CAST5_MAC_GENERAL 0x00000324UL /* Deprecated */ #define CKM_CAST128_MAC_GENERAL 0x00000324UL #define CKM_CAST5_CBC_PAD 0x00000325UL /* Deprecated */ #define CKM_CAST128_CBC_PAD 0x00000325UL #define CKM_RC5_KEY_GEN 0x00000330UL #define CKM_RC5_ECB 0x00000331UL #define CKM_RC5_CBC 0x00000332UL #define CKM_RC5_MAC 0x00000333UL #define CKM_RC5_MAC_GENERAL 0x00000334UL #define CKM_RC5_CBC_PAD 0x00000335UL #define CKM_IDEA_KEY_GEN 0x00000340UL #define CKM_IDEA_ECB 0x00000341UL #define CKM_IDEA_CBC 0x00000342UL #define CKM_IDEA_MAC 0x00000343UL #define CKM_IDEA_MAC_GENERAL 0x00000344UL #define CKM_IDEA_CBC_PAD 0x00000345UL #define CKM_GENERIC_SECRET_KEY_GEN 0x00000350UL #define CKM_CONCATENATE_BASE_AND_KEY 0x00000360UL #define CKM_CONCATENATE_BASE_AND_DATA 0x00000362UL #define CKM_CONCATENATE_DATA_AND_BASE 0x00000363UL #define CKM_XOR_BASE_AND_DATA 0x00000364UL #define CKM_EXTRACT_KEY_FROM_KEY 0x00000365UL #define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370UL #define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371UL #define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372UL #define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373UL #define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374UL #define CKM_TLS_MASTER_KEY_DERIVE 0x00000375UL #define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376UL #define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377UL #define CKM_TLS_PRF 0x00000378UL #define CKM_SSL3_MD5_MAC 0x00000380UL #define CKM_SSL3_SHA1_MAC 0x00000381UL #define CKM_MD5_KEY_DERIVATION 0x00000390UL #define CKM_MD2_KEY_DERIVATION 0x00000391UL #define CKM_SHA1_KEY_DERIVATION 0x00000392UL #define CKM_SHA256_KEY_DERIVATION 0x00000393UL #define CKM_SHA384_KEY_DERIVATION 0x00000394UL #define CKM_SHA512_KEY_DERIVATION 0x00000395UL #define CKM_SHA224_KEY_DERIVATION 0x00000396UL #define CKM_SHA3_256_KEY_DERIVATION 0x00000397UL #define CKM_SHA3_224_KEY_DERIVATION 0x00000398UL #define CKM_SHA3_384_KEY_DERIVATION 0x00000399UL #define CKM_SHA3_512_KEY_DERIVATION 0x0000039aUL #define CKM_SHAKE_128_KEY_DERIVATION 0x0000039bUL #define CKM_SHAKE_256_KEY_DERIVATION 0x0000039cUL #define CKM_SHA3_256_KEY_DERIVE CKM_SHA3_256_KEY_DERIVATION #define CKM_SHA3_224_KEY_DERIVE CKM_SHA3_224_KEY_DERIVATION #define CKM_SHA3_384_KEY_DERIVE CKM_SHA3_384_KEY_DERIVATION #define CKM_SHA3_512_KEY_DERIVE CKM_SHA3_512_KEY_DERIVATION #define CKM_SHAKE_128_KEY_DERIVE CKM_SHAKE_128_KEY_DERIVATION #define CKM_SHAKE_256_KEY_DERIVE CKM_SHAKE_256_KEY_DERIVATION #define CKM_PBE_MD2_DES_CBC 0x000003a0UL #define CKM_PBE_MD5_DES_CBC 0x000003a1UL #define CKM_PBE_MD5_CAST_CBC 0x000003a2UL #define CKM_PBE_MD5_CAST3_CBC 0x000003a3UL #define CKM_PBE_MD5_CAST5_CBC 0x000003a4UL /* Deprecated */ #define CKM_PBE_MD5_CAST128_CBC 0x000003a4UL #define CKM_PBE_SHA1_CAST5_CBC 0x000003a5UL /* Deprecated */ #define CKM_PBE_SHA1_CAST128_CBC 0x000003a5UL #define CKM_PBE_SHA1_RC4_128 0x000003a6UL #define CKM_PBE_SHA1_RC4_40 0x000003a7UL #define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003a8UL #define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003a9UL #define CKM_PBE_SHA1_RC2_128_CBC 0x000003aaUL #define CKM_PBE_SHA1_RC2_40_CBC 0x000003abUL #define CKM_PKCS5_PBKD2 0x000003b0UL #define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003c0UL #define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003d0UL #define CKM_WTLS_MASTER_KEY_DERIVE 0x000003d1UL #define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003d2UL #define CKM_WTLS_PRF 0x000003d3UL #define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003d4UL #define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003d5UL #define CKM_TLS10_MAC_SERVER 0x000003d6UL #define CKM_TLS10_MAC_CLIENT 0x000003d7UL #define CKM_TLS12_MAC 0x000003d8UL #define CKM_TLS12_KDF 0x000003d9UL #define CKM_TLS12_MASTER_KEY_DERIVE 0x000003e0UL #define CKM_TLS12_KEY_AND_MAC_DERIVE 0x000003e1UL #define CKM_TLS12_MASTER_KEY_DERIVE_DH 0x000003e2UL #define CKM_TLS12_KEY_SAFE_DERIVE 0x000003e3UL #define CKM_TLS_MAC 0x000003e4UL #define CKM_TLS_KDF 0x000003e5UL #define CKM_KEY_WRAP_LYNKS 0x00000400UL #define CKM_KEY_WRAP_SET_OAEP 0x00000401UL #define CKM_CMS_SIG 0x00000500UL #define CKM_KIP_DERIVE 0x00000510UL #define CKM_KIP_WRAP 0x00000511UL #define CKM_KIP_MAC 0x00000512UL #define CKM_CAMELLIA_KEY_GEN 0x00000550UL #define CKM_CAMELLIA_ECB 0x00000551UL #define CKM_CAMELLIA_CBC 0x00000552UL #define CKM_CAMELLIA_MAC 0x00000553UL #define CKM_CAMELLIA_MAC_GENERAL 0x00000554UL #define CKM_CAMELLIA_CBC_PAD 0x00000555UL #define CKM_CAMELLIA_ECB_ENCRYPT_DATA 0x00000556UL #define CKM_CAMELLIA_CBC_ENCRYPT_DATA 0x00000557UL #define CKM_CAMELLIA_CTR 0x00000558UL #define CKM_ARIA_KEY_GEN 0x00000560UL #define CKM_ARIA_ECB 0x00000561UL #define CKM_ARIA_CBC 0x00000562UL #define CKM_ARIA_MAC 0x00000563UL #define CKM_ARIA_MAC_GENERAL 0x00000564UL #define CKM_ARIA_CBC_PAD 0x00000565UL #define CKM_ARIA_ECB_ENCRYPT_DATA 0x00000566UL #define CKM_ARIA_CBC_ENCRYPT_DATA 0x00000567UL #define CKM_SEED_KEY_GEN 0x00000650UL #define CKM_SEED_ECB 0x00000651UL #define CKM_SEED_CBC 0x00000652UL #define CKM_SEED_MAC 0x00000653UL #define CKM_SEED_MAC_GENERAL 0x00000654UL #define CKM_SEED_CBC_PAD 0x00000655UL #define CKM_SEED_ECB_ENCRYPT_DATA 0x00000656UL #define CKM_SEED_CBC_ENCRYPT_DATA 0x00000657UL #define CKM_SKIPJACK_KEY_GEN 0x00001000UL #define CKM_SKIPJACK_ECB64 0x00001001UL #define CKM_SKIPJACK_CBC64 0x00001002UL #define CKM_SKIPJACK_OFB64 0x00001003UL #define CKM_SKIPJACK_CFB64 0x00001004UL #define CKM_SKIPJACK_CFB32 0x00001005UL #define CKM_SKIPJACK_CFB16 0x00001006UL #define CKM_SKIPJACK_CFB8 0x00001007UL #define CKM_SKIPJACK_WRAP 0x00001008UL #define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009UL #define CKM_SKIPJACK_RELAYX 0x0000100aUL #define CKM_KEA_KEY_PAIR_GEN 0x00001010UL #define CKM_KEA_KEY_DERIVE 0x00001011UL #define CKM_KEA_DERIVE 0x00001012UL #define CKM_FORTEZZA_TIMESTAMP 0x00001020UL #define CKM_BATON_KEY_GEN 0x00001030UL #define CKM_BATON_ECB128 0x00001031UL #define CKM_BATON_ECB96 0x00001032UL #define CKM_BATON_CBC128 0x00001033UL #define CKM_BATON_COUNTER 0x00001034UL #define CKM_BATON_SHUFFLE 0x00001035UL #define CKM_BATON_WRAP 0x00001036UL #define CKM_ECDSA_KEY_PAIR_GEN 0x00001040UL /* Deprecated */ #define CKM_EC_KEY_PAIR_GEN 0x00001040UL #define CKM_ECDSA 0x00001041UL #define CKM_ECDSA_SHA1 0x00001042UL #define CKM_ECDSA_SHA224 0x00001043UL #define CKM_ECDSA_SHA256 0x00001044UL #define CKM_ECDSA_SHA384 0x00001045UL #define CKM_ECDSA_SHA512 0x00001046UL #define CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS 0x0000140bUL #define CKM_ECDH1_DERIVE 0x00001050UL #define CKM_ECDH1_COFACTOR_DERIVE 0x00001051UL #define CKM_ECMQV_DERIVE 0x00001052UL #define CKM_ECDH_AES_KEY_WRAP 0x00001053UL #define CKM_RSA_AES_KEY_WRAP 0x00001054UL #define CKM_JUNIPER_KEY_GEN 0x00001060UL #define CKM_JUNIPER_ECB128 0x00001061UL #define CKM_JUNIPER_CBC128 0x00001062UL #define CKM_JUNIPER_COUNTER 0x00001063UL #define CKM_JUNIPER_SHUFFLE 0x00001064UL #define CKM_JUNIPER_WRAP 0x00001065UL #define CKM_FASTHASH 0x00001070UL #define CKM_AES_XTS 0x00001071UL #define CKM_AES_XTS_KEY_GEN 0x00001072UL #define CKM_AES_KEY_GEN 0x00001080UL #define CKM_AES_ECB 0x00001081UL #define CKM_AES_CBC 0x00001082UL #define CKM_AES_MAC 0x00001083UL #define CKM_AES_MAC_GENERAL 0x00001084UL #define CKM_AES_CBC_PAD 0x00001085UL #define CKM_AES_CTR 0x00001086UL #define CKM_AES_GCM 0x00001087UL #define CKM_AES_CCM 0x00001088UL #define CKM_AES_CTS 0x00001089UL #define CKM_AES_CMAC 0x0000108aUL #define CKM_AES_CMAC_GENERAL 0x0000108bUL #define CKM_AES_XCBC_MAC 0x0000108cUL #define CKM_AES_XCBC_MAC_96 0x0000108dUL #define CKM_AES_GMAC 0x0000108eUL #define CKM_BLOWFISH_KEY_GEN 0x00001090UL #define CKM_BLOWFISH_CBC 0x00001091UL #define CKM_TWOFISH_KEY_GEN 0x00001092UL #define CKM_TWOFISH_CBC 0x00001093UL #define CKM_BLOWFISH_CBC_PAD 0x00001094UL #define CKM_TWOFISH_CBC_PAD 0x00001095UL #define CKM_DES_ECB_ENCRYPT_DATA 0x00001100UL #define CKM_DES_CBC_ENCRYPT_DATA 0x00001101UL #define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102UL #define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103UL #define CKM_AES_ECB_ENCRYPT_DATA 0x00001104UL #define CKM_AES_CBC_ENCRYPT_DATA 0x00001105UL #define CKM_GOSTR3410_KEY_PAIR_GEN 0x00001200UL #define CKM_GOSTR3410 0x00001201UL #define CKM_GOSTR3410_WITH_GOSTR3411 0x00001202UL #define CKM_GOSTR3410_KEY_WRAP 0x00001203UL #define CKM_GOSTR3410_DERIVE 0x00001204UL #define CKM_GOSTR3411 0x00001210UL #define CKM_GOSTR3411_HMAC 0x00001211UL #define CKM_GOST28147_KEY_GEN 0x00001220UL #define CKM_GOST28147_ECB 0x00001221UL #define CKM_GOST28147 0x00001222UL #define CKM_GOST28147_MAC 0x00001223UL #define CKM_GOST28147_KEY_WRAP 0x00001224UL #define CKM_CHACHA20_KEY_GEN 0x00001225UL #define CKM_CHACHA20 0x00001226UL #define CKM_POLY1305_KEY_GEN 0x00001227UL #define CKM_POLY1305 0x00001228UL #define CKM_DSA_PARAMETER_GEN 0x00002000UL #define CKM_DH_PKCS_PARAMETER_GEN 0x00002001UL #define CKM_X9_42_DH_PARAMETER_GEN 0x00002002UL #define CKM_DSA_PROBABILISTIC_PARAMETER_GEN 0x00002003UL #define CKM_DSA_PROBABLISTIC_PARAMETER_GEN CKM_DSA_PROBABILISTIC_PARAMETER_GEN #define CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN 0x00002004UL #define CKM_DSA_FIPS_G_GEN 0x00002005UL #define CKM_AES_OFB 0x00002104UL #define CKM_AES_CFB64 0x00002105UL #define CKM_AES_CFB8 0x00002106UL #define CKM_AES_CFB128 0x00002107UL #define CKM_AES_CFB1 0x00002108UL #define CKM_AES_KEY_WRAP 0x00002109UL /* WAS: 0x00001090 */ #define CKM_AES_KEY_WRAP_PAD 0x0000210AUL /* WAS: 0x00001091 */ #define CKM_AES_KEY_WRAP_KWP 0x0000210BUL #define CKM_AES_KEY_WRAP_PKCS7 0x0000210CUL #define CKM_RSA_PKCS_TPM_1_1 0x00004001UL #define CKM_RSA_PKCS_OAEP_TPM_1_1 0x00004002UL #define CKM_SHA_1_KEY_GEN 0x00004003UL #define CKM_SHA224_KEY_GEN 0x00004004UL #define CKM_SHA256_KEY_GEN 0x00004005UL #define CKM_SHA384_KEY_GEN 0x00004006UL #define CKM_SHA512_KEY_GEN 0x00004007UL #define CKM_SHA512_224_KEY_GEN 0x00004008UL #define CKM_SHA512_256_KEY_GEN 0x00004009UL #define CKM_SHA512_T_KEY_GEN 0x0000400aUL #define CKM_NULL 0x0000400bUL #define CKM_BLAKE2B_160 0x0000400cUL #define CKM_BLAKE2B_160_HMAC 0x0000400dUL #define CKM_BLAKE2B_160_HMAC_GENERAL 0x0000400eUL #define CKM_BLAKE2B_160_KEY_DERIVE 0x0000400fUL #define CKM_BLAKE2B_160_KEY_GEN 0x00004010UL #define CKM_BLAKE2B_256 0x00004011UL #define CKM_BLAKE2B_256_HMAC 0x00004012UL #define CKM_BLAKE2B_256_HMAC_GENERAL 0x00004013UL #define CKM_BLAKE2B_256_KEY_DERIVE 0x00004014UL #define CKM_BLAKE2B_256_KEY_GEN 0x00004015UL #define CKM_BLAKE2B_384 0x00004016UL #define CKM_BLAKE2B_384_HMAC 0x00004017UL #define CKM_BLAKE2B_384_HMAC_GENERAL 0x00004018UL #define CKM_BLAKE2B_384_KEY_DERIVE 0x00004019UL #define CKM_BLAKE2B_384_KEY_GEN 0x0000401aUL #define CKM_BLAKE2B_512 0x0000401bUL #define CKM_BLAKE2B_512_HMAC 0x0000401cUL #define CKM_BLAKE2B_512_HMAC_GENERAL 0x0000401dUL #define CKM_BLAKE2B_512_KEY_DERIVE 0x0000401eUL #define CKM_BLAKE2B_512_KEY_GEN 0x0000401fUL #define CKM_SALSA20 0x00004020UL #define CKM_CHACHA20_POLY1305 0x00004021UL #define CKM_SALSA20_POLY1305 0x00004022UL #define CKM_X3DH_INITIALIZE 0x00004023UL #define CKM_X3DH_RESPOND 0x00004024UL #define CKM_X2RATCHET_INITIALIZE 0x00004025UL #define CKM_X2RATCHET_RESPOND 0x00004026UL #define CKM_X2RATCHET_ENCRYPT 0x00004027UL #define CKM_X2RATCHET_DECRYPT 0x00004028UL #define CKM_XEDDSA 0x00004029UL #define CKM_HKDF_DERIVE 0x0000402aUL #define CKM_HKDF_DATA 0x0000402bUL #define CKM_HKDF_KEY_GEN 0x0000402cUL #define CKM_SALSA20_KEY_GEN 0x0000402dUL #define CKM_ECDSA_SHA3_224 0x00001047UL #define CKM_ECDSA_SHA3_256 0x00001048UL #define CKM_ECDSA_SHA3_384 0x00001049UL #define CKM_ECDSA_SHA3_512 0x0000104aUL #define CKM_EC_EDWARDS_KEY_PAIR_GEN 0x00001055UL #define CKM_EC_MONTGOMERY_KEY_PAIR_GEN 0x00001056UL #define CKM_EDDSA 0x00001057UL #define CKM_SP800_108_COUNTER_KDF 0x000003acUL #define CKM_SP800_108_FEEDBACK_KDF 0x000003adUL #define CKM_SP800_108_DOUBLE_PIPELINE_KDF 0x000003aeUL #define CKM_IKE2_PRF_PLUS_DERIVE 0x0000402eUL #define CKM_IKE_PRF_DERIVE 0x0000402fUL #define CKM_IKE1_PRF_DERIVE 0x00004030UL #define CKM_IKE1_EXTENDED_DERIVE 0x00004031UL #define CKM_HSS_KEY_PAIR_GEN 0x00004032UL #define CKM_HSS 0x00004033UL #define CKM_VENDOR_DEFINED 0x80000000UL typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR; /* CK_MECHANISM is a structure that specifies a particular * mechanism */ typedef struct CK_MECHANISM { CK_MECHANISM_TYPE mechanism; CK_VOID_PTR pParameter; CK_ULONG ulParameterLen; /* in bytes */ } CK_MECHANISM; typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR; /* CK_MECHANISM_INFO provides information about a particular * mechanism */ typedef struct CK_MECHANISM_INFO { CK_ULONG ulMinKeySize; CK_ULONG ulMaxKeySize; CK_FLAGS flags; } CK_MECHANISM_INFO; /* The flags are defined as follows: * Bit Flag Mask Meaning */ #define CKF_HW 0x00000001UL /* performed by HW */ /* Specify whether or not a mechanism can be used for a particular task */ #define CKF_MESSAGE_ENCRYPT 0x00000002UL #define CKF_MESSAGE_DECRYPT 0x00000004UL #define CKF_MESSAGE_SIGN 0x00000008UL #define CKF_MESSAGE_VERIFY 0x00000010UL #define CKF_MULTI_MESSAGE 0x00000020UL #define CKF_MULTI_MESSGE CKF_MULTI_MESSAGE #define CKF_FIND_OBJECTS 0x00000040UL #define CKF_ENCRYPT 0x00000100UL #define CKF_DECRYPT 0x00000200UL #define CKF_DIGEST 0x00000400UL #define CKF_SIGN 0x00000800UL #define CKF_SIGN_RECOVER 0x00001000UL #define CKF_VERIFY 0x00002000UL #define CKF_VERIFY_RECOVER 0x00004000UL #define CKF_GENERATE 0x00008000UL #define CKF_GENERATE_KEY_PAIR 0x00010000UL #define CKF_WRAP 0x00020000UL #define CKF_UNWRAP 0x00040000UL #define CKF_DERIVE 0x00080000UL /* Describe a token's EC capabilities not available in mechanism * information. */ #define CKF_EC_F_P 0x00100000UL #define CKF_EC_F_2M 0x00200000UL #define CKF_EC_ECPARAMETERS 0x00400000UL #define CKF_EC_OID 0x00800000UL #define CKF_EC_NAMEDCURVE CKF_EC_OID /* deprecated since PKCS#11 3.00 */ #define CKF_EC_UNCOMPRESS 0x01000000UL #define CKF_EC_COMPRESS 0x02000000UL #define CKF_EC_CURVENAME 0x04000000UL #define CKF_EXTENSION 0x80000000UL typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR; /* CK_RV is a value that identifies the return value of a * Cryptoki function */ typedef CK_ULONG CK_RV; #define CKR_OK 0x00000000UL #define CKR_CANCEL 0x00000001UL #define CKR_HOST_MEMORY 0x00000002UL #define CKR_SLOT_ID_INVALID 0x00000003UL #define CKR_GENERAL_ERROR 0x00000005UL #define CKR_FUNCTION_FAILED 0x00000006UL #define CKR_ARGUMENTS_BAD 0x00000007UL #define CKR_NO_EVENT 0x00000008UL #define CKR_NEED_TO_CREATE_THREADS 0x00000009UL #define CKR_CANT_LOCK 0x0000000AUL #define CKR_ATTRIBUTE_READ_ONLY 0x00000010UL #define CKR_ATTRIBUTE_SENSITIVE 0x00000011UL #define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012UL #define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013UL #define CKR_ACTION_PROHIBITED 0x0000001BUL #define CKR_DATA_INVALID 0x00000020UL #define CKR_DATA_LEN_RANGE 0x00000021UL #define CKR_DEVICE_ERROR 0x00000030UL #define CKR_DEVICE_MEMORY 0x00000031UL #define CKR_DEVICE_REMOVED 0x00000032UL #define CKR_ENCRYPTED_DATA_INVALID 0x00000040UL #define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041UL #define CKR_AEAD_DECRYPT_FAILED 0x00000042UL #define CKR_FUNCTION_CANCELED 0x00000050UL #define CKR_FUNCTION_NOT_PARALLEL 0x00000051UL #define CKR_FUNCTION_NOT_SUPPORTED 0x00000054UL #define CKR_KEY_HANDLE_INVALID 0x00000060UL #define CKR_KEY_SIZE_RANGE 0x00000062UL #define CKR_KEY_TYPE_INCONSISTENT 0x00000063UL #define CKR_KEY_NOT_NEEDED 0x00000064UL #define CKR_KEY_CHANGED 0x00000065UL #define CKR_KEY_NEEDED 0x00000066UL #define CKR_KEY_INDIGESTIBLE 0x00000067UL #define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068UL #define CKR_KEY_NOT_WRAPPABLE 0x00000069UL #define CKR_KEY_UNEXTRACTABLE 0x0000006AUL #define CKR_MECHANISM_INVALID 0x00000070UL #define CKR_MECHANISM_PARAM_INVALID 0x00000071UL #define CKR_OBJECT_HANDLE_INVALID 0x00000082UL #define CKR_OPERATION_ACTIVE 0x00000090UL #define CKR_OPERATION_NOT_INITIALIZED 0x00000091UL #define CKR_PIN_INCORRECT 0x000000A0UL #define CKR_PIN_INVALID 0x000000A1UL #define CKR_PIN_LEN_RANGE 0x000000A2UL #define CKR_PIN_EXPIRED 0x000000A3UL #define CKR_PIN_LOCKED 0x000000A4UL #define CKR_SESSION_CLOSED 0x000000B0UL #define CKR_SESSION_COUNT 0x000000B1UL #define CKR_SESSION_HANDLE_INVALID 0x000000B3UL #define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4UL #define CKR_SESSION_READ_ONLY 0x000000B5UL #define CKR_SESSION_EXISTS 0x000000B6UL #define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7UL #define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8UL #define CKR_SIGNATURE_INVALID 0x000000C0UL #define CKR_SIGNATURE_LEN_RANGE 0x000000C1UL #define CKR_TEMPLATE_INCOMPLETE 0x000000D0UL #define CKR_TEMPLATE_INCONSISTENT 0x000000D1UL #define CKR_TOKEN_NOT_PRESENT 0x000000E0UL #define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1UL #define CKR_TOKEN_WRITE_PROTECTED 0x000000E2UL #define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0UL #define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1UL #define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2UL #define CKR_USER_ALREADY_LOGGED_IN 0x00000100UL #define CKR_USER_NOT_LOGGED_IN 0x00000101UL #define CKR_USER_PIN_NOT_INITIALIZED 0x00000102UL #define CKR_USER_TYPE_INVALID 0x00000103UL #define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104UL #define CKR_USER_TOO_MANY_TYPES 0x00000105UL #define CKR_WRAPPED_KEY_INVALID 0x00000110UL #define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112UL #define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113UL #define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114UL #define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115UL #define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120UL #define CKR_RANDOM_NO_RNG 0x00000121UL #define CKR_DOMAIN_PARAMS_INVALID 0x00000130UL #define CKR_CURVE_NOT_SUPPORTED 0x00000140UL #define CKR_BUFFER_TOO_SMALL 0x00000150UL #define CKR_SAVED_STATE_INVALID 0x00000160UL #define CKR_INFORMATION_SENSITIVE 0x00000170UL #define CKR_STATE_UNSAVEABLE 0x00000180UL #define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190UL #define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191UL #define CKR_MUTEX_BAD 0x000001A0UL #define CKR_MUTEX_NOT_LOCKED 0x000001A1UL #define CKR_NEW_PIN_MODE 0x000001B0UL #define CKR_NEXT_OTP 0x000001B1UL #define CKR_EXCEEDED_MAX_ITERATIONS 0x000001B5UL #define CKR_FIPS_SELF_TEST_FAILED 0x000001B6UL #define CKR_LIBRARY_LOAD_FAILED 0x000001B7UL #define CKR_PIN_TOO_WEAK 0x000001B8UL #define CKR_PUBLIC_KEY_INVALID 0x000001B9UL #define CKR_FUNCTION_REJECTED 0x00000200UL #define CKR_TOKEN_RESOURCE_EXCEEDED 0x00000201UL #define CKR_OPERATION_CANCEL_FAILED 0x00000202UL #define CKR_KEY_EXHAUSTED 0x00000203UL #define CKR_VENDOR_DEFINED 0x80000000UL /* CK_NOTIFY is an application callback that processes events */ typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)( CK_SESSION_HANDLE hSession, /* the session's handle */ CK_NOTIFICATION event, CK_VOID_PTR pApplication /* passed to C_OpenSession */ ); /* CK_FUNCTION_LIST is a structure holding a Cryptoki spec * version and pointers of appropriate types to all the * Cryptoki functions */ typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST; typedef struct CK_FUNCTION_LIST_3_0 CK_FUNCTION_LIST_3_0; typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR; typedef CK_FUNCTION_LIST_3_0 CK_PTR CK_FUNCTION_LIST_3_0_PTR; typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR; typedef CK_FUNCTION_LIST_3_0_PTR CK_PTR CK_FUNCTION_LIST_3_0_PTR_PTR; typedef struct CK_INTERFACE { CK_CHAR *pInterfaceName; CK_VOID_PTR pFunctionList; CK_FLAGS flags; } CK_INTERFACE; typedef CK_INTERFACE CK_PTR CK_INTERFACE_PTR; typedef CK_INTERFACE_PTR CK_PTR CK_INTERFACE_PTR_PTR; #define CKF_END_OF_MESSAGE 0x00000001UL /* CK_CREATEMUTEX is an application callback for creating a * mutex object */ typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)( CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */ ); /* CK_DESTROYMUTEX is an application callback for destroying a * mutex object */ typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)( CK_VOID_PTR pMutex /* pointer to mutex */ ); /* CK_LOCKMUTEX is an application callback for locking a mutex */ typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)( CK_VOID_PTR pMutex /* pointer to mutex */ ); /* CK_UNLOCKMUTEX is an application callback for unlocking a * mutex */ typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)( CK_VOID_PTR pMutex /* pointer to mutex */ ); /* Get functionlist flags */ #define CKF_INTERFACE_FORK_SAFE 0x00000001UL /* CK_C_INITIALIZE_ARGS provides the optional arguments to * C_Initialize */ typedef struct CK_C_INITIALIZE_ARGS { CK_CREATEMUTEX CreateMutex; CK_DESTROYMUTEX DestroyMutex; CK_LOCKMUTEX LockMutex; CK_UNLOCKMUTEX UnlockMutex; CK_FLAGS flags; CK_VOID_PTR pReserved; } CK_C_INITIALIZE_ARGS; /* flags: bit flags that provide capabilities of the slot * Bit Flag Mask Meaning */ #define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001UL #define CKF_OS_LOCKING_OK 0x00000002UL typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR; /* additional flags for parameters to functions */ /* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */ #define CKF_DONT_BLOCK 1 /* CK_RSA_PKCS_MGF_TYPE is used to indicate the Message * Generation Function (MGF) applied to a message block when * formatting a message block for the PKCS #1 OAEP encryption * scheme. */ typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE; typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR; /* The following MGFs are defined */ #define CKG_MGF1_SHA1 0x00000001UL #define CKG_MGF1_SHA256 0x00000002UL #define CKG_MGF1_SHA384 0x00000003UL #define CKG_MGF1_SHA512 0x00000004UL #define CKG_MGF1_SHA224 0x00000005UL #define CKG_MGF1_SHA3_224 0x00000006UL #define CKG_MGF1_SHA3_256 0x00000007UL #define CKG_MGF1_SHA3_384 0x00000008UL #define CKG_MGF1_SHA3_512 0x00000009UL /* CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source * of the encoding parameter when formatting a message block * for the PKCS #1 OAEP encryption scheme. */ typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE; typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR; /* The following encoding parameter sources are defined */ #define CKZ_DATA_SPECIFIED 0x00000001UL /* CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the * CKM_RSA_PKCS_OAEP mechanism. */ typedef struct CK_RSA_PKCS_OAEP_PARAMS { CK_MECHANISM_TYPE hashAlg; CK_RSA_PKCS_MGF_TYPE mgf; CK_RSA_PKCS_OAEP_SOURCE_TYPE source; CK_VOID_PTR pSourceData; CK_ULONG ulSourceDataLen; } CK_RSA_PKCS_OAEP_PARAMS; typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR; /* CK_RSA_PKCS_PSS_PARAMS provides the parameters to the * CKM_RSA_PKCS_PSS mechanism(s). */ typedef struct CK_RSA_PKCS_PSS_PARAMS { CK_MECHANISM_TYPE hashAlg; CK_RSA_PKCS_MGF_TYPE mgf; CK_ULONG sLen; } CK_RSA_PKCS_PSS_PARAMS; typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR; typedef CK_ULONG CK_EC_KDF_TYPE; typedef CK_EC_KDF_TYPE CK_PTR CK_EC_KDF_TYPE_PTR; /* The following EC Key Derivation Functions are defined */ #define CKD_NULL 0x00000001UL #define CKD_SHA1_KDF 0x00000002UL /* The following X9.42 DH key derivation functions are defined */ #define CKD_SHA1_KDF_ASN1 0x00000003UL #define CKD_SHA1_KDF_CONCATENATE 0x00000004UL #define CKD_SHA224_KDF 0x00000005UL #define CKD_SHA256_KDF 0x00000006UL #define CKD_SHA384_KDF 0x00000007UL #define CKD_SHA512_KDF 0x00000008UL #define CKD_CPDIVERSIFY_KDF 0x00000009UL #define CKD_SHA3_224_KDF 0x0000000AUL #define CKD_SHA3_256_KDF 0x0000000BUL #define CKD_SHA3_384_KDF 0x0000000CUL #define CKD_SHA3_512_KDF 0x0000000DUL #define CKD_SHA1_KDF_SP800 0x0000000EUL #define CKD_SHA224_KDF_SP800 0x0000000FUL #define CKD_SHA256_KDF_SP800 0x00000010UL #define CKD_SHA384_KDF_SP800 0x00000011UL #define CKD_SHA512_KDF_SP800 0x00000012UL #define CKD_SHA3_224_KDF_SP800 0x00000013UL #define CKD_SHA3_256_KDF_SP800 0x00000014UL #define CKD_SHA3_384_KDF_SP800 0x00000015UL #define CKD_SHA3_512_KDF_SP800 0x00000016UL #define CKD_BLAKE2B_160_KDF 0x00000017UL #define CKD_BLAKE2B_256_KDF 0x00000018UL #define CKD_BLAKE2B_384_KDF 0x00000019UL #define CKD_BLAKE2B_512_KDF 0x0000001aUL /* CK_ECDH1_DERIVE_PARAMS provides the parameters to the * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms, * where each party contributes one key pair. */ typedef struct CK_ECDH1_DERIVE_PARAMS { CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE_PTR pSharedData; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; } CK_ECDH1_DERIVE_PARAMS; typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR; /* * CK_ECDH2_DERIVE_PARAMS provides the parameters to the * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */ typedef struct CK_ECDH2_DERIVE_PARAMS { CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE_PTR pSharedData; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; CK_ULONG ulPrivateDataLen; CK_OBJECT_HANDLE hPrivateData; CK_ULONG ulPublicDataLen2; CK_BYTE_PTR pPublicData2; } CK_ECDH2_DERIVE_PARAMS; typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR; typedef struct CK_ECMQV_DERIVE_PARAMS { CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE_PTR pSharedData; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; CK_ULONG ulPrivateDataLen; CK_OBJECT_HANDLE hPrivateData; CK_ULONG ulPublicDataLen2; CK_BYTE_PTR pPublicData2; CK_OBJECT_HANDLE publicKey; } CK_ECMQV_DERIVE_PARAMS; typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR; /* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the * CKM_X9_42_DH_PARAMETER_GEN mechanisms */ typedef CK_ULONG CK_X9_42_DH_KDF_TYPE; typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR; /* CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party * contributes one key pair */ typedef struct CK_X9_42_DH1_DERIVE_PARAMS { CK_X9_42_DH_KDF_TYPE kdf; CK_ULONG ulOtherInfoLen; CK_BYTE_PTR pOtherInfo; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; } CK_X9_42_DH1_DERIVE_PARAMS; typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR; /* CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation * mechanisms, where each party contributes two key pairs */ typedef struct CK_X9_42_DH2_DERIVE_PARAMS { CK_X9_42_DH_KDF_TYPE kdf; CK_ULONG ulOtherInfoLen; CK_BYTE_PTR pOtherInfo; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; CK_ULONG ulPrivateDataLen; CK_OBJECT_HANDLE hPrivateData; CK_ULONG ulPublicDataLen2; CK_BYTE_PTR pPublicData2; } CK_X9_42_DH2_DERIVE_PARAMS; typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR; typedef struct CK_X9_42_MQV_DERIVE_PARAMS { CK_X9_42_DH_KDF_TYPE kdf; CK_ULONG ulOtherInfoLen; CK_BYTE_PTR pOtherInfo; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; CK_ULONG ulPrivateDataLen; CK_OBJECT_HANDLE hPrivateData; CK_ULONG ulPublicDataLen2; CK_BYTE_PTR pPublicData2; CK_OBJECT_HANDLE publicKey; } CK_X9_42_MQV_DERIVE_PARAMS; typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR; /* CK_KEA_DERIVE_PARAMS provides the parameters to the * CKM_KEA_DERIVE mechanism */ typedef struct CK_KEA_DERIVE_PARAMS { CK_BBOOL isSender; CK_ULONG ulRandomLen; CK_BYTE_PTR pRandomA; CK_BYTE_PTR pRandomB; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; } CK_KEA_DERIVE_PARAMS; typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR; /* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just * holds the effective keysize */ typedef CK_ULONG CK_RC2_PARAMS; typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR; /* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC * mechanism */ typedef struct CK_RC2_CBC_PARAMS { CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ CK_BYTE iv[8]; /* IV for CBC mode */ } CK_RC2_CBC_PARAMS; typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR; /* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the * CKM_RC2_MAC_GENERAL mechanism */ typedef struct CK_RC2_MAC_GENERAL_PARAMS { CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ CK_ULONG ulMacLength; /* Length of MAC in bytes */ } CK_RC2_MAC_GENERAL_PARAMS; typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR CK_RC2_MAC_GENERAL_PARAMS_PTR; /* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and * CKM_RC5_MAC mechanisms */ typedef struct CK_RC5_PARAMS { CK_ULONG ulWordsize; /* wordsize in bits */ CK_ULONG ulRounds; /* number of rounds */ } CK_RC5_PARAMS; typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR; /* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC * mechanism */ typedef struct CK_RC5_CBC_PARAMS { CK_ULONG ulWordsize; /* wordsize in bits */ CK_ULONG ulRounds; /* number of rounds */ CK_BYTE_PTR pIv; /* pointer to IV */ CK_ULONG ulIvLen; /* length of IV in bytes */ } CK_RC5_CBC_PARAMS; typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR; /* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the * CKM_RC5_MAC_GENERAL mechanism */ typedef struct CK_RC5_MAC_GENERAL_PARAMS { CK_ULONG ulWordsize; /* wordsize in bits */ CK_ULONG ulRounds; /* number of rounds */ CK_ULONG ulMacLength; /* Length of MAC in bytes */ } CK_RC5_MAC_GENERAL_PARAMS; typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR CK_RC5_MAC_GENERAL_PARAMS_PTR; /* CK_MAC_GENERAL_PARAMS provides the parameters to most block * ciphers' MAC_GENERAL mechanisms. Its value is the length of * the MAC */ typedef CK_ULONG CK_MAC_GENERAL_PARAMS; typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR; typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[8]; CK_BYTE_PTR pData; CK_ULONG length; } CK_DES_CBC_ENCRYPT_DATA_PARAMS; typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR; typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[16]; CK_BYTE_PTR pData; CK_ULONG length; } CK_AES_CBC_ENCRYPT_DATA_PARAMS; typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR; /* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the * CKM_SKIPJACK_PRIVATE_WRAP mechanism */ typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS { CK_ULONG ulPasswordLen; CK_BYTE_PTR pPassword; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; CK_ULONG ulPAndGLen; CK_ULONG ulQLen; CK_ULONG ulRandomLen; CK_BYTE_PTR pRandomA; CK_BYTE_PTR pPrimeP; CK_BYTE_PTR pBaseG; CK_BYTE_PTR pSubprimeQ; } CK_SKIPJACK_PRIVATE_WRAP_PARAMS; typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR CK_SKIPJACK_PRIVATE_WRAP_PARAMS_PTR; /* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the * CKM_SKIPJACK_RELAYX mechanism */ typedef struct CK_SKIPJACK_RELAYX_PARAMS { CK_ULONG ulOldWrappedXLen; CK_BYTE_PTR pOldWrappedX; CK_ULONG ulOldPasswordLen; CK_BYTE_PTR pOldPassword; CK_ULONG ulOldPublicDataLen; CK_BYTE_PTR pOldPublicData; CK_ULONG ulOldRandomLen; CK_BYTE_PTR pOldRandomA; CK_ULONG ulNewPasswordLen; CK_BYTE_PTR pNewPassword; CK_ULONG ulNewPublicDataLen; CK_BYTE_PTR pNewPublicData; CK_ULONG ulNewRandomLen; CK_BYTE_PTR pNewRandomA; } CK_SKIPJACK_RELAYX_PARAMS; typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR CK_SKIPJACK_RELAYX_PARAMS_PTR; typedef struct CK_PBE_PARAMS { CK_BYTE_PTR pInitVector; CK_UTF8CHAR_PTR pPassword; CK_ULONG ulPasswordLen; CK_BYTE_PTR pSalt; CK_ULONG ulSaltLen; CK_ULONG ulIteration; } CK_PBE_PARAMS; typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR; /* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the * CKM_KEY_WRAP_SET_OAEP mechanism */ typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS { CK_BYTE bBC; /* block contents byte */ CK_BYTE_PTR pX; /* extra data */ CK_ULONG ulXLen; /* length of extra data in bytes */ } CK_KEY_WRAP_SET_OAEP_PARAMS; typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR CK_KEY_WRAP_SET_OAEP_PARAMS_PTR; typedef struct CK_SSL3_RANDOM_DATA { CK_BYTE_PTR pClientRandom; CK_ULONG ulClientRandomLen; CK_BYTE_PTR pServerRandom; CK_ULONG ulServerRandomLen; } CK_SSL3_RANDOM_DATA; typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS { CK_SSL3_RANDOM_DATA RandomInfo; CK_VERSION_PTR pVersion; } CK_SSL3_MASTER_KEY_DERIVE_PARAMS; typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR; typedef struct CK_SSL3_KEY_MAT_OUT { CK_OBJECT_HANDLE hClientMacSecret; CK_OBJECT_HANDLE hServerMacSecret; CK_OBJECT_HANDLE hClientKey; CK_OBJECT_HANDLE hServerKey; CK_BYTE_PTR pIVClient; CK_BYTE_PTR pIVServer; } CK_SSL3_KEY_MAT_OUT; typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR; typedef struct CK_SSL3_KEY_MAT_PARAMS { CK_ULONG ulMacSizeInBits; CK_ULONG ulKeySizeInBits; CK_ULONG ulIVSizeInBits; CK_BBOOL bIsExport; CK_SSL3_RANDOM_DATA RandomInfo; CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; } CK_SSL3_KEY_MAT_PARAMS; typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR; typedef struct CK_TLS_PRF_PARAMS { CK_BYTE_PTR pSeed; CK_ULONG ulSeedLen; CK_BYTE_PTR pLabel; CK_ULONG ulLabelLen; CK_BYTE_PTR pOutput; CK_ULONG_PTR pulOutputLen; } CK_TLS_PRF_PARAMS; typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR; typedef struct CK_WTLS_RANDOM_DATA { CK_BYTE_PTR pClientRandom; CK_ULONG ulClientRandomLen; CK_BYTE_PTR pServerRandom; CK_ULONG ulServerRandomLen; } CK_WTLS_RANDOM_DATA; typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR; typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS { CK_MECHANISM_TYPE DigestMechanism; CK_WTLS_RANDOM_DATA RandomInfo; CK_BYTE_PTR pVersion; } CK_WTLS_MASTER_KEY_DERIVE_PARAMS; typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR; typedef struct CK_WTLS_PRF_PARAMS { CK_MECHANISM_TYPE DigestMechanism; CK_BYTE_PTR pSeed; CK_ULONG ulSeedLen; CK_BYTE_PTR pLabel; CK_ULONG ulLabelLen; CK_BYTE_PTR pOutput; CK_ULONG_PTR pulOutputLen; } CK_WTLS_PRF_PARAMS; typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR; typedef struct CK_WTLS_KEY_MAT_OUT { CK_OBJECT_HANDLE hMacSecret; CK_OBJECT_HANDLE hKey; CK_BYTE_PTR pIV; } CK_WTLS_KEY_MAT_OUT; typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR; typedef struct CK_WTLS_KEY_MAT_PARAMS { CK_MECHANISM_TYPE DigestMechanism; CK_ULONG ulMacSizeInBits; CK_ULONG ulKeySizeInBits; CK_ULONG ulIVSizeInBits; CK_ULONG ulSequenceNumber; CK_BBOOL bIsExport; CK_WTLS_RANDOM_DATA RandomInfo; CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial; } CK_WTLS_KEY_MAT_PARAMS; typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR; typedef struct CK_CMS_SIG_PARAMS { CK_OBJECT_HANDLE certificateHandle; CK_MECHANISM_PTR pSigningMechanism; CK_MECHANISM_PTR pDigestMechanism; CK_UTF8CHAR_PTR pContentType; CK_BYTE_PTR pRequestedAttributes; CK_ULONG ulRequestedAttributesLen; CK_BYTE_PTR pRequiredAttributes; CK_ULONG ulRequiredAttributesLen; } CK_CMS_SIG_PARAMS; typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR; typedef struct CK_KEY_DERIVATION_STRING_DATA { CK_BYTE_PTR pData; CK_ULONG ulLen; } CK_KEY_DERIVATION_STRING_DATA; typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR CK_KEY_DERIVATION_STRING_DATA_PTR; /* The CK_EXTRACT_PARAMS is used for the * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit * of the base key should be used as the first bit of the * derived key */ typedef CK_ULONG CK_EXTRACT_PARAMS; typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR; /* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to * indicate the Pseudo-Random Function (PRF) used to generate * key bits using PKCS #5 PBKDF2. */ typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE; typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR; #define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001UL #define CKP_PKCS5_PBKD2_HMAC_GOSTR3411 0x00000002UL #define CKP_PKCS5_PBKD2_HMAC_SHA224 0x00000003UL #define CKP_PKCS5_PBKD2_HMAC_SHA256 0x00000004UL #define CKP_PKCS5_PBKD2_HMAC_SHA384 0x00000005UL #define CKP_PKCS5_PBKD2_HMAC_SHA512 0x00000006UL #define CKP_PKCS5_PBKD2_HMAC_SHA512_224 0x00000007UL #define CKP_PKCS5_PBKD2_HMAC_SHA512_256 0x00000008UL /* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the * source of the salt value when deriving a key using PKCS #5 * PBKDF2. */ typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE; typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR; /* The following salt value sources are defined in PKCS #5 v2.0. */ #define CKZ_SALT_SPECIFIED 0x00000001UL /* CK_PKCS5_PBKD2_PARAMS is a structure that provides the * parameters to the CKM_PKCS5_PBKD2 mechanism. */ typedef struct CK_PKCS5_PBKD2_PARAMS { CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; CK_VOID_PTR pSaltSourceData; CK_ULONG ulSaltSourceDataLen; CK_ULONG iterations; CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; CK_VOID_PTR pPrfData; CK_ULONG ulPrfDataLen; CK_UTF8CHAR_PTR pPassword; CK_ULONG_PTR ulPasswordLen; } CK_PKCS5_PBKD2_PARAMS; typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR; /* CK_PKCS5_PBKD2_PARAMS2 is a corrected version of the CK_PKCS5_PBKD2_PARAMS * structure that provides the parameters to the CKM_PKCS5_PBKD2 mechanism * noting that the ulPasswordLen field is a CK_ULONG and not a CK_ULONG_PTR. */ typedef struct CK_PKCS5_PBKD2_PARAMS2 { CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; CK_VOID_PTR pSaltSourceData; CK_ULONG ulSaltSourceDataLen; CK_ULONG iterations; CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; CK_VOID_PTR pPrfData; CK_ULONG ulPrfDataLen; CK_UTF8CHAR_PTR pPassword; CK_ULONG ulPasswordLen; } CK_PKCS5_PBKD2_PARAMS2; typedef CK_PKCS5_PBKD2_PARAMS2 CK_PTR CK_PKCS5_PBKD2_PARAMS2_PTR; typedef CK_ULONG CK_OTP_PARAM_TYPE; typedef CK_OTP_PARAM_TYPE CK_PARAM_TYPE; /* backward compatibility */ typedef struct CK_OTP_PARAM { CK_OTP_PARAM_TYPE type; CK_VOID_PTR pValue; CK_ULONG ulValueLen; } CK_OTP_PARAM; typedef CK_OTP_PARAM CK_PTR CK_OTP_PARAM_PTR; typedef struct CK_OTP_PARAMS { CK_OTP_PARAM_PTR pParams; CK_ULONG ulCount; } CK_OTP_PARAMS; typedef CK_OTP_PARAMS CK_PTR CK_OTP_PARAMS_PTR; typedef struct CK_OTP_SIGNATURE_INFO { CK_OTP_PARAM_PTR pParams; CK_ULONG ulCount; } CK_OTP_SIGNATURE_INFO; typedef CK_OTP_SIGNATURE_INFO CK_PTR CK_OTP_SIGNATURE_INFO_PTR; #define CK_OTP_VALUE 0UL #define CK_OTP_PIN 1UL #define CK_OTP_CHALLENGE 2UL #define CK_OTP_TIME 3UL #define CK_OTP_COUNTER 4UL #define CK_OTP_FLAGS 5UL #define CK_OTP_OUTPUT_LENGTH 6UL #define CK_OTP_OUTPUT_FORMAT 7UL #define CKF_NEXT_OTP 0x00000001UL #define CKF_EXCLUDE_TIME 0x00000002UL #define CKF_EXCLUDE_COUNTER 0x00000004UL #define CKF_EXCLUDE_CHALLENGE 0x00000008UL #define CKF_EXCLUDE_PIN 0x00000010UL #define CKF_USER_FRIENDLY_OTP 0x00000020UL typedef struct CK_KIP_PARAMS { CK_MECHANISM_PTR pMechanism; CK_OBJECT_HANDLE hKey; CK_BYTE_PTR pSeed; CK_ULONG ulSeedLen; } CK_KIP_PARAMS; typedef CK_KIP_PARAMS CK_PTR CK_KIP_PARAMS_PTR; typedef struct CK_AES_CTR_PARAMS { CK_ULONG ulCounterBits; CK_BYTE cb[16]; } CK_AES_CTR_PARAMS; typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR; typedef struct CK_GCM_PARAMS { CK_BYTE_PTR pIv; CK_ULONG ulIvLen; CK_ULONG ulIvBits; CK_BYTE_PTR pAAD; CK_ULONG ulAADLen; CK_ULONG ulTagBits; } CK_GCM_PARAMS; typedef CK_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR; typedef CK_ULONG CK_GENERATOR_FUNCTION; #define CKG_NO_GENERATE 0x00000000UL #define CKG_GENERATE 0x00000001UL #define CKG_GENERATE_COUNTER 0x00000002UL #define CKG_GENERATE_RANDOM 0x00000003UL #define CKG_GENERATE_COUNTER_XOR 0x00000004UL typedef struct CK_GCM_MESSAGE_PARAMS { CK_BYTE_PTR pIv; CK_ULONG ulIvLen; CK_ULONG ulIvFixedBits; CK_GENERATOR_FUNCTION ivGenerator; CK_BYTE_PTR pTag; CK_ULONG ulTagBits; } CK_GCM_MESSAGE_PARAMS; typedef CK_GCM_MESSAGE_PARAMS CK_PTR CK_GCM_MESSAGE_PARAMS_PTR; typedef struct CK_CCM_PARAMS { CK_ULONG ulDataLen; CK_BYTE_PTR pNonce; CK_ULONG ulNonceLen; CK_BYTE_PTR pAAD; CK_ULONG ulAADLen; CK_ULONG ulMACLen; } CK_CCM_PARAMS; typedef CK_CCM_PARAMS CK_PTR CK_CCM_PARAMS_PTR; typedef struct CK_CCM_MESSAGE_PARAMS { CK_ULONG ulDataLen; /*plaintext or ciphertext*/ CK_BYTE_PTR pNonce; CK_ULONG ulNonceLen; CK_ULONG ulNonceFixedBits; CK_GENERATOR_FUNCTION nonceGenerator; CK_BYTE_PTR pMAC; CK_ULONG ulMACLen; } CK_CCM_MESSAGE_PARAMS; typedef CK_CCM_MESSAGE_PARAMS CK_PTR CK_CCM_MESSAGE_PARAMS_PTR; /* Deprecated. Use CK_GCM_PARAMS */ typedef struct CK_AES_GCM_PARAMS { CK_BYTE_PTR pIv; CK_ULONG ulIvLen; CK_ULONG ulIvBits; CK_BYTE_PTR pAAD; CK_ULONG ulAADLen; CK_ULONG ulTagBits; } CK_AES_GCM_PARAMS; typedef CK_AES_GCM_PARAMS CK_PTR CK_AES_GCM_PARAMS_PTR; /* Deprecated. Use CK_CCM_PARAMS */ typedef struct CK_AES_CCM_PARAMS { CK_ULONG ulDataLen; CK_BYTE_PTR pNonce; CK_ULONG ulNonceLen; CK_BYTE_PTR pAAD; CK_ULONG ulAADLen; CK_ULONG ulMACLen; } CK_AES_CCM_PARAMS; typedef CK_AES_CCM_PARAMS CK_PTR CK_AES_CCM_PARAMS_PTR; typedef struct CK_CAMELLIA_CTR_PARAMS { CK_ULONG ulCounterBits; CK_BYTE cb[16]; } CK_CAMELLIA_CTR_PARAMS; typedef CK_CAMELLIA_CTR_PARAMS CK_PTR CK_CAMELLIA_CTR_PARAMS_PTR; typedef struct CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[16]; CK_BYTE_PTR pData; CK_ULONG length; } CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS; typedef CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS_PTR; typedef struct CK_ARIA_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[16]; CK_BYTE_PTR pData; CK_ULONG length; } CK_ARIA_CBC_ENCRYPT_DATA_PARAMS; typedef CK_ARIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_ARIA_CBC_ENCRYPT_DATA_PARAMS_PTR; typedef struct CK_DSA_PARAMETER_GEN_PARAM { CK_MECHANISM_TYPE hash; CK_BYTE_PTR pSeed; CK_ULONG ulSeedLen; CK_ULONG ulIndex; } CK_DSA_PARAMETER_GEN_PARAM; typedef CK_DSA_PARAMETER_GEN_PARAM CK_PTR CK_DSA_PARAMETER_GEN_PARAM_PTR; typedef struct CK_ECDH_AES_KEY_WRAP_PARAMS { CK_ULONG ulAESKeyBits; CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE_PTR pSharedData; } CK_ECDH_AES_KEY_WRAP_PARAMS; typedef CK_ECDH_AES_KEY_WRAP_PARAMS CK_PTR CK_ECDH_AES_KEY_WRAP_PARAMS_PTR; typedef CK_ULONG CK_JAVA_MIDP_SECURITY_DOMAIN; typedef CK_ULONG CK_CERTIFICATE_CATEGORY; typedef struct CK_RSA_AES_KEY_WRAP_PARAMS { CK_ULONG ulAESKeyBits; CK_RSA_PKCS_OAEP_PARAMS_PTR pOAEPParams; } CK_RSA_AES_KEY_WRAP_PARAMS; typedef CK_RSA_AES_KEY_WRAP_PARAMS CK_PTR CK_RSA_AES_KEY_WRAP_PARAMS_PTR; typedef struct CK_TLS12_MASTER_KEY_DERIVE_PARAMS { CK_SSL3_RANDOM_DATA RandomInfo; CK_VERSION_PTR pVersion; CK_MECHANISM_TYPE prfHashMechanism; } CK_TLS12_MASTER_KEY_DERIVE_PARAMS; typedef CK_TLS12_MASTER_KEY_DERIVE_PARAMS CK_PTR CK_TLS12_MASTER_KEY_DERIVE_PARAMS_PTR; typedef struct CK_TLS12_KEY_MAT_PARAMS { CK_ULONG ulMacSizeInBits; CK_ULONG ulKeySizeInBits; CK_ULONG ulIVSizeInBits; CK_BBOOL bIsExport; CK_SSL3_RANDOM_DATA RandomInfo; CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; CK_MECHANISM_TYPE prfHashMechanism; } CK_TLS12_KEY_MAT_PARAMS; typedef CK_TLS12_KEY_MAT_PARAMS CK_PTR CK_TLS12_KEY_MAT_PARAMS_PTR; typedef struct CK_TLS_KDF_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BYTE_PTR pLabel; CK_ULONG ulLabelLength; CK_SSL3_RANDOM_DATA RandomInfo; CK_BYTE_PTR pContextData; CK_ULONG ulContextDataLength; } CK_TLS_KDF_PARAMS; typedef CK_TLS_KDF_PARAMS CK_PTR CK_TLS_KDF_PARAMS_PTR; typedef struct CK_TLS_MAC_PARAMS { CK_MECHANISM_TYPE prfHashMechanism; CK_ULONG ulMacLength; CK_ULONG ulServerOrClient; } CK_TLS_MAC_PARAMS; typedef CK_TLS_MAC_PARAMS CK_PTR CK_TLS_MAC_PARAMS_PTR; typedef struct CK_GOSTR3410_DERIVE_PARAMS { CK_EC_KDF_TYPE kdf; CK_BYTE_PTR pPublicData; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pUKM; CK_ULONG ulUKMLen; } CK_GOSTR3410_DERIVE_PARAMS; typedef CK_GOSTR3410_DERIVE_PARAMS CK_PTR CK_GOSTR3410_DERIVE_PARAMS_PTR; typedef struct CK_GOSTR3410_KEY_WRAP_PARAMS { CK_BYTE_PTR pWrapOID; CK_ULONG ulWrapOIDLen; CK_BYTE_PTR pUKM; CK_ULONG ulUKMLen; CK_OBJECT_HANDLE hKey; } CK_GOSTR3410_KEY_WRAP_PARAMS; typedef CK_GOSTR3410_KEY_WRAP_PARAMS CK_PTR CK_GOSTR3410_KEY_WRAP_PARAMS_PTR; typedef struct CK_SEED_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[16]; CK_BYTE_PTR pData; CK_ULONG length; } CK_SEED_CBC_ENCRYPT_DATA_PARAMS; typedef CK_SEED_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_SEED_CBC_ENCRYPT_DATA_PARAMS_PTR; /* * New PKCS 11 v3.0 data structures. */ typedef CK_ULONG CK_PROFILE_ID; typedef CK_PROFILE_ID CK_PTR CK_PROFILE_ID_PTR; /* Typedefs for Flexible KDF */ typedef CK_ULONG CK_PRF_DATA_TYPE; typedef CK_MECHANISM_TYPE CK_SP800_108_PRF_TYPE; #define CK_SP800_108_ITERATION_VARIABLE 0x00000001UL #define CK_SP800_108_OPTIONAL_COUNTER 0x00000002UL #define CK_SP800_108_DKM_LENGTH 0x00000003UL #define CK_SP800_108_BYTE_ARRAY 0x00000004UL #define CK_SP800_108_COUNTER CK_SP800_108_OPTIONAL_COUNTER typedef struct CK_PRF_DATA_PARAM { CK_PRF_DATA_TYPE type; CK_VOID_PTR pValue; CK_ULONG ulValueLen; } CK_PRF_DATA_PARAM; typedef CK_PRF_DATA_PARAM CK_PTR CK_PRF_DATA_PARAM_PTR; typedef struct CK_SP800_108_COUNTER_FORMAT { CK_BBOOL bLittleEndian; CK_ULONG ulWidthInBits; } CK_SP800_108_COUNTER_FORMAT; typedef CK_SP800_108_COUNTER_FORMAT CK_PTR CK_SP800_108_COUNTER_FORMAT_PTR; typedef CK_ULONG CK_SP800_108_DKM_LENGTH_METHOD; #define CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS 0x00000001UL #define CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS 0x00000002UL typedef struct CK_SP800_108_DKM_LENGTH_FORMAT { CK_SP800_108_DKM_LENGTH_METHOD dkmLengthMethod; CK_BBOOL bLittleEndian; CK_ULONG ulWidthInBits; } CK_SP800_108_DKM_LENGTH_FORMAT; typedef CK_SP800_108_DKM_LENGTH_FORMAT CK_PTR CK_SP800_108_DKM_LENGTH_FORMAT_PTR; typedef struct CK_DERIVED_KEY { CK_ATTRIBUTE_PTR pTemplate; CK_ULONG ulAttributeCount; CK_OBJECT_HANDLE_PTR phKey; } CK_DERIVED_KEY; typedef CK_DERIVED_KEY CK_PTR CK_DERIVED_KEY_PTR; typedef struct CK_SP800_108_KDF_PARAMS { CK_SP800_108_PRF_TYPE prfType; CK_ULONG ulNumberOfDataParams; CK_PRF_DATA_PARAM_PTR pDataParams; CK_ULONG ulAdditionalDerivedKeys; CK_DERIVED_KEY_PTR pAdditionalDerivedKeys; } CK_SP800_108_KDF_PARAMS; typedef CK_SP800_108_KDF_PARAMS CK_PTR CK_SP800_108_KDF_PARAMS_PTR; typedef struct CK_SP800_108_FEEDBACK_KDF_PARAMS { CK_SP800_108_PRF_TYPE prfType; CK_ULONG ulNumberOfDataParams; CK_PRF_DATA_PARAM_PTR pDataParams; CK_ULONG ulIVLen; CK_BYTE_PTR pIV; CK_ULONG ulAdditionalDerivedKeys; CK_DERIVED_KEY_PTR pAdditionalDerivedKeys; } CK_SP800_108_FEEDBACK_KDF_PARAMS; typedef CK_SP800_108_FEEDBACK_KDF_PARAMS CK_PTR CK_SP800_108_FEEDBACK_KDF_PARAMS_PTR; /* EDDSA */ typedef struct CK_EDDSA_PARAMS { CK_BBOOL phFlag; CK_ULONG ulContextDataLen; CK_BYTE_PTR pContextData; } CK_EDDSA_PARAMS; typedef CK_EDDSA_PARAMS CK_PTR CK_EDDSA_PARAMS_PTR; /* Extended ChaCha20/Salsa20 support*/ typedef struct CK_CHACHA20_PARAMS { CK_BYTE_PTR pBlockCounter; CK_ULONG blockCounterBits; CK_BYTE_PTR pNonce; CK_ULONG ulNonceBits; } CK_CHACHA20_PARAMS; typedef CK_CHACHA20_PARAMS CK_PTR CK_CHACHA20_PARAMS_PTR; typedef struct CK_SALSA20_PARAMS { CK_BYTE_PTR pBlockCounter; CK_BYTE_PTR pNonce; CK_ULONG ulNonceBits; } CK_SALSA20_PARAMS; typedef CK_SALSA20_PARAMS CK_PTR CK_SALSA20_PARAMS_PTR; typedef struct CK_SALSA20_CHACHA20_POLY1305_PARAMS { CK_BYTE_PTR pNonce; CK_ULONG ulNonceLen; CK_BYTE_PTR pAAD; CK_ULONG ulAADLen; } CK_SALSA20_CHACHA20_POLY1305_PARAMS; typedef CK_SALSA20_CHACHA20_POLY1305_PARAMS CK_PTR CK_SALSA20_CHACHA20_POLY1305_PARAMS_PTR; typedef struct CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS { CK_BYTE_PTR pNonce; CK_ULONG ulNonceLen; CK_BYTE_PTR pTag; } CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS; typedef CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS CK_PTR CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS_PTR; typedef CK_ULONG CK_X3DH_KDF_TYPE; typedef CK_X3DH_KDF_TYPE CK_PTR CK_X3DH_KDF_TYPE_PTR; /* X3dh, ratchet */ typedef struct CK_X3DH_INITIATE_PARAMS { CK_X3DH_KDF_TYPE kdf; CK_OBJECT_HANDLE pPeer_identity; CK_OBJECT_HANDLE pPeer_prekey; CK_BYTE_PTR pPrekey_signature; CK_BYTE_PTR pOnetime_key; CK_OBJECT_HANDLE pOwn_identity; CK_OBJECT_HANDLE pOwn_ephemeral; } CK_X3DH_INITIATE_PARAMS; typedef struct CK_X3DH_RESPOND_PARAMS { CK_X3DH_KDF_TYPE kdf; CK_BYTE_PTR pIdentity_id; CK_BYTE_PTR pPrekey_id; CK_BYTE_PTR pOnetime_id; CK_OBJECT_HANDLE pInitiator_identity; CK_BYTE_PTR pInitiator_ephemeral; } CK_X3DH_RESPOND_PARAMS; typedef CK_ULONG CK_X2RATCHET_KDF_TYPE; typedef CK_X2RATCHET_KDF_TYPE CK_PTR CK_X2RATCHET_KDF_TYPE_PTR; typedef struct CK_X2RATCHET_INITIALIZE_PARAMS { CK_BYTE_PTR sk; CK_OBJECT_HANDLE peer_public_prekey; CK_OBJECT_HANDLE peer_public_identity; CK_OBJECT_HANDLE own_public_identity; CK_BBOOL bEncryptedHeader; CK_ULONG eCurve; CK_MECHANISM_TYPE aeadMechanism; CK_X2RATCHET_KDF_TYPE kdfMechanism; } CK_X2RATCHET_INITIALIZE_PARAMS; typedef CK_X2RATCHET_INITIALIZE_PARAMS CK_PTR CK_X2RATCHET_INITIALIZE_PARAMS_PTR; typedef struct CK_X2RATCHET_RESPOND_PARAMS { CK_BYTE_PTR sk; CK_OBJECT_HANDLE own_prekey; CK_OBJECT_HANDLE initiator_identity; CK_OBJECT_HANDLE own_public_identity; CK_BBOOL bEncryptedHeader; CK_ULONG eCurve; CK_MECHANISM_TYPE aeadMechanism; CK_X2RATCHET_KDF_TYPE kdfMechanism; } CK_X2RATCHET_RESPOND_PARAMS; typedef CK_X2RATCHET_RESPOND_PARAMS CK_PTR CK_X2RATCHET_RESPOND_PARAMS_PTR; typedef CK_ULONG CK_XEDDSA_HASH_TYPE; typedef CK_XEDDSA_HASH_TYPE CK_PTR CK_XEDDSA_HASH_TYPE_PTR; /* XEDDSA */ typedef struct CK_XEDDSA_PARAMS { CK_XEDDSA_HASH_TYPE hash; } CK_XEDDSA_PARAMS; typedef CK_XEDDSA_PARAMS CK_PTR CK_XEDDSA_PARAMS_PTR; /* HKDF params */ typedef struct CK_HKDF_PARAMS { CK_BBOOL bExtract; CK_BBOOL bExpand; CK_MECHANISM_TYPE prfHashMechanism; CK_ULONG ulSaltType; CK_BYTE_PTR pSalt; CK_ULONG ulSaltLen; CK_OBJECT_HANDLE hSaltKey; CK_BYTE_PTR pInfo; CK_ULONG ulInfoLen; } CK_HKDF_PARAMS; typedef CK_HKDF_PARAMS CK_PTR CK_HKDF_PARAMS_PTR; #define CKF_HKDF_SALT_NULL 0x00000001UL #define CKF_HKDF_SALT_DATA 0x00000002UL #define CKF_HKDF_SALT_KEY 0x00000004UL /* HSS */ typedef CK_ULONG CK_HSS_LEVELS; typedef CK_ULONG CK_LMS_TYPE; typedef CK_ULONG CK_LMOTS_TYPE; typedef struct specifiedParams { CK_HSS_LEVELS levels; CK_LMS_TYPE lm_type[8]; CK_LMOTS_TYPE lm_ots_type[8]; } specifiedParams; /* IKE Params */ typedef struct CK_IKE2_PRF_PLUS_DERIVE_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BBOOL bHasSeedKey; CK_OBJECT_HANDLE hSeedKey; CK_BYTE_PTR pSeedData; CK_ULONG ulSeedDataLen; } CK_IKE2_PRF_PLUS_DERIVE_PARAMS; typedef CK_IKE2_PRF_PLUS_DERIVE_PARAMS CK_PTR CK_IKE2_PRF_PLUS_DERIVE_PARAMS_PTR; typedef struct CK_IKE_PRF_DERIVE_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BBOOL bDataAsKey; CK_BBOOL bRekey; CK_BYTE_PTR pNi; CK_ULONG ulNiLen; CK_BYTE_PTR pNr; CK_ULONG ulNrLen; CK_OBJECT_HANDLE hNewKey; } CK_IKE_PRF_DERIVE_PARAMS; typedef CK_IKE_PRF_DERIVE_PARAMS CK_PTR CK_IKE_PRF_DERIVE_PARAMS_PTR; typedef struct CK_IKE1_PRF_DERIVE_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BBOOL bHasPrevKey; CK_OBJECT_HANDLE hKeygxy; CK_OBJECT_HANDLE hPrevKey; CK_BYTE_PTR pCKYi; CK_ULONG ulCKYiLen; CK_BYTE_PTR pCKYr; CK_ULONG ulCKYrLen; CK_BYTE keyNumber; } CK_IKE1_PRF_DERIVE_PARAMS; typedef CK_IKE1_PRF_DERIVE_PARAMS CK_PTR CK_IKE1_PRF_DERIVE_PARAMS_PTR; typedef struct CK_IKE1_EXTENDED_DERIVE_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BBOOL bHasKeygxy; CK_OBJECT_HANDLE hKeygxy; CK_BYTE_PTR pExtraData; CK_ULONG ulExtraDataLen; } CK_IKE1_EXTENDED_DERIVE_PARAMS; typedef CK_IKE1_EXTENDED_DERIVE_PARAMS CK_PTR CK_IKE1_EXTENDED_DERIVE_PARAMS_PTR; #endif /* _PKCS11T_H_ */ yubihsm-shell-2.7.3/pkcs11/cmdline.c0000644000175000017500000012554015167357143016172 0ustar aveenaveen/* File autogenerated by gengetopt version 2.23 generated with the following command: gengetopt --conf-parser --no-handle-error --string-parser -i /home/runner/work/yubihsm-shell/yubihsm-shell/pkcs11/cmdline.ggo --output-dir /home/runner/work/yubihsm-shell/yubihsm-shell/pkcs11 cmdline The developers of gengetopt consider the fixed text that goes in all gengetopt output files to be in the public domain: we make no copyright claims on it. */ /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifndef FIX_UNUSED #define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ #endif #include #include "cmdline.h" const char *gengetopt_args_info_purpose = ""; const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { " -h, --help Print help and exit", " -V, --version Print version and exit", " --config-file=STRING Configuration file to read\n (default=`./yubihsm_pkcs11.conf')", " --connector=STRING List of connectors to use", " --debug Enable pkcs11 debugging (default=off)", " --dinout Enable pkcs11 function tracing (default=off)", " --libdebug Enable libyubihsm debugging (default=off)", " --debug-file=STRING Output file for debugging (default=`stderr')", " --cacert=STRING Cacert to use for HTTPS validation", " --cert=STRING HTTPS client certificate to authenticate with", " --key=STRING HTTPS client certificate key", " --proxy=STRING Proxy server to use for connector", " --noproxy=STRING Comma separated list of hosts ignore proxy for", " --timeout=INT Timeout to use for initial connection to\n connector (default=`5')", " --device-pubkey=STRING List of device public keys allowed for asymmetric\n authentication", 0 }; typedef enum {ARG_NO , ARG_FLAG , ARG_STRING , ARG_INT } cmdline_parser_arg_type; static void clear_given (struct gengetopt_args_info *args_info); static void clear_args (struct gengetopt_args_info *args_info); static int cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error); static int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error); struct line_list { char * string_arg; struct line_list * next; }; static struct line_list *cmd_line_list = 0; static struct line_list *cmd_line_list_tmp = 0; static void free_cmd_list(void) { /* free the list of a previous call */ if (cmd_line_list) { while (cmd_line_list) { cmd_line_list_tmp = cmd_line_list; cmd_line_list = cmd_line_list->next; free (cmd_line_list_tmp->string_arg); free (cmd_line_list_tmp); } } } static char * gengetopt_strdup (const char *s); static void clear_given (struct gengetopt_args_info *args_info) { args_info->help_given = 0 ; args_info->version_given = 0 ; args_info->config_file_given = 0 ; args_info->connector_given = 0 ; args_info->debug_given = 0 ; args_info->dinout_given = 0 ; args_info->libdebug_given = 0 ; args_info->debug_file_given = 0 ; args_info->cacert_given = 0 ; args_info->cert_given = 0 ; args_info->key_given = 0 ; args_info->proxy_given = 0 ; args_info->noproxy_given = 0 ; args_info->timeout_given = 0 ; args_info->device_pubkey_given = 0 ; } static void clear_args (struct gengetopt_args_info *args_info) { FIX_UNUSED (args_info); args_info->config_file_arg = gengetopt_strdup ("./yubihsm_pkcs11.conf"); args_info->config_file_orig = NULL; args_info->connector_arg = NULL; args_info->connector_orig = NULL; args_info->debug_flag = 0; args_info->dinout_flag = 0; args_info->libdebug_flag = 0; args_info->debug_file_arg = gengetopt_strdup ("stderr"); args_info->debug_file_orig = NULL; args_info->cacert_arg = NULL; args_info->cacert_orig = NULL; args_info->cert_arg = NULL; args_info->cert_orig = NULL; args_info->key_arg = NULL; args_info->key_orig = NULL; args_info->proxy_arg = NULL; args_info->proxy_orig = NULL; args_info->noproxy_arg = NULL; args_info->noproxy_orig = NULL; args_info->timeout_arg = 5; args_info->timeout_orig = NULL; args_info->device_pubkey_arg = NULL; args_info->device_pubkey_orig = NULL; } static void init_args_info(struct gengetopt_args_info *args_info) { args_info->help_help = gengetopt_args_info_help[0] ; args_info->version_help = gengetopt_args_info_help[1] ; args_info->config_file_help = gengetopt_args_info_help[2] ; args_info->connector_help = gengetopt_args_info_help[3] ; args_info->connector_min = 0; args_info->connector_max = 0; args_info->debug_help = gengetopt_args_info_help[4] ; args_info->dinout_help = gengetopt_args_info_help[5] ; args_info->libdebug_help = gengetopt_args_info_help[6] ; args_info->debug_file_help = gengetopt_args_info_help[7] ; args_info->cacert_help = gengetopt_args_info_help[8] ; args_info->cert_help = gengetopt_args_info_help[9] ; args_info->key_help = gengetopt_args_info_help[10] ; args_info->proxy_help = gengetopt_args_info_help[11] ; args_info->noproxy_help = gengetopt_args_info_help[12] ; args_info->timeout_help = gengetopt_args_info_help[13] ; args_info->device_pubkey_help = gengetopt_args_info_help[14] ; args_info->device_pubkey_min = 0; args_info->device_pubkey_max = 0; } void cmdline_parser_print_version (void) { printf ("%s %s\n", (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), CMDLINE_PARSER_VERSION); if (strlen(gengetopt_args_info_versiontext) > 0) printf("\n%s\n", gengetopt_args_info_versiontext); } static void print_help_common(void) { size_t len_purpose = strlen(gengetopt_args_info_purpose); size_t len_usage = strlen(gengetopt_args_info_usage); if (len_usage > 0) { printf("%s\n", gengetopt_args_info_usage); } if (len_purpose > 0) { printf("%s\n", gengetopt_args_info_purpose); } if (len_usage || len_purpose) { printf("\n"); } if (strlen(gengetopt_args_info_description) > 0) { printf("%s\n\n", gengetopt_args_info_description); } } void cmdline_parser_print_help (void) { int i = 0; print_help_common(); while (gengetopt_args_info_help[i]) printf("%s\n", gengetopt_args_info_help[i++]); } void cmdline_parser_init (struct gengetopt_args_info *args_info) { clear_given (args_info); clear_args (args_info); init_args_info (args_info); } void cmdline_parser_params_init(struct cmdline_parser_params *params) { if (params) { params->override = 0; params->initialize = 1; params->check_required = 1; params->check_ambiguity = 0; params->print_errors = 1; } } struct cmdline_parser_params * cmdline_parser_params_create(void) { struct cmdline_parser_params *params = (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); cmdline_parser_params_init(params); return params; } static void free_string_field (char **s) { if (*s) { free (*s); *s = 0; } } /** @brief generic value variable */ union generic_value { int int_arg; char *string_arg; const char *default_string_arg; }; /** @brief holds temporary values for multiple options */ struct generic_list { union generic_value arg; char *orig; struct generic_list *next; }; /** * @brief add a node at the head of the list */ static void add_node(struct generic_list **list) { struct generic_list *new_node = (struct generic_list *) malloc (sizeof (struct generic_list)); new_node->next = *list; *list = new_node; new_node->arg.string_arg = 0; new_node->orig = 0; } static void free_multiple_string_field(unsigned int len, char ***arg, char ***orig) { unsigned int i; if (*arg) { for (i = 0; i < len; ++i) { free_string_field(&((*arg)[i])); free_string_field(&((*orig)[i])); } free_string_field(&((*arg)[0])); /* free default string */ free (*arg); *arg = 0; free (*orig); *orig = 0; } } static void cmdline_parser_release (struct gengetopt_args_info *args_info) { free_string_field (&(args_info->config_file_arg)); free_string_field (&(args_info->config_file_orig)); free_multiple_string_field (args_info->connector_given, &(args_info->connector_arg), &(args_info->connector_orig)); free_string_field (&(args_info->debug_file_arg)); free_string_field (&(args_info->debug_file_orig)); free_string_field (&(args_info->cacert_arg)); free_string_field (&(args_info->cacert_orig)); free_string_field (&(args_info->cert_arg)); free_string_field (&(args_info->cert_orig)); free_string_field (&(args_info->key_arg)); free_string_field (&(args_info->key_orig)); free_string_field (&(args_info->proxy_arg)); free_string_field (&(args_info->proxy_orig)); free_string_field (&(args_info->noproxy_arg)); free_string_field (&(args_info->noproxy_orig)); free_string_field (&(args_info->timeout_orig)); free_multiple_string_field (args_info->device_pubkey_given, &(args_info->device_pubkey_arg), &(args_info->device_pubkey_orig)); clear_given (args_info); } static void write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) { FIX_UNUSED (values); if (arg) { fprintf(outfile, "%s=\"%s\"\n", opt, arg); } else { fprintf(outfile, "%s\n", opt); } } static void write_multiple_into_file(FILE *outfile, int len, const char *opt, char **arg, const char *values[]) { int i; for (i = 0; i < len; ++i) write_into_file(outfile, opt, (arg ? arg[i] : 0), values); } int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) { int i = 0; if (!outfile) { fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); return EXIT_FAILURE; } if (args_info->help_given) write_into_file(outfile, "help", 0, 0 ); if (args_info->version_given) write_into_file(outfile, "version", 0, 0 ); if (args_info->config_file_given) write_into_file(outfile, "config-file", args_info->config_file_orig, 0); write_multiple_into_file(outfile, args_info->connector_given, "connector", args_info->connector_orig, 0); if (args_info->debug_given) write_into_file(outfile, "debug", 0, 0 ); if (args_info->dinout_given) write_into_file(outfile, "dinout", 0, 0 ); if (args_info->libdebug_given) write_into_file(outfile, "libdebug", 0, 0 ); if (args_info->debug_file_given) write_into_file(outfile, "debug-file", args_info->debug_file_orig, 0); if (args_info->cacert_given) write_into_file(outfile, "cacert", args_info->cacert_orig, 0); if (args_info->cert_given) write_into_file(outfile, "cert", args_info->cert_orig, 0); if (args_info->key_given) write_into_file(outfile, "key", args_info->key_orig, 0); if (args_info->proxy_given) write_into_file(outfile, "proxy", args_info->proxy_orig, 0); if (args_info->noproxy_given) write_into_file(outfile, "noproxy", args_info->noproxy_orig, 0); if (args_info->timeout_given) write_into_file(outfile, "timeout", args_info->timeout_orig, 0); write_multiple_into_file(outfile, args_info->device_pubkey_given, "device-pubkey", args_info->device_pubkey_orig, 0); i = EXIT_SUCCESS; return i; } int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) { FILE *outfile; int i = 0; outfile = fopen(filename, "w"); if (!outfile) { fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); return EXIT_FAILURE; } i = cmdline_parser_dump(outfile, args_info); fclose (outfile); return i; } void cmdline_parser_free (struct gengetopt_args_info *args_info) { cmdline_parser_release (args_info); } /** @brief replacement of strdup, which is not standard */ char * gengetopt_strdup (const char *s) { char *result = 0; if (!s) return result; result = (char*)malloc(strlen(s) + 1); if (result == (char*)0) return (char*)0; strcpy(result, s); return result; } static char * get_multiple_arg_token(const char *arg) { const char *tok; char *ret; size_t len, num_of_escape, i, j; if (!arg) return 0; tok = strchr (arg, ','); num_of_escape = 0; /* make sure it is not escaped */ while (tok) { if (*(tok-1) == '\\') { /* find the next one */ tok = strchr (tok+1, ','); ++num_of_escape; } else break; } if (tok) len = (size_t)(tok - arg + 1); else len = strlen (arg) + 1; len -= num_of_escape; ret = (char *) malloc (len); i = 0; j = 0; while (arg[i] && (j < len-1)) { if (arg[i] == '\\' && arg[ i + 1 ] && arg[ i + 1 ] == ',') ++i; ret[j++] = arg[i++]; } ret[len-1] = '\0'; return ret; } static const char * get_multiple_arg_token_next(const char *arg) { const char *tok; if (!arg) return 0; tok = strchr (arg, ','); /* make sure it is not escaped */ while (tok) { if (*(tok-1) == '\\') { /* find the next one */ tok = strchr (tok+1, ','); } else break; } if (! tok || strlen(tok) == 1) return 0; return tok+1; } static int check_multiple_option_occurrences(const char *prog_name, unsigned int option_given, unsigned int min, unsigned int max, const char *option_desc); int check_multiple_option_occurrences(const char *prog_name, unsigned int option_given, unsigned int min, unsigned int max, const char *option_desc) { int error_occurred = 0; if (option_given && (min > 0 || max > 0)) { if (min > 0 && max > 0) { if (min == max) { /* specific occurrences */ if (option_given != (unsigned int) min) { fprintf (stderr, "%s: %s option occurrences must be %d\n", prog_name, option_desc, min); error_occurred = 1; } } else if (option_given < (unsigned int) min || option_given > (unsigned int) max) { /* range occurrences */ fprintf (stderr, "%s: %s option occurrences must be between %d and %d\n", prog_name, option_desc, min, max); error_occurred = 1; } } else if (min > 0) { /* at least check */ if (option_given < min) { fprintf (stderr, "%s: %s option occurrences must be at least %d\n", prog_name, option_desc, min); error_occurred = 1; } } else if (max > 0) { /* at most check */ if (option_given > max) { fprintf (stderr, "%s: %s option occurrences must be at most %d\n", prog_name, option_desc, max); error_occurred = 1; } } } return error_occurred; } int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) { return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); } int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params) { int result; result = cmdline_parser_internal (argc, argv, args_info, params, 0); return result; } int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) { int result; struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); return result; } int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) { int result = EXIT_SUCCESS; if (cmdline_parser_required2(args_info, prog_name, 0) > 0) result = EXIT_FAILURE; return result; } int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error) { int error_occurred = 0; FIX_UNUSED (additional_error); /* checks for required options */ if (check_multiple_option_occurrences(prog_name, args_info->connector_given, args_info->connector_min, args_info->connector_max, "'--connector'")) error_occurred = 1; if (check_multiple_option_occurrences(prog_name, args_info->device_pubkey_given, args_info->device_pubkey_min, args_info->device_pubkey_max, "'--device-pubkey'")) error_occurred = 1; /* checks for dependences among options */ return error_occurred; } static char *package_name = 0; /** * @brief updates an option * @param field the generic pointer to the field to update * @param orig_field the pointer to the orig field * @param field_given the pointer to the number of occurrence of this option * @param prev_given the pointer to the number of occurrence already seen * @param value the argument for this option (if null no arg was specified) * @param possible_values the possible values for this option (if specified) * @param default_value the default value (in case the option only accepts fixed values) * @param arg_type the type of this option * @param check_ambiguity @see cmdline_parser_params.check_ambiguity * @param override @see cmdline_parser_params.override * @param no_free whether to free a possible previous value * @param multiple_option whether this is a multiple option * @param long_opt the corresponding long option * @param short_opt the corresponding short option (or '-' if none) * @param additional_error possible further error specification */ static int update_arg(void *field, char **orig_field, unsigned int *field_given, unsigned int *prev_given, char *value, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, int check_ambiguity, int override, int no_free, int multiple_option, const char *long_opt, char short_opt, const char *additional_error) { char *stop_char = 0; const char *val = value; int found; char **string_field; FIX_UNUSED (field); stop_char = 0; found = 0; if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) { if (short_opt != '-') fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", package_name, long_opt, short_opt, (additional_error ? additional_error : "")); else fprintf (stderr, "%s: `--%s' option given more than once%s\n", package_name, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } FIX_UNUSED (default_value); if (field_given && *field_given && ! override) return 0; if (prev_given) (*prev_given)++; if (field_given) (*field_given)++; if (possible_values) val = possible_values[found]; switch(arg_type) { case ARG_FLAG: *((int *)field) = !*((int *)field); break; case ARG_INT: if (val) *((int *)field) = strtol (val, &stop_char, 0); break; case ARG_STRING: if (val) { string_field = (char **)field; if (!no_free && *string_field) free (*string_field); /* free previous string */ *string_field = gengetopt_strdup (val); } break; default: break; }; /* check numeric conversion */ switch(arg_type) { case ARG_INT: if (val && !(stop_char && *stop_char == '\0')) { fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val); return 1; /* failure */ } break; default: ; }; /* store the original value */ switch(arg_type) { case ARG_NO: case ARG_FLAG: break; default: if (value && orig_field) { if (no_free) { *orig_field = value; } else { if (*orig_field) free (*orig_field); /* free previous string */ *orig_field = gengetopt_strdup (value); } } }; return 0; /* OK */ } /** * @brief store information about a multiple option in a temporary list * @param list where to (temporarily) store multiple options */ static int update_multiple_arg_temp(struct generic_list **list, unsigned int *prev_given, const char *val, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, const char *long_opt, char short_opt, const char *additional_error) { /* store single arguments */ char *multi_token; const char *multi_next; if (arg_type == ARG_NO) { (*prev_given)++; return 0; /* OK */ } multi_token = get_multiple_arg_token(val); multi_next = get_multiple_arg_token_next (val); while (1) { add_node (list); if (update_arg((void *)&((*list)->arg), &((*list)->orig), 0, prev_given, multi_token, possible_values, default_value, arg_type, 0, 1, 1, 1, long_opt, short_opt, additional_error)) { if (multi_token) free(multi_token); return 1; /* failure */ } if (multi_next) { multi_token = get_multiple_arg_token(multi_next); multi_next = get_multiple_arg_token_next (multi_next); } else break; } return 0; /* OK */ } /** * @brief free the passed list (including possible string argument) */ static void free_list(struct generic_list *list, short string_arg) { if (list) { struct generic_list *tmp; while (list) { tmp = list; if (string_arg && list->arg.string_arg) free (list->arg.string_arg); if (list->orig) free (list->orig); list = list->next; free (tmp); } } } /** * @brief updates a multiple option starting from the passed list */ static void update_multiple_arg(void *field, char ***orig_field, unsigned int field_given, unsigned int prev_given, union generic_value *default_value, cmdline_parser_arg_type arg_type, struct generic_list *list) { int i; struct generic_list *tmp; if (prev_given && list) { *orig_field = (char **) realloc (*orig_field, (field_given + prev_given) * sizeof (char *)); switch(arg_type) { case ARG_INT: *((int **)field) = (int *)realloc (*((int **)field), (field_given + prev_given) * sizeof (int)); break; case ARG_STRING: *((char ***)field) = (char **)realloc (*((char ***)field), (field_given + prev_given) * sizeof (char *)); break; default: break; }; for (i = (prev_given - 1); i >= 0; --i) { tmp = list; switch(arg_type) { case ARG_INT: (*((int **)field))[i + field_given] = tmp->arg.int_arg; break; case ARG_STRING: (*((char ***)field))[i + field_given] = tmp->arg.string_arg; break; default: break; } (*orig_field) [i + field_given] = list->orig; list = list->next; free (tmp); } } else { /* set the default value */ if (default_value && ! field_given) { switch(arg_type) { case ARG_INT: if (! *((int **)field)) { *((int **)field) = (int *)malloc (sizeof (int)); (*((int **)field))[0] = default_value->int_arg; } break; case ARG_STRING: if (! *((char ***)field)) { *((char ***)field) = (char **)malloc (sizeof (char *)); (*((char ***)field))[0] = gengetopt_strdup(default_value->string_arg); } break; default: break; } if (!(*orig_field)) { *orig_field = (char **) malloc (sizeof (char *)); (*orig_field)[0] = 0; } } } } int cmdline_parser_internal ( int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error) { int c; /* Character of the parsed option. */ struct generic_list * connector_list = NULL; struct generic_list * device_pubkey_list = NULL; int error_occurred = 0; struct gengetopt_args_info local_args_info; int override; int initialize; int check_required; int check_ambiguity; package_name = argv[0]; /* TODO: Why is this here? It is not used anywhere. */ override = params->override; FIX_UNUSED(override); initialize = params->initialize; check_required = params->check_required; /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); cmdline_parser_init (&local_args_info); optarg = 0; optind = 0; opterr = params->print_errors; optopt = '?'; while (1) { int option_index = 0; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, { "config-file", 1, NULL, 0 }, { "connector", 1, NULL, 0 }, { "debug", 0, NULL, 0 }, { "dinout", 0, NULL, 0 }, { "libdebug", 0, NULL, 0 }, { "debug-file", 1, NULL, 0 }, { "cacert", 1, NULL, 0 }, { "cert", 1, NULL, 0 }, { "key", 1, NULL, 0 }, { "proxy", 1, NULL, 0 }, { "noproxy", 1, NULL, 0 }, { "timeout", 1, NULL, 0 }, { "device-pubkey", 1, NULL, 0 }, { 0, 0, 0, 0 } }; c = getopt_long (argc, argv, "hV", long_options, &option_index); if (c == -1) break; /* Exit from `while (1)' loop. */ switch (c) { case 'h': /* Print help and exit. */ cmdline_parser_print_help (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'V': /* Print version and exit. */ cmdline_parser_print_version (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 0: /* Long option with no short option */ /* Configuration file to read. */ if (strcmp (long_options[option_index].name, "config-file") == 0) { if (update_arg( (void *)&(args_info->config_file_arg), &(args_info->config_file_orig), &(args_info->config_file_given), &(local_args_info.config_file_given), optarg, 0, "./yubihsm_pkcs11.conf", ARG_STRING, check_ambiguity, override, 0, 0, "config-file", '-', additional_error)) goto failure; } /* List of connectors to use. */ else if (strcmp (long_options[option_index].name, "connector") == 0) { if (update_multiple_arg_temp(&connector_list, &(local_args_info.connector_given), optarg, 0, 0, ARG_STRING, "connector", '-', additional_error)) goto failure; } /* Enable pkcs11 debugging. */ else if (strcmp (long_options[option_index].name, "debug") == 0) { if (update_arg((void *)&(args_info->debug_flag), 0, &(args_info->debug_given), &(local_args_info.debug_given), optarg, 0, 0, ARG_FLAG, check_ambiguity, override, 1, 0, "debug", '-', additional_error)) goto failure; } /* Enable pkcs11 function tracing. */ else if (strcmp (long_options[option_index].name, "dinout") == 0) { if (update_arg((void *)&(args_info->dinout_flag), 0, &(args_info->dinout_given), &(local_args_info.dinout_given), optarg, 0, 0, ARG_FLAG, check_ambiguity, override, 1, 0, "dinout", '-', additional_error)) goto failure; } /* Enable libyubihsm debugging. */ else if (strcmp (long_options[option_index].name, "libdebug") == 0) { if (update_arg((void *)&(args_info->libdebug_flag), 0, &(args_info->libdebug_given), &(local_args_info.libdebug_given), optarg, 0, 0, ARG_FLAG, check_ambiguity, override, 1, 0, "libdebug", '-', additional_error)) goto failure; } /* Output file for debugging. */ else if (strcmp (long_options[option_index].name, "debug-file") == 0) { if (update_arg( (void *)&(args_info->debug_file_arg), &(args_info->debug_file_orig), &(args_info->debug_file_given), &(local_args_info.debug_file_given), optarg, 0, "stderr", ARG_STRING, check_ambiguity, override, 0, 0, "debug-file", '-', additional_error)) goto failure; } /* Cacert to use for HTTPS validation. */ else if (strcmp (long_options[option_index].name, "cacert") == 0) { if (update_arg( (void *)&(args_info->cacert_arg), &(args_info->cacert_orig), &(args_info->cacert_given), &(local_args_info.cacert_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "cacert", '-', additional_error)) goto failure; } /* HTTPS client certificate to authenticate with. */ else if (strcmp (long_options[option_index].name, "cert") == 0) { if (update_arg( (void *)&(args_info->cert_arg), &(args_info->cert_orig), &(args_info->cert_given), &(local_args_info.cert_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "cert", '-', additional_error)) goto failure; } /* HTTPS client certificate key. */ else if (strcmp (long_options[option_index].name, "key") == 0) { if (update_arg( (void *)&(args_info->key_arg), &(args_info->key_orig), &(args_info->key_given), &(local_args_info.key_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "key", '-', additional_error)) goto failure; } /* Proxy server to use for connector. */ else if (strcmp (long_options[option_index].name, "proxy") == 0) { if (update_arg( (void *)&(args_info->proxy_arg), &(args_info->proxy_orig), &(args_info->proxy_given), &(local_args_info.proxy_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "proxy", '-', additional_error)) goto failure; } /* Comma separated list of hosts ignore proxy for. */ else if (strcmp (long_options[option_index].name, "noproxy") == 0) { if (update_arg( (void *)&(args_info->noproxy_arg), &(args_info->noproxy_orig), &(args_info->noproxy_given), &(local_args_info.noproxy_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "noproxy", '-', additional_error)) goto failure; } /* Timeout to use for initial connection to connector. */ else if (strcmp (long_options[option_index].name, "timeout") == 0) { if (update_arg( (void *)&(args_info->timeout_arg), &(args_info->timeout_orig), &(args_info->timeout_given), &(local_args_info.timeout_given), optarg, 0, "5", ARG_INT, check_ambiguity, override, 0, 0, "timeout", '-', additional_error)) goto failure; } /* List of device public keys allowed for asymmetric authentication. */ else if (strcmp (long_options[option_index].name, "device-pubkey") == 0) { if (update_multiple_arg_temp(&device_pubkey_list, &(local_args_info.device_pubkey_given), optarg, 0, 0, ARG_STRING, "device-pubkey", '-', additional_error)) goto failure; } break; case '?': /* Invalid option. */ /* `getopt_long' already printed an error message. */ goto failure; default: /* bug: option not considered. */ fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); abort (); } /* switch */ } /* while */ update_multiple_arg((void *)&(args_info->connector_arg), &(args_info->connector_orig), args_info->connector_given, local_args_info.connector_given, 0, ARG_STRING, connector_list); update_multiple_arg((void *)&(args_info->device_pubkey_arg), &(args_info->device_pubkey_orig), args_info->device_pubkey_given, local_args_info.device_pubkey_given, 0, ARG_STRING, device_pubkey_list); args_info->connector_given += local_args_info.connector_given; local_args_info.connector_given = 0; args_info->device_pubkey_given += local_args_info.device_pubkey_given; local_args_info.device_pubkey_given = 0; if (check_required) { error_occurred += cmdline_parser_required2 (args_info, argv[0], additional_error); } cmdline_parser_release (&local_args_info); if ( error_occurred ) return (EXIT_FAILURE); return 0; failure: free_list (connector_list, 1 ); free_list (device_pubkey_list, 1 ); cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } #ifndef CONFIG_FILE_LINE_SIZE #define CONFIG_FILE_LINE_SIZE 2048 #endif #define ADDITIONAL_ERROR " in configuration file " #define CONFIG_FILE_LINE_BUFFER_SIZE (CONFIG_FILE_LINE_SIZE+3) /* 3 is for "--" and "=" */ static int _cmdline_parser_configfile (const char *filename, int *my_argc) { FILE* file; char my_argv[CONFIG_FILE_LINE_BUFFER_SIZE+1]; char linebuf[CONFIG_FILE_LINE_SIZE]; int line_num = 0; int result = 0, equal; char *fopt, *farg; char *str_index; size_t len, next_token; char delimiter; if ((file = fopen(filename, "r")) == 0) { fprintf (stderr, "%s: Error opening configuration file '%s'\n", CMDLINE_PARSER_PACKAGE, filename); return EXIT_FAILURE; } while ((fgets(linebuf, CONFIG_FILE_LINE_SIZE, file)) != 0) { ++line_num; my_argv[0] = '\0'; len = strlen(linebuf); if (len > (CONFIG_FILE_LINE_BUFFER_SIZE-1)) { fprintf (stderr, "%s:%s:%d: Line too long in configuration file\n", CMDLINE_PARSER_PACKAGE, filename, line_num); result = EXIT_FAILURE; break; } /* find first non-whitespace character in the line */ next_token = strspn (linebuf, " \t\r\n"); str_index = linebuf + next_token; if ( str_index[0] == '\0' || str_index[0] == '#') continue; /* empty line or comment line is skipped */ fopt = str_index; /* truncate fopt at the end of the first non-valid character */ next_token = strcspn (fopt, " \t\r\n="); if (fopt[next_token] == '\0') /* the line is over */ { farg = 0; equal = 0; goto noarg; } /* remember if equal sign is present */ equal = (fopt[next_token] == '='); fopt[next_token++] = '\0'; /* advance pointers to the next token after the end of fopt */ next_token += strspn (fopt + next_token, " \t\r\n"); /* check for the presence of equal sign, and if so, skip it */ if ( !equal ) if ((equal = (fopt[next_token] == '='))) { next_token++; next_token += strspn (fopt + next_token, " \t\r\n"); } str_index += next_token; /* find argument */ farg = str_index; if ( farg[0] == '\"' || farg[0] == '\'' ) { /* quoted argument */ str_index = strchr (++farg, str_index[0] ); /* skip opening quote */ if (! str_index) { fprintf (stderr, "%s:%s:%d: unterminated string in configuration file\n", CMDLINE_PARSER_PACKAGE, filename, line_num); result = EXIT_FAILURE; break; } } else { /* read up the remaining part up to a delimiter */ next_token = strcspn (farg, " \t\r\n#\'\""); str_index += next_token; } /* truncate farg at the delimiter and store it for further check */ delimiter = *str_index, *str_index++ = '\0'; /* everything but comment is illegal at the end of line */ if (delimiter != '\0' && delimiter != '#') { str_index += strspn(str_index, " \t\r\n"); if (*str_index != '\0' && *str_index != '#') { fprintf (stderr, "%s:%s:%d: malformed string in configuration file\n", CMDLINE_PARSER_PACKAGE, filename, line_num); result = EXIT_FAILURE; break; } } noarg: if (!strcmp(fopt,"include")) { if (farg && *farg) { result = _cmdline_parser_configfile(farg, my_argc); } else { fprintf(stderr, "%s:%s:%d: include requires a filename argument.\n", CMDLINE_PARSER_PACKAGE, filename, line_num); } continue; } len = strlen(fopt); strcat (my_argv, len > 1 ? "--" : "-"); strcat (my_argv, fopt); if (len > 1 && ((farg && *farg) || equal)) strcat (my_argv, "="); if (farg && *farg) strcat (my_argv, farg); ++(*my_argc); cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); cmd_line_list_tmp->next = cmd_line_list; cmd_line_list = cmd_line_list_tmp; cmd_line_list->string_arg = gengetopt_strdup(my_argv); } /* while */ if (file) fclose(file); return result; } int cmdline_parser_configfile ( const char *filename, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) { struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; return cmdline_parser_config_file (filename, args_info, ¶ms); } int cmdline_parser_config_file (const char *filename, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params) { int i, result; int my_argc = 1; char **my_argv_arg; char *additional_error; /* store the program name */ cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); cmd_line_list_tmp->next = cmd_line_list; cmd_line_list = cmd_line_list_tmp; cmd_line_list->string_arg = gengetopt_strdup (CMDLINE_PARSER_PACKAGE); result = _cmdline_parser_configfile(filename, &my_argc); if (result != EXIT_FAILURE) { my_argv_arg = (char **) malloc((my_argc+1) * sizeof(char *)); cmd_line_list_tmp = cmd_line_list; for (i = my_argc - 1; i >= 0; --i) { my_argv_arg[i] = cmd_line_list_tmp->string_arg; cmd_line_list_tmp = cmd_line_list_tmp->next; } my_argv_arg[my_argc] = 0; additional_error = (char *)malloc(strlen(filename) + strlen(ADDITIONAL_ERROR) + 1); strcpy (additional_error, ADDITIONAL_ERROR); strcat (additional_error, filename); result = cmdline_parser_internal (my_argc, my_argv_arg, args_info, params, additional_error); free (additional_error); free (my_argv_arg); } free_cmd_list(); return result; } static unsigned int cmdline_parser_create_argv(const char *cmdline_, char ***argv_ptr, const char *prog_name) { char *cmdline, *p; size_t n = 0, j; int i; if (prog_name) { cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); cmd_line_list_tmp->next = cmd_line_list; cmd_line_list = cmd_line_list_tmp; cmd_line_list->string_arg = gengetopt_strdup (prog_name); ++n; } cmdline = gengetopt_strdup(cmdline_); p = cmdline; while (p && strlen(p)) { j = strcspn(p, " \t"); ++n; if (j && j < strlen(p)) { p[j] = '\0'; cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); cmd_line_list_tmp->next = cmd_line_list; cmd_line_list = cmd_line_list_tmp; cmd_line_list->string_arg = gengetopt_strdup (p); p += (j+1); p += strspn(p, " \t"); } else { cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); cmd_line_list_tmp->next = cmd_line_list; cmd_line_list = cmd_line_list_tmp; cmd_line_list->string_arg = gengetopt_strdup (p); break; } } *argv_ptr = (char **) malloc((n + 1) * sizeof(char *)); cmd_line_list_tmp = cmd_line_list; for (i = (n-1); i >= 0; --i) { (*argv_ptr)[i] = cmd_line_list_tmp->string_arg; cmd_line_list_tmp = cmd_line_list_tmp->next; } (*argv_ptr)[n] = 0; free(cmdline); return n; } int cmdline_parser_string(const char *cmdline, struct gengetopt_args_info *args_info, const char *prog_name) { return cmdline_parser_string2(cmdline, args_info, prog_name, 0, 1, 1); } int cmdline_parser_string2(const char *cmdline, struct gengetopt_args_info *args_info, const char *prog_name, int override, int initialize, int check_required) { struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; return cmdline_parser_string_ext(cmdline, args_info, prog_name, ¶ms); } int cmdline_parser_string_ext(const char *cmdline, struct gengetopt_args_info *args_info, const char *prog_name, struct cmdline_parser_params *params) { char **argv_ptr = 0; int result; unsigned int argc; argc = cmdline_parser_create_argv(cmdline, &argv_ptr, prog_name); result = cmdline_parser_internal (argc, argv_ptr, args_info, params, 0); if (argv_ptr) { free (argv_ptr); } free_cmd_list(); return result; } /* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ yubihsm-shell-2.7.3/pkcs11/yubihsm_pkcs11.h0000644000175000017500000001375315167357110017422 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YUBIHSM_PKCS11_H #define YUBIHSM_PKCS11_H #include "pkcs11y.h" #include "list.h" #include #include "../common/platform-config.h" #include "../lib/internal.h" #ifndef _MSVC #include #endif #include #define YUBIHSM_PKCS11_OP_BUFSIZE 4096 #define MAX_ECDH_SESSION_KEYS 255 #define ECDH_KEY_BUF_SIZE 128 #define ECDH_KEY_TYPE 0x00FF #ifndef AES_BLOCK_SIZE #define AES_BLOCK_SIZE 16 #endif #define CKA_ATTRIBUTE_VALUE_SIZE 256 typedef enum { SESSION_RESERVED_RO = 1 << 0, SESSION_RESERVED_RW = 1 << 1, SESSION_AUTHENTICATED_RO = 1 << 2, SESSION_AUTHENTICATED_RW = 1 << 3, } yubihsm_pkcs11_session_state; #define SESSION_AUTHENTICATED \ (SESSION_AUTHENTICATED_RO | SESSION_AUTHENTICATED_RW) #define SESSION_NOT_AUTHENTICATED (SESSION_RESERVED_RO | SESSION_RESERVED_RW) typedef struct { uint16_t len; uint8_t value[CKA_ATTRIBUTE_VALUE_SIZE]; } cka_meta_item; typedef struct { /// Original objectID of the asymmetric key/certificate/symmetric key uint16_t target_id; /// Original object type yh_object_type target_type; /// Original object sequence uint8_t target_sequence; /// CKA_ID for private key cka_meta_item cka_id; /// CKA_LABEL for private key cka_meta_item cka_label; /// CKA_ID for public key cka_meta_item cka_id_pubkey; /// CKA_LABEL for public key cka_meta_item cka_label_pubkey; } pkcs11_meta_object; typedef struct { struct timeval tv; yh_object_descriptor object; pkcs11_meta_object meta_object; } yubihsm_pkcs11_object_desc; typedef enum { OPERATION_NOOP, OPERATION_FIND, OPERATION_GEN, OPERATION_SIGN, OPERATION_DIGEST, OPERATION_DECRYPT, OPERATION_VERIFY, OPERATION_ENCRYPT } yubihsm_pkcs11_op_type; typedef enum { PART_INIT, PART_SINGLE, PART_MULTIPLE, } yubihsm_pkcs11_part_type; typedef struct { yh_object_descriptor objects[YH_MAX_ITEMS_COUNT]; size_t current_object; size_t n_objects; bool only_private; } find_info; typedef struct { EVP_MD_CTX *md_ctx; // Digest context uint16_t key_id; // Key id CK_ULONG key_len; // Length in bits uint16_t sig_len; // Length in bytes } sign_info; typedef struct { EVP_MD_CTX *md_ctx; // Digest context CK_ULONG digest_len; // Length in bits } digest_info; typedef struct { uint16_t key_id; // Key id CK_ULONG key_len; // Length in bits bool finalized; } decrypt_info; typedef struct { uint16_t key_id; CK_ULONG key_len; // Length in bits CK_ULONG padding; // RSA padding, 0 for EC const EVP_MD *oaep_md; const EVP_MD *mgf1_md; unsigned char *oaep_label; CK_ULONG oaep_label_len; } encrypt_info; typedef struct { EVP_MD_CTX *md_ctx; // running hash const EVP_MD *md; // digest used int padding; // padding in the rsa case unsigned long saltLen; // saltlen for rsa-pss const EVP_MD *mgf1md; // mgf1 md used for rsa-pss uint16_t key_id; // Key id CK_ULONG key_len; // Length in bits } verify_info; typedef union { find_info find; sign_info sign; digest_info digest; verify_info verify; decrypt_info decrypt; encrypt_info encrypt; } op; typedef struct { CK_MECHANISM_TYPE mechanism; union { struct { uint8_t label[64]; // hash of OAEP label unsigned int label_len; // length of the hashed label yh_algorithm mgf1Algo; } oaep; struct { uint16_t salt_len; yh_algorithm mgf1Algo; } pss; struct { uint8_t iv[AES_BLOCK_SIZE]; uint8_t orig[AES_BLOCK_SIZE]; } cbc; }; } mechanism; typedef struct { // The session key ID 0x00 ff 0001, 0x00 ff 0002, 0x00 ff 0003...etc CK_OBJECT_HANDLE id; /// The key itself uint8_t ecdh_key[ECDH_KEY_BUF_SIZE]; /// The length of the key size_t len; /// Object label char label[YH_OBJ_LABEL_LEN + 1]; } ecdh_session_key; typedef struct { yubihsm_pkcs11_op_type type; yubihsm_pkcs11_part_type part; mechanism mechanism; op op; uint8_t buffer[YUBIHSM_PKCS11_OP_BUFSIZE]; unsigned int buffer_length; } yubihsm_pkcs11_op_info; typedef struct { List slots; List device_pubkeys; CK_CREATEMUTEX create_mutex; CK_DESTROYMUTEX destroy_mutex; CK_LOCKMUTEX lock_mutex; CK_UNLOCKMUTEX unlock_mutex; void *mutex; } yubihsm_pkcs11_context; typedef struct { uint16_t id; uint16_t authkey_domains; uint16_t max_session_id; char *connector_name; yh_connector *connector; yh_session *device_session; List pkcs11_sessions; yubihsm_pkcs11_object_desc objects[YH_MAX_ITEMS_COUNT]; void *mutex; } yubihsm_pkcs11_slot; typedef struct { uint16_t id; yubihsm_pkcs11_op_info operation; yubihsm_pkcs11_session_state session_state; yubihsm_pkcs11_slot *slot; List ecdh_session_keys; } yubihsm_pkcs11_session; typedef enum { ATTRIBUTE_NOT_SET = 0, ATTRIBUTE_FALSE, ATTRIBUTE_TRUE, } yubihsm_pkcs11_attribute; typedef struct { yh_algorithm algorithm; uint16_t id; char label[YH_OBJ_LABEL_LEN + 1]; yubihsm_pkcs11_attribute sign; yubihsm_pkcs11_attribute encrypt; yubihsm_pkcs11_attribute decrypt; yubihsm_pkcs11_attribute derive; yubihsm_pkcs11_attribute exportable; yubihsm_pkcs11_attribute verify; yubihsm_pkcs11_attribute wrap; yubihsm_pkcs11_attribute unwrap; uint16_t objlen; union { struct { BIGNUM *p; BIGNUM *q; } rsa; struct { BIGNUM *d; } ec; uint8_t *buf; } obj; } yubihsm_pkcs11_object_template; #ifdef _MSC_VER #pragma strict_gs_check(on) #endif #endif yubihsm-shell-2.7.3/pkcs11/pkcs11y.h0000644000175000017500000000515415167357110016047 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PKCS11Y_H #define PKCS11Y_H #include #ifdef CRYPTOKI_EXPORTS #ifdef _WIN32 #define CK_SPEC __declspec(dllexport) #else #define CK_SPEC __attribute__((visibility("default"))) #endif #else #define CK_SPEC #endif #ifndef NULL_PTR #define NULL_PTR 0 #endif #define CRYPTOKI_LEGACY_VERSION_MAJOR 2 #define CRYPTOKI_LEGACY_VERSION_MINOR 40 #define CK_PTR * #define CK_BOOL bool #define CK_HANDLE void * #define CK_DECLARE_FUNCTION(returnType, name) returnType CK_SPEC name #define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType(*name) #define CK_CALLBACK_FUNCTION(returnType, name) returnType(*name) #define CK_DEFINE_FUNCTION(returnType, name) returnType CK_SPEC name #ifdef _WIN32 #pragma pack(push, cryptoki, 1) #endif #ifdef __cplusplus extern "C" { #endif #include "pkcs11.h" #ifdef __cplusplus } #endif #ifdef _WIN32 #pragma pack(pop, cryptoki) #endif /* This is an offset for the vendor definitions to avoid clashes */ #define YUBICO_BASE_VENDOR 0x59554200 #define CKK_YUBICO_AES128_CCM_WRAP \ (CKK_VENDOR_DEFINED | YUBICO_BASE_VENDOR | YH_ALGO_AES128_CCM_WRAP) #define CKK_YUBICO_AES192_CCM_WRAP \ (CKK_VENDOR_DEFINED | YUBICO_BASE_VENDOR | YH_ALGO_AES192_CCM_WRAP) #define CKK_YUBICO_AES256_CCM_WRAP \ (CKK_VENDOR_DEFINED | YUBICO_BASE_VENDOR | YH_ALGO_AES256_CCM_WRAP) #define CKM_YUBICO_AES_CCM_WRAP \ (CKM_VENDOR_DEFINED | YUBICO_BASE_VENDOR | YH_WRAP_KEY) /* CKM_YUBICO_AES_CCM_WRAP_PARAMS provides the parameters to the * CKM_YUBICO_AES_CCM_WRAP mechanism. */ typedef struct CKM_YUBICO_AES_CCM_WRAP_PARAMS { CK_ULONG format; // 0 = legacy, 1 = ED keys with seed } CKM_YUBICO_AES_CCM_WRAP_PARAMS; typedef CKM_YUBICO_AES_CCM_WRAP_PARAMS CK_PTR CKM_YUBICO_AES_CCM_WRAP_PARAMS_PTR; #define CKM_YUBICO_RSA_WRAP \ (CKM_VENDOR_DEFINED | YUBICO_BASE_VENDOR | YH_PUBLIC_WRAP_KEY) #endif yubihsm-shell-2.7.3/pkcs11/pkcs11.h0000644000175000017500000001657515167357110015667 0ustar aveenaveen/* * PKCS #11 Specification Version 3.1 * Committee Specification Draft 01 * 16 February 2022 * Copyright (c) OASIS Open 2022. All Rights Reserved. * Source: * https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/csd01/include/pkcs11-v3.1/ * Latest stage of narrative specification: * https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html TC * IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php */ /* Copyright (c) OASIS Open 2016,2019. All Rights Reserved./ * /Distributed under the terms of the OASIS IPR Policy, * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others. */ /* Latest version of the specification: * http://docs.oasis-open.org/pkcs11/pkcs11-base/v3.0/pkcs11-base-v3.0.html */ #ifndef _PKCS11_H_ #define _PKCS11_H_ 1 #ifdef __cplusplus extern "C" { #endif /* Before including this file (pkcs11.h) (or pkcs11t.h by * itself), 5 platform-specific macros must be defined. These * macros are described below, and typical definitions for them * are also given. Be advised that these definitions can depend * on both the platform and the compiler used (and possibly also * on whether a Cryptoki library is linked statically or * dynamically). * * In addition to defining these 5 macros, the packing convention * for Cryptoki structures should be set. The Cryptoki * convention on packing is that structures should be 1-byte * aligned. * * If you're using Windows this might be done by using the following * preprocessor directive before including pkcs11.h or pkcs11t.h: * * #pragma pack(push, cryptoki, 1) * * and using the following preprocessor directive after including * pkcs11.h or pkcs11t.h: * * #pragma pack(pop, cryptoki) * * In a UNIX environment, you're on your own for this. You might * not need to do (or be able to do!) anything. * * * Now for the macros: * * * 1. CK_PTR: The indirection string for making a pointer to an * object. It can be used like this: * * typedef CK_BYTE CK_PTR CK_BYTE_PTR; * * If you're using Windows, it might be defined by: * * #define CK_PTR * * * In a typical UNIX environment, it might be defined by: * * #define CK_PTR * * * * 2. CK_DECLARE_FUNCTION(returnType, name): A macro which makes * an importable Cryptoki library function declaration out of a * return type and a function name. It should be used in the * following fashion: * * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)( * CK_VOID_PTR pReserved * ); * * If you're using Windows to declare a function in a Win32 Cryptoki .dll, * it might be defined by: * * #define CK_DECLARE_FUNCTION(returnType, name) \ * returnType __declspec(dllimport) name * * In a UNIX environment, it might be defined by: * * #define CK_DECLARE_FUNCTION(returnType, name) \ * returnType name * * * 3. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro * which makes a Cryptoki API function pointer declaration or * function pointer type declaration out of a return type and a * function name. It should be used in the following fashion: * * // Define funcPtr to be a pointer to a Cryptoki API function * // taking arguments args and returning CK_RV. * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args); * * or * * // Define funcPtrType to be the type of a pointer to a * // Cryptoki API function taking arguments args and returning * // CK_RV, and then define funcPtr to be a variable of type * // funcPtrType. * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args); * funcPtrType funcPtr; * * If you're using Windows to access * functions in a Win32 Cryptoki .dll, in might be defined by: * * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ * returnType __declspec(dllimport) (* name) * * In a UNIX environment, it might be defined by: * * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ * returnType (* name) * * * 4. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes * a function pointer type for an application callback out of * a return type for the callback and a name for the callback. * It should be used in the following fashion: * * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args); * * to declare a function pointer, myCallback, to a callback * which takes arguments args and returns a CK_RV. It can also * be used like this: * * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args); * myCallbackType myCallback; * * If you're using Windows, it might be defined by: * * #define CK_CALLBACK_FUNCTION(returnType, name) \ * returnType (* name) * * In a UNIX environment, it might be defined by: * * #define CK_CALLBACK_FUNCTION(returnType, name) \ * returnType (* name) * * * 5. NULL_PTR: This macro is the value of a NULL pointer. * * In any ANSI/ISO C environment (and in many others as well), * this should best be defined by * * #ifndef NULL_PTR * #define NULL_PTR 0 * #endif */ /* All the various Cryptoki types and #define'd values are in the * file pkcs11t.h. */ #include "pkcs11t.h" #define __PASTE(x, y) x##y /* ============================================================== * Define the "extern" form of all the entry points. * ============================================================== */ #define CK_NEED_ARG_LIST 1 #define CK_PKCS11_FUNCTION_INFO(name) extern CK_DECLARE_FUNCTION(CK_RV, name) /* pkcs11f.h has all the information about the Cryptoki * function prototypes. */ #include "pkcs11f.h" #undef CK_NEED_ARG_LIST #undef CK_PKCS11_FUNCTION_INFO /* ============================================================== * Define the typedef form of all the entry points. That is, for * each Cryptoki function C_XXX, define a type CK_C_XXX which is * a pointer to that kind of function. * ============================================================== */ #define CK_NEED_ARG_LIST 1 #define CK_PKCS11_FUNCTION_INFO(name) \ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_, name)) /* pkcs11f.h has all the information about the Cryptoki * function prototypes. */ #include "pkcs11f.h" #undef CK_NEED_ARG_LIST #undef CK_PKCS11_FUNCTION_INFO /* ============================================================== * Define structed vector of entry points. A CK_FUNCTION_LIST * contains a CK_VERSION indicating a library's Cryptoki version * and then a whole slew of function pointers to the routines in * the library. This type was declared, but not defined, in * pkcs11t.h. * ============================================================== */ #define CK_PKCS11_FUNCTION_INFO(name) __PASTE(CK_, name) name; /* Create the 3.0 Function list */ struct CK_FUNCTION_LIST_3_0 { CK_VERSION version; /* Cryptoki version */ /* Pile all the function pointers into the CK_FUNCTION_LIST. */ /* pkcs11f.h has all the information about the Cryptoki * function prototypes. */ #include "pkcs11f.h" }; #define CK_PKCS11_2_0_ONLY 1 /* Continue to define the old CK_FUNCTION_LIST */ struct CK_FUNCTION_LIST { CK_VERSION version; /* Cryptoki version */ /* Pile all the function pointers into the CK_FUNCTION_LIST. */ /* pkcs11f.h has all the information about the Cryptoki * function prototypes. */ #include "pkcs11f.h" }; #undef CK_PKCS11_FUNCTION_INFO #undef CK_PKCS11_2_0_ONLY #undef __PASTE #ifdef __cplusplus } #endif #endif /* _PKCS11_H_ */ yubihsm-shell-2.7.3/cmake/0000755000175000017500000000000015167357110014354 5ustar aveenaveenyubihsm-shell-2.7.3/cmake/gengetopt.cmake0000644000175000017500000000153515167357110017356 0ustar aveenaveenmacro (find_gengetopt) if (NOT GENGETOPT_EXECUTABLE) find_program (GENGETOPT_EXECUTABLE gengetopt) if (NOT GENGETOPT_EXECUTABLE) message (FATAL_ERROR "gengetopt not found. Aborting...") endif () endif () endmacro () macro (add_gengetopt_files _basename) find_gengetopt () set (_ggo_extra_input ${ARGV}) set (_ggo_c ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.c) set (_ggo_h ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.h) set (_ggo_g ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.ggo) add_custom_command ( OUTPUT ${_ggo_c} ${_ggo_h} COMMAND gengetopt ${_ggo_extra_input} -i ${_ggo_g} --output-dir ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${_ggo_g} # BYPRODUCTS COMMENT "Generating getopt parser code (cmdline.{h,c}) ..." VERBATIM ) set (GGO_C ${_ggo_c}) set (GGO_H ${_ggo_h}) endmacro (add_gengetopt_files) yubihsm-shell-2.7.3/cmake/Fuzzing.cmake0000644000175000017500000000220415167357110017010 0ustar aveenaveenoption(FUZZING "Compile binaries with fuzzing instrumentation" OFF) option(LIBFUZZER_ASAN "Enable ASAN instrumentation with libfuzzer" OFF) option(FUZZING_MSAN "Compile binaries with MemorySanitizer instrumentation" OFF) if (FUZZING) message(STATUS "Building with fuzzing instrumentation.") string (APPEND CMAKE_C_FLAGS " -DFUZZING") string (APPEND CMAKE_C_FLAGS " -fno-omit-frame-pointer -O1 -g") string (APPEND CMAKE_CXX_FLAGS " -std=c++17") string (APPEND CMAKE_CXX_FLAGS " -DFUZZING") string (APPEND CMAKE_CXX_FLAGS " -fno-omit-frame-pointer -O1 -g") string (APPEND CMAKE_EXE_LINKER_FLAGS " -g") if (FUZZING_MSAN) string (APPEND CMAKE_C_FLAGS " -fsanitize=memory") string (APPEND CMAKE_CXX_FLAGS " -fsanitize=memory") string (APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=memory") else (FUZZING_MSAN) string (APPEND CMAKE_C_FLAGS " -fsanitize=address -fsanitize=undefined") string (APPEND CMAKE_CXX_FLAGS " -fsanitize=address -fsanitize=undefined") string (APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=address -fsanitize=undefined") endif (FUZZING_MSAN) endif () yubihsm-shell-2.7.3/cmake/cppcheck.cmake0000644000175000017500000000265515167357110017146 0ustar aveenaveenmacro (add_cppcheck_target _cc_target _cc_directories _cc_ignore) set(_cc_directories_var ${_cc_directories}) string (REPLACE " " " ${CMAKE_CURRENT_SOURCE_DIR}/" _cc_abs_directories ${_cc_directories_var}) set (_cc_abs_directories "${CMAKE_CURRENT_SOURCE_DIR}/${_cc_abs_directories}") separate_arguments (xxx UNIX_COMMAND "${_cc_abs_directories}") if (_cc_ignore STREQUAL "") string (REPLACE " " "${CMAKE_CURRENT_SOURCE_DIR}/" _cc_abs_ignore ${_cc_ignore}) set (_cc_abs_ignore ";${CMAKE_CURRENT_SOURCE_DIR}/${_cc_abs_ignore}") endif () set (_cc_extra_input "${ARGV3}") message ("Replaced ?${_cc_abs_directories}?") message ("Replaxxx ?${xxx}?") list (LENGTH _cc_abs_directories bla) message ("ignored ${_cc_abs_ignore} length is ${bla}") file(GLOB_RECURSE ALL_SOURCE_FILES *.c *.h) #message (${ALL_SOURCE_FILES}) # # set (_ignore_arg "--ignore ${_ignore}") #else () # set (_ignore_arg "set ${_ignore}") #endif () #list (APPEND _cpp_remove_list "") #list (APPEND _cpp_remove_list ) #set (_ggo_extra_input ${ARGV1}) add_custom_target ( ${_cc_target} COMMAND cppcheck --enable=all --template="[{severity}][{id}] {message} {callstack} \(On {file}:{line}\)" --suppress="unusedStructMember" -i="${_cc_abs_ignore}" --verbose --quiet ${_cc_extra_input} #"${_cc_abs_directories}" ${CMAKE_SOURCE_DIR} #"${xxx}" #VERBATIM ) endmacro(add_cppcheck_target) yubihsm-shell-2.7.3/cmake/Findcodecov.cmake0000644000175000017500000002034315167357110017603 0ustar aveenaveen# This file is part of CMake-codecov. # # Copyright (c) # 2015-2017 RWTH Aachen University, Federal Republic of Germany # # See the LICENSE file in the package base directory for details # # Written by Alexander Haase, alexander.haase@rwth-aachen.de # # Add an option to choose, if coverage should be enabled or not. If enabled # marked targets will be build with coverage support and appropriate targets # will be added. If disabled coverage will be ignored for *ALL* targets. option(ENABLE_COVERAGE "Enable coverage build." OFF) set(COVERAGE_FLAG_CANDIDATES # gcc and clang "-O0 -g -fprofile-arcs -ftest-coverage" # gcc and clang fallback "-O0 -g --coverage" ) # Add coverage support for target ${TNAME} and register target for coverage # evaluation. If coverage is disabled or not supported, this function will # simply do nothing. # # Note: This function is only a wrapper to define this function always, even if # coverage is not supported by the compiler or disabled. This function must # be defined here, because the module will be exited, if there is no coverage # support by the compiler or it is disabled by the user. function (add_coverage TNAME) # only add coverage for target, if coverage is support and enabled. if (ENABLE_COVERAGE) foreach (TNAME ${ARGV}) add_coverage_target(${TNAME}) endforeach () endif () endfunction (add_coverage) # Add global target to gather coverage information after all targets have been # added. Other evaluation functions could be added here, after checks for the # specific module have been passed. # # Note: This function is only a wrapper to define this function always, even if # coverage is not supported by the compiler or disabled. This function must # be defined here, because the module will be exited, if there is no coverage # support by the compiler or it is disabled by the user. function (coverage_evaluate) # add lcov evaluation if (LCOV_FOUND) lcov_capture_initial() lcov_capture() endif (LCOV_FOUND) endfunction () # Exit this module, if coverage is disabled. add_coverage is defined before this # return, so this module can be exited now safely without breaking any build- # scripts. if (NOT ENABLE_COVERAGE) return() endif () # Find the reuired flags foreach language. set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) foreach (LANG ${ENABLED_LANGUAGES}) # Coverage flags are not dependend on language, but the used compiler. So # instead of searching flags foreach language, search flags foreach compiler # used. set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) if (NOT COVERAGE_${COMPILER}_FLAGS) foreach (FLAG ${COVERAGE_FLAG_CANDIDATES}) if(NOT CMAKE_REQUIRED_QUIET) message(STATUS "Try ${COMPILER} code coverage flag = [${FLAG}]") endif() set(CMAKE_REQUIRED_FLAGS "${FLAG}") unset(COVERAGE_FLAG_DETECTED CACHE) if (${LANG} STREQUAL "C") include(CheckCCompilerFlag) check_c_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) elseif (${LANG} STREQUAL "CXX") include(CheckCXXCompilerFlag) check_cxx_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) elseif (${LANG} STREQUAL "Fortran") # CheckFortranCompilerFlag was introduced in CMake 3.x. To be # compatible with older Cmake versions, we will check if this # module is present before we use it. Otherwise we will define # Fortran coverage support as not available. include(CheckFortranCompilerFlag OPTIONAL RESULT_VARIABLE INCLUDED) if (INCLUDED) check_fortran_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) elseif (NOT CMAKE_REQUIRED_QUIET) message("-- Performing Test COVERAGE_FLAG_DETECTED") message("-- Performing Test COVERAGE_FLAG_DETECTED - Failed" " (Check not supported)") endif () endif() if (COVERAGE_FLAG_DETECTED) set(COVERAGE_${COMPILER}_FLAGS "${FLAG}" CACHE STRING "${COMPILER} flags for code coverage.") mark_as_advanced(COVERAGE_${COMPILER}_FLAGS) break() else () message(WARNING "Code coverage is not available for ${COMPILER}" " compiler. Targets using this compiler will be " "compiled without it.") endif () endforeach () endif () endforeach () set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) # Helper function to get the language of a source file. function (codecov_lang_of_source FILE RETURN_VAR) get_filename_component(FILE_EXT "${FILE}" EXT) string(TOLOWER "${FILE_EXT}" FILE_EXT) string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) foreach (LANG ${ENABLED_LANGUAGES}) list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) if (NOT ${TEMP} EQUAL -1) set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) return() endif () endforeach() set(${RETURN_VAR} "" PARENT_SCOPE) endfunction () # Helper function to get the relative path of the source file destination path. # This path is needed by FindGcov and FindLcov cmake files to locate the # captured data. function (codecov_path_of_source FILE RETURN_VAR) string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _source ${FILE}) # If expression was found, SOURCEFILE is a generator-expression for an # object library. Currently we found no way to call this function automatic # for the referenced target, so it must be called in the directoryso of the # object library definition. if (NOT "${_source}" STREQUAL "") set(${RETURN_VAR} "" PARENT_SCOPE) return() endif () string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" FILE "${FILE}") if(IS_ABSOLUTE ${FILE}) file(RELATIVE_PATH FILE ${CMAKE_CURRENT_SOURCE_DIR} ${FILE}) endif() # get the right path for file string(REPLACE ".." "__" PATH "${FILE}") set(${RETURN_VAR} "${PATH}" PARENT_SCOPE) endfunction() # Add coverage support for target ${TNAME} and register target for coverage # evaluation. function(add_coverage_target TNAME) # Check if all sources for target use the same compiler. If a target uses # e.g. C and Fortran mixed and uses different compilers (e.g. clang and # gfortran) this can trigger huge problems, because different compilers may # use different implementations for code coverage. get_target_property(TSOURCES ${TNAME} SOURCES) set(TARGET_COMPILER "") set(ADDITIONAL_FILES "") foreach (FILE ${TSOURCES}) # If expression was found, FILE is a generator-expression for an object # library. Object libraries will be ignored. string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) if ("${_file}" STREQUAL "") codecov_lang_of_source(${FILE} LANG) if (LANG) list(APPEND TARGET_COMPILER ${CMAKE_${LANG}_COMPILER_ID}) list(APPEND ADDITIONAL_FILES "${FILE}.gcno") list(APPEND ADDITIONAL_FILES "${FILE}.gcda") endif () endif () endforeach () list(REMOVE_DUPLICATES TARGET_COMPILER) list(LENGTH TARGET_COMPILER NUM_COMPILERS) if (NUM_COMPILERS GREATER 1) message(WARNING "Can't use code coverage for target ${TNAME}, because " "it will be compiled by incompatible compilers. Target will be " "compiled without code coverage.") return() elseif (NUM_COMPILERS EQUAL 0) message(WARNING "Can't use code coverage for target ${TNAME}, because " "it uses an unknown compiler. Target will be compiled without " "code coverage.") return() elseif (NOT DEFINED "COVERAGE_${TARGET_COMPILER}_FLAGS") # A warning has been printed before, so just return if flags for this # compiler aren't available. return() endif() # enable coverage for target set_property(TARGET ${TNAME} APPEND_STRING PROPERTY COMPILE_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") set_property(TARGET ${TNAME} APPEND_STRING PROPERTY LINK_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") # Add gcov files generated by compiler to clean target. set(CLEAN_FILES "") foreach (FILE ${ADDITIONAL_FILES}) codecov_path_of_source(${FILE} FILE) list(APPEND CLEAN_FILES "CMakeFiles/${TNAME}.dir/${FILE}") endforeach() set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CLEAN_FILES}") add_gcov_target(${TNAME}) add_lcov_target(${TNAME}) endfunction(add_coverage_target) # Include modules for parsing the collected data and output it in a readable # format (like gcov and lcov). find_package(Gcov) find_package(Lcov) yubihsm-shell-2.7.3/cmake/FindGcov.cmake0000644000175000017500000001173615167357110017065 0ustar aveenaveen# This file is part of CMake-codecov. # # Copyright (c) # 2015-2017 RWTH Aachen University, Federal Republic of Germany # # See the LICENSE file in the package base directory for details # # Written by Alexander Haase, alexander.haase@rwth-aachen.de # # include required Modules include(FindPackageHandleStandardArgs) # Search for gcov binary. set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) foreach (LANG ${ENABLED_LANGUAGES}) # Gcov evaluation is dependend on the used compiler. Check gcov support for # each compiler that is used. If gcov binary was already found for this # compiler, do not try to find it again. if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN) get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH) if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU") # Some distributions like OSX (homebrew) ship gcov with the compiler # version appended as gcov-x. To find this binary we'll build the # suggested binary name with the compiler version. string(REGEX MATCH "^[0-9]+" GCC_VERSION "${CMAKE_${LANG}_COMPILER_VERSION}") find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov HINTS ${COMPILER_PATH}) elseif ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Clang") # Some distributions like Debian ship llvm-cov with the compiler # version appended as llvm-cov-x.y. To find this binary we'll build # the suggested binary name with the compiler version. string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION "${CMAKE_${LANG}_COMPILER_VERSION}") # llvm-cov prior version 3.5 seems to be not working with coverage # evaluation tools, but these versions are compatible with the gcc # gcov tool. if(LLVM_VERSION VERSION_GREATER 3.4) find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}" "llvm-cov" HINTS ${COMPILER_PATH}) mark_as_advanced(LLVM_COV_BIN) if (LLVM_COV_BIN) find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS ${CMAKE_MODULE_PATH}) if (LLVM_COV_WRAPPER) set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "") # set additional parameters set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV "LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING "Environment variables for llvm-cov-wrapper.") mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV) endif () endif () endif () if (NOT GCOV_BIN) # Fall back to gcov binary if llvm-cov was not found or is # incompatible. This is the default on OSX, but may crash on # recent Linux versions. find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH}) endif () endif () if (GCOV_BIN) set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING "${LANG} gcov binary.") if (NOT CMAKE_REQUIRED_QUIET) message("-- Found gcov evaluation for " "${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}") endif() unset(GCOV_BIN CACHE) endif () endif () endforeach () # Add a new global target for all gcov targets. This target could be used to # generate the gcov files for the whole project instead of calling -gcov # for each target. if (NOT TARGET gcov) add_custom_target(gcov) endif (NOT TARGET gcov) # This function will add gcov evaluation for target . Only sources of # this target will be evaluated and no dependencies will be added. It will call # Gcov on any source file of once and store the gcov file in the same # directory. function (add_gcov_target TNAME) set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) # We don't have to check, if the target has support for coverage, thus this # will be checked by add_coverage_target in Findcoverage.cmake. Instead we # have to determine which gcov binary to use. get_target_property(TSOURCES ${TNAME} SOURCES) set(SOURCES "") set(TCOMPILER "") foreach (FILE ${TSOURCES}) codecov_path_of_source(${FILE} FILE) if (NOT "${FILE}" STREQUAL "") codecov_lang_of_source(${FILE} LANG) if (NOT "${LANG}" STREQUAL "") list(APPEND SOURCES "${FILE}") set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) endif () endif () endforeach () # If no gcov binary was found, coverage data can't be evaluated. if (NOT GCOV_${TCOMPILER}_BIN) message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") return() endif () set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") set(BUFFER "") foreach(FILE ${SOURCES}) get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH) # call gcov add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov COMMAND ${GCOV_ENV} ${GCOV_BIN} ${TDIR}/${FILE}.gcno > /dev/null DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno WORKING_DIRECTORY ${FILE_PATH} ) list(APPEND BUFFER ${TDIR}/${FILE}.gcov) endforeach() # add target for gcov evaluation of add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER}) # add evaluation target to the global gcov target. add_dependencies(gcov ${TNAME}-gcov) endfunction (add_gcov_target) yubihsm-shell-2.7.3/cmake/mingw32.cmake0000644000175000017500000000117315167357110016646 0ustar aveenaveen# the name of the target operating system SET(CMAKE_SYSTEM_NAME Windows) # which compilers to use for C and C++ SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc) SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres) # here is the target environment located SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32 ) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) yubihsm-shell-2.7.3/cmake/mingw64.cmake0000644000175000017500000000120315167357110016645 0ustar aveenaveen# the name of the target operating system SET(CMAKE_SYSTEM_NAME Windows) # which compilers to use for C and C++ SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) # here is the target environment located SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32 ) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) yubihsm-shell-2.7.3/cmake/help2man.cmake0000644000175000017500000000066115167357110017067 0ustar aveenaveenfind_program (HELP2MAN_LOCATION help2man) IF (NOT HELP2MAN_LOCATION) message (FATAL_ERROR "Cannot find help2man. Please install it.") ENDIF () MACRO (add_help2man_manpage file command) add_custom_command (OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${file} COMMAND ${HELP2MAN_LOCATION} ARGS -s1 -N -o ${CMAKE_CURRENT_BINARY_DIR}/${file} ./${command} DEPENDS ${command} COMMENT "Building manpage for ${command}") ENDMACRO () yubihsm-shell-2.7.3/cmake/FindLcov.cmake0000644000175000017500000003005015167357110017060 0ustar aveenaveen# This file is part of CMake-codecov. # # Copyright (c) # 2015-2017 RWTH Aachen University, Federal Republic of Germany # # See the LICENSE file in the package base directory for details # # Written by Alexander Haase, alexander.haase@rwth-aachen.de # # configuration set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data") set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init") set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture") set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html") # Search for Gcov which is used by Lcov. find_package(Gcov) # This function will add lcov evaluation for target . Only sources of # this target will be evaluated and no dependencies will be added. It will call # geninfo on any source file of once and store the info file in the same # directory. # # Note: This function is only a wrapper to define this function always, even if # coverage is not supported by the compiler or disabled. This function must # be defined here, because the module will be exited, if there is no coverage # support by the compiler or it is disabled by the user. function (add_lcov_target TNAME) if (LCOV_FOUND) # capture initial coverage data lcov_capture_initial_tgt(${TNAME}) # capture coverage data after execution lcov_capture_tgt(${TNAME}) endif () endfunction (add_lcov_target) # include required Modules include(FindPackageHandleStandardArgs) # Search for required lcov binaries. find_program(LCOV_BIN lcov) find_program(GENINFO_BIN geninfo) find_program(GENHTML_BIN genhtml) find_package_handle_standard_args(lcov REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN ) # enable genhtml C++ demangeling, if c++filt is found. set(GENHTML_CPPFILT_FLAG "") find_program(CPPFILT_BIN c++filt) if (NOT CPPFILT_BIN STREQUAL "") set(GENHTML_CPPFILT_FLAG "--demangle-cpp") endif (NOT CPPFILT_BIN STREQUAL "") # enable no-external flag for lcov, if available. if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG) set(FLAG "") execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP) string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}") if (GENINFO_RES) set(FLAG "--no-external") endif () set(GENINFO_EXTERN_FLAG "${FLAG}" CACHE STRING "Geninfo flag to exclude system sources.") endif () # If Lcov was not found, exit module now. if (NOT LCOV_FOUND) return() endif (NOT LCOV_FOUND) # Create directories to be used. file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT}) file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE}) set(LCOV_REMOVE_PATTERNS "") # This function will merge lcov files to a single target file. Additional lcov # flags may be set with setting LCOV_EXTRA_FLAGS before calling this function. function (lcov_merge_files OUTFILE ...) # Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files. list(REMOVE_AT ARGV 0) # Generate merged file. string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}") add_custom_command(OUTPUT "${OUTFILE}.raw" COMMAND cat ${ARGV} > ${OUTFILE}.raw DEPENDS ${ARGV} COMMENT "Generating ${FILE_REL}" ) add_custom_command(OUTPUT "${OUTFILE}" COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE} --base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS} COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS} --output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS} DEPENDS ${OUTFILE}.raw COMMENT "Post-processing ${FILE_REL}" ) endfunction () # Add a new global target to generate initial coverage reports for all targets. # This target will be used to generate the global initial info file, which is # used to gather even empty report data. if (NOT TARGET lcov-capture-init) add_custom_target(lcov-capture-init) set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "") endif (NOT TARGET lcov-capture-init) # This function will add initial capture of coverage data for target , # which is needed to get also data for objects, which were not loaded at # execution time. It will call geninfo for every source file of once and # store the info file in the same directory. function (lcov_capture_initial_tgt TNAME) # We don't have to check, if the target has support for coverage, thus this # will be checked by add_coverage_target in Findcoverage.cmake. Instead we # have to determine which gcov binary to use. get_target_property(TSOURCES ${TNAME} SOURCES) set(SOURCES "") set(TCOMPILER "") foreach (FILE ${TSOURCES}) codecov_path_of_source(${FILE} FILE) if (NOT "${FILE}" STREQUAL "") codecov_lang_of_source(${FILE} LANG) if (NOT "${LANG}" STREQUAL "") list(APPEND SOURCES "${FILE}") set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) endif () endif () endforeach () # If no gcov binary was found, coverage data can't be evaluated. if (NOT GCOV_${TCOMPILER}_BIN) message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") return() endif () set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) set(GENINFO_FILES "") foreach(FILE ${SOURCES}) # generate empty coverage files set(OUTFILE "${TDIR}/${FILE}.info.init") list(APPEND GENINFO_FILES ${OUTFILE}) add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory ${PROJECT_SOURCE_DIR} --initial --gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno DEPENDS ${TNAME} COMMENT "Capturing initial coverage data for ${FILE}" ) endforeach() # Concatenate all files generated by geninfo to a single file per target. set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info") set(LCOV_EXTRA_FLAGS "--initial") lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE}) # add geninfo file generation to global lcov-geninfo target add_dependencies(lcov-capture-init ${TNAME}-capture-init) set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}" "${OUTFILE}" CACHE INTERNAL "" ) endfunction (lcov_capture_initial_tgt) # This function will generate the global info file for all targets. It has to be # called after all other CMake functions in the root CMakeLists.txt file, to get # a full list of all targets that generate coverage data. function (lcov_capture_initial) # Skip this function (and do not create the following targets), if there are # no input files. if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "") return() endif () # Add a new target to merge the files of all targets. set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info") lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES}) add_custom_target(lcov-geninfo-init ALL DEPENDS ${OUTFILE} lcov-capture-init ) endfunction (lcov_capture_initial) # Add a new global target to generate coverage reports for all targets. This # target will be used to generate the global info file. if (NOT TARGET lcov-capture) add_custom_target(lcov-capture) set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "") endif (NOT TARGET lcov-capture) # This function will add capture of coverage data for target , which is # needed to get also data for objects, which were not loaded at execution time. # It will call geninfo for every source file of once and store the info # file in the same directory. function (lcov_capture_tgt TNAME) # We don't have to check, if the target has support for coverage, thus this # will be checked by add_coverage_target in Findcoverage.cmake. Instead we # have to determine which gcov binary to use. get_target_property(TSOURCES ${TNAME} SOURCES) set(SOURCES "") set(TCOMPILER "") foreach (FILE ${TSOURCES}) codecov_path_of_source(${FILE} FILE) if (NOT "${FILE}" STREQUAL "") codecov_lang_of_source(${FILE} LANG) if (NOT "${LANG}" STREQUAL "") list(APPEND SOURCES "${FILE}") set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) endif () endif () endforeach () # If no gcov binary was found, coverage data can't be evaluated. if (NOT GCOV_${TCOMPILER}_BIN) message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") return() endif () set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) set(GENINFO_FILES "") foreach(FILE ${SOURCES}) # Generate coverage files. If no .gcda file was generated during # execution, the empty coverage file will be used instead. set(OUTFILE "${TDIR}/${FILE}.info") list(APPEND GENINFO_FILES ${OUTFILE}) add_custom_command(OUTPUT ${OUTFILE} COMMAND test -f "${TDIR}/${FILE}.gcda" && ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory ${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcda || cp ${OUTFILE}.init ${OUTFILE} DEPENDS ${TNAME} ${TNAME}-capture-init COMMENT "Capturing coverage data for ${FILE}" ) endforeach() # Concatenate all files generated by geninfo to a single file per target. set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info") lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE}) # add geninfo file generation to global lcov-capture target add_dependencies(lcov-capture ${TNAME}-geninfo) set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL "" ) # Add target for generating html output for this target only. file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME}) add_custom_target(${TNAME}-genhtml COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR} --baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info --output-directory ${LCOV_HTML_PATH}/${TNAME} --title "${CMAKE_PROJECT_NAME} - target ${TNAME}" ${GENHTML_CPPFILT_FLAG} ${OUTFILE} DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init ) endfunction (lcov_capture_tgt) # This function will generate the global info file for all targets. It has to be # called after all other CMake functions in the root CMakeLists.txt file, to get # a full list of all targets that generate coverage data. function (lcov_capture) # Skip this function (and do not create the following targets), if there are # no input files. if ("${LCOV_CAPTURE_FILES}" STREQUAL "") return() endif () # Add a new target to merge the files of all targets. set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info") lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES}) add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture) # Add a new global target for all lcov targets. This target could be used to # generate the lcov html output for the whole project instead of calling # -geninfo and -genhtml for each target. It will also be # used to generate a html site for all project data together instead of one # for each target. if (NOT TARGET lcov) file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets) add_custom_target(lcov COMMAND ${GENHTML_BIN} --quiet --sort --baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info --output-directory ${LCOV_HTML_PATH}/all_targets --title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}" ${GENHTML_CPPFILT_FLAG} ${OUTFILE} DEPENDS lcov-geninfo-init lcov-geninfo ) endif () endfunction (lcov_capture) # Add a new global target to generate the lcov html report for the whole project # instead of calling -genhtml for each target (to create an own report # for each target). Instead of the lcov target it does not require geninfo for # all targets, so you have to call -geninfo to generate the info files # the targets you'd like to have in your report or lcov-geninfo for generating # info files for all targets before calling lcov-genhtml. file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets) if (NOT TARGET lcov-genhtml) add_custom_target(lcov-genhtml COMMAND ${GENHTML_BIN} --quiet --output-directory ${LCOV_HTML_PATH}/selected_targets --title \"${CMAKE_PROJECT_NAME} - targets `find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name \"all_targets.info\" -exec basename {} .info \\\;`\" --prefix ${PROJECT_SOURCE_DIR} --sort ${GENHTML_CPPFILT_FLAG} `find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name \"all_targets.info\"` ) endif (NOT TARGET lcov-genhtml) yubihsm-shell-2.7.3/cmake/zlib.cmake0000644000175000017500000000117315167357110016320 0ustar aveenaveenmacro(find_zlib) if(MSVC) if (NOT ZLIB_LIB_DIR AND NOT ZLIB_INCLUDE_DIR) message(FATAL_ERROR "Missing 'ZLIB_LIB_DIR' and 'ZLIB_INCLUDE_DIR' options to CMake command. Aborting...") else (NOT ZLIB_LIB_DIR AND NOT ZLIB_INCLUDE_DIR) find_library(ZLIB zlib PATHS ${ZLIB_LIB_DIR}) set(ZLIB_LIBS ${ZLIB}) include_directories(${ZLIB_INCLUDE_DIR}) endif (NOT ZLIB_LIB_DIR AND NOT ZLIB_INCLUDE_DIR) else (MSVC) find_package(ZLIB REQUIRED) set(ZLIB_LIBS ${ZLIB_LIBRARIES}) include_directories(${ZLIB_INCLUDE_DIRS}) endif (MSVC) endmacro()yubihsm-shell-2.7.3/cmake/getopt.cmake0000644000175000017500000000101315167357110016653 0ustar aveenaveenmacro (find_getopt) if (MSVC) if(NOT GETOPT_LIB_DIR AND NOT GETOPT_INCLUDE_DIR) message (FATAL_ERROR "Missing 'GETOPT_LIB_DIR' and 'GETOPT_INCLUDE_DIR' options to CMake command. Aborting...") else(NOT GETOPT_LIB_DIR AND NOT GETOPT_INCLUDE_DIR) find_library(GETOPT getopt PATHS ${GETOPT_LIB_DIR}) set(GETOPT_LIBS ${GETOPT}) include_directories(${GETOPT_INCLUDE_DIR}) endif(NOT GETOPT_LIB_DIR AND NOT GETOPT_INCLUDE_DIR) endif (MSVC) endmacro ()yubihsm-shell-2.7.3/cmake/SecurityFlags.cmake0000644000175000017500000000447015167357110020147 0ustar aveenaveeninclude(CheckCCompilerFlag) if (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_C_COMPILER_ID STREQUAL "GNU") add_compile_options (-Wformat -Wformat-nonliteral -Wformat-security) add_compile_options (-Wshadow) #add_compile_options (-Wcast-qual) add_compile_options (-Wmissing-prototypes) add_compile_options (-Wbad-function-cast) add_compile_options (-pedantic -pedantic-errors) add_compile_options (-fpie -fpic) if (NOT FUZZING) add_compile_options (-Wall -Wextra -Werror) add_compile_options(-O2) add_definitions (-D_FORTIFY_SOURCE=2) endif () check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL) if (HAVE_STACK_PROTECTOR_ALL) message(STATUS "-fstack-protector-all support detected") add_compile_options(-fstack-protector-all) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fstack-protector-all") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fstack-protector-all") else () check_c_compiler_flag("-fstack-protector" HAVE_STACK_PROTECTOR) if(HAVE_STACK_PROTECTOR) message(STATUS "-fstack-protector support detected") add_compile_options(-fstack-protector) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fstack-protector") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fstack-protector") else () message(WARNING "No stack protection supported.") endif () endif () check_c_compiler_flag("-Wno-implicit-fallthrough" HAVE_NO_IMPLICIT_FALLTHROUGH) if (HAVE_NO_IMPLICIT_FALLTHROUGH) add_compile_options (-Wno-implicit-fallthrough) endif () if (NOT APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,noexecstack -Wl,-z,relro,-z,now") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,noexecstack -Wl,-z,relro,-z,now") endif() elseif (CMAKE_C_COMPILER_ID STREQUAL "MSVC") add_compile_options (/GS) add_compile_options (/Gs) add_link_options (/NXCOMPAT) add_link_options (/guard:cf) else () message(WARNING "Security related flags cannot be set for unknown C compiler.") endif () yubihsm-shell-2.7.3/cmake/openssl.cmake0000644000175000017500000000065315167357110017045 0ustar aveenaveenmacro (find_libcrypto) if(NOT LIBCRYPTO_LDFLAGS) if(WIN32) find_package(OpenSSL REQUIRED) set(LIBCRYPTO_LDFLAGS "OpenSSL::Crypto") set(LIBCRYPTO_VERSION ${OPENSSL_VERSION}) set(LIBCRYPTO_INCLUDEDIR ${OPENSSL_INCLUDE_DIR}) else(WIN32) pkg_search_module (LIBCRYPTO REQUIRED libcrypto) endif(WIN32) endif(NOT LIBCRYPTO_LDFLAGS) endmacro()yubihsm-shell-2.7.3/src/0000755000175000017500000000000015167357160014070 5ustar aveenaveenyubihsm-shell-2.7.3/src/cmdline.h0000644000175000017500000006155515167357160015670 0ustar aveenaveen/** @file cmdline.h * @brief The header file for the command line option parser * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten * @author GNU Gengetopt */ #ifndef CMDLINE_H #define CMDLINE_H /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* for FILE */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef CMDLINE_PARSER_PACKAGE /** @brief the program name (used for printing errors) */ #define CMDLINE_PARSER_PACKAGE PACKAGE #endif #ifndef CMDLINE_PARSER_PACKAGE_NAME /** @brief the complete program name (used for help and version) */ #ifdef PACKAGE_NAME #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE_NAME #else #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE #endif #endif #ifndef CMDLINE_PARSER_VERSION /** @brief the program version */ #define CMDLINE_PARSER_VERSION VERSION #endif enum enum_action { action__NULL = -1, action_arg_benchmark = 0, action_arg_blinkMINUS_device, action_arg_createMINUS_otpMINUS_aead, action_arg_decryptMINUS_aesccm, action_arg_decryptMINUS_aescbc, action_arg_decryptMINUS_aesecb, action_arg_decryptMINUS_oaep, action_arg_decryptMINUS_otp, action_arg_decryptMINUS_pkcs1v15, action_arg_deleteMINUS_object, action_arg_deriveMINUS_ecdh, action_arg_encryptMINUS_aesccm, action_arg_encryptMINUS_aescbc, action_arg_encryptMINUS_aesecb, action_arg_generateMINUS_asymmetricMINUS_key, action_arg_generateMINUS_csr, action_arg_generateMINUS_hmacMINUS_key, action_arg_generateMINUS_otpMINUS_aeadMINUS_key, action_arg_generateMINUS_wrapMINUS_key, action_arg_generateMINUS_symmetricMINUS_key, action_arg_getMINUS_deviceMINUS_info, action_arg_getMINUS_logs, action_arg_getMINUS_objectMINUS_info, action_arg_getMINUS_opaque, action_arg_getMINUS_option, action_arg_getMINUS_pseudoMINUS_random, action_arg_getMINUS_publicMINUS_key, action_arg_getMINUS_storageMINUS_info, action_arg_getMINUS_template, action_arg_getMINUS_wrapped, action_arg_getMINUS_rsaMINUS_wrapped, action_arg_getMINUS_rsaMINUS_wrappedMINUS_key, action_arg_getMINUS_deviceMINUS_pubkey, action_arg_listMINUS_objects, action_arg_putMINUS_asymmetricMINUS_key, action_arg_putMINUS_authenticationMINUS_key, action_arg_putMINUS_hmacMINUS_key, action_arg_putMINUS_opaque, action_arg_putMINUS_option, action_arg_putMINUS_otpMINUS_aeadMINUS_key, action_arg_putMINUS_symmetricMINUS_key, action_arg_putMINUS_template, action_arg_putMINUS_wrapMINUS_key, action_arg_putMINUS_rsaMINUS_wrapkey, action_arg_putMINUS_publicMINUS_wrapkey, action_arg_putMINUS_wrapped, action_arg_putMINUS_rsaMINUS_wrapped, action_arg_putMINUS_rsaMINUS_wrappedMINUS_key, action_arg_randomizeMINUS_otpMINUS_aead, action_arg_reset, action_arg_setMINUS_logMINUS_index, action_arg_signMINUS_attestationMINUS_certificate, action_arg_signMINUS_ecdsa, action_arg_signMINUS_eddsa, action_arg_signMINUS_hmac, action_arg_signMINUS_pkcs1v15, action_arg_signMINUS_pss, action_arg_signMINUS_sshMINUS_certificate }; enum enum_informat { informat__NULL = -1, informat_arg_default = 0, informat_arg_base64, informat_arg_binary, informat_arg_PEM, informat_arg_password, informat_arg_hex, informat_arg_ASCII }; enum enum_outformat { outformat__NULL = -1, outformat_arg_default = 0, outformat_arg_base64, outformat_arg_binary, outformat_arg_PEM, outformat_arg_hex, outformat_arg_ASCII }; /** @brief Where the command line options are stored */ struct gengetopt_args_info { const char *help_help; /**< @brief Print help and exit help description. */ const char *version_help; /**< @brief Print version and exit help description. */ enum enum_action *action_arg; /**< @brief Action to perform. */ char ** action_orig; /**< @brief Action to perform original value given at command line. */ unsigned int action_min; /**< @brief Action to perform's minimum occurreces */ unsigned int action_max; /**< @brief Action to perform's maximum occurreces */ const char *action_help; /**< @brief Action to perform help description. */ char * password_arg; /**< @brief Authentication password. */ char * password_orig; /**< @brief Authentication password original value given at command line. */ const char *password_help; /**< @brief Authentication password help description. */ short authkey_arg; /**< @brief Authentication key (default='1'). */ char * authkey_orig; /**< @brief Authentication key original value given at command line. */ const char *authkey_help; /**< @brief Authentication key help description. */ short object_id_arg; /**< @brief Object ID (default='0'). */ char * object_id_orig; /**< @brief Object ID original value given at command line. */ const char *object_id_help; /**< @brief Object ID help description. */ char * label_arg; /**< @brief Object label (default=''). */ char * label_orig; /**< @brief Object label original value given at command line. */ const char *label_help; /**< @brief Object label help description. */ char * domains_arg; /**< @brief Object domains (default='1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16'). */ char * domains_orig; /**< @brief Object domains original value given at command line. */ const char *domains_help; /**< @brief Object domains help description. */ char * capabilities_arg; /**< @brief Capabilities for an object (default='0'). */ char * capabilities_orig; /**< @brief Capabilities for an object original value given at command line. */ const char *capabilities_help; /**< @brief Capabilities for an object help description. */ char * object_type_arg; /**< @brief Object type (default='any'). */ char * object_type_orig; /**< @brief Object type original value given at command line. */ const char *object_type_help; /**< @brief Object type help description. */ char * ykhsmauth_label_arg; /**< @brief Credential label on YubiKey (implicitly enables ykhsmauth). */ char * ykhsmauth_label_orig; /**< @brief Credential label on YubiKey (implicitly enables ykhsmauth) original value given at command line. */ const char *ykhsmauth_label_help; /**< @brief Credential label on YubiKey (implicitly enables ykhsmauth) help description. */ char * ykhsmauth_reader_arg; /**< @brief Only use a matching YubiKey reader name (default=''). */ char * ykhsmauth_reader_orig; /**< @brief Only use a matching YubiKey reader name original value given at command line. */ const char *ykhsmauth_reader_help; /**< @brief Only use a matching YubiKey reader name help description. */ char * delegated_arg; /**< @brief Delegated capabilities (default='0'). */ char * delegated_orig; /**< @brief Delegated capabilities original value given at command line. */ const char *delegated_help; /**< @brief Delegated capabilities help description. */ char * new_password_arg; /**< @brief New authentication password. */ char * new_password_orig; /**< @brief New authentication password original value given at command line. */ const char *new_password_help; /**< @brief New authentication password help description. */ char * algorithm_arg; /**< @brief Operation algorithm (default='any'). */ char * algorithm_orig; /**< @brief Operation algorithm original value given at command line. */ const char *algorithm_help; /**< @brief Operation algorithm help description. */ char * oaep_arg; /**< @brief OAEP algorithm. Used primarily with asymmetric wrap (default='rsa-oaep-sha256'). */ char * oaep_orig; /**< @brief OAEP algorithm. Used primarily with asymmetric wrap original value given at command line. */ const char *oaep_help; /**< @brief OAEP algorithm. Used primarily with asymmetric wrap help description. */ char * mgf1_arg; /**< @brief MGF1 algorithm. Used primarily with asymmetric wrap (default='mgf1-sha256'). */ char * mgf1_orig; /**< @brief MGF1 algorithm. Used primarily with asymmetric wrap original value given at command line. */ const char *mgf1_help; /**< @brief MGF1 algorithm. Used primarily with asymmetric wrap help description. */ int nonce_arg; /**< @brief OTP nonce. */ char * nonce_orig; /**< @brief OTP nonce original value given at command line. */ const char *nonce_help; /**< @brief OTP nonce help description. */ char * iv_arg; /**< @brief An initialization vector as a hexadecimal string. */ char * iv_orig; /**< @brief An initialization vector as a hexadecimal string original value given at command line. */ const char *iv_help; /**< @brief An initialization vector as a hexadecimal string help description. */ int count_arg; /**< @brief Number of bytes to request (default='256'). */ char * count_orig; /**< @brief Number of bytes to request original value given at command line. */ const char *count_help; /**< @brief Number of bytes to request help description. */ int duration_arg; /**< @brief Blink duration in seconds (default='10'). */ char * duration_orig; /**< @brief Blink duration in seconds original value given at command line. */ const char *duration_help; /**< @brief Blink duration in seconds help description. */ short wrap_id_arg; /**< @brief Wrap key ID. */ char * wrap_id_orig; /**< @brief Wrap key ID original value given at command line. */ const char *wrap_id_help; /**< @brief Wrap key ID help description. */ int include_seed_flag; /**< @brief Include seed when exporting an ED25519 key under wrap (default=off). */ const char *include_seed_help; /**< @brief Include seed when exporting an ED25519 key under wrap help description. */ short template_id_arg; /**< @brief Template ID. */ char * template_id_orig; /**< @brief Template ID original value given at command line. */ const char *template_id_help; /**< @brief Template ID help description. */ short attestation_id_arg; /**< @brief Attestation ID. */ char * attestation_id_orig; /**< @brief Attestation ID original value given at command line. */ const char *attestation_id_help; /**< @brief Attestation ID help description. */ int log_index_arg; /**< @brief Log index. */ char * log_index_orig; /**< @brief Log index original value given at command line. */ const char *log_index_help; /**< @brief Log index help description. */ char * opt_name_arg; /**< @brief Device option name. */ char * opt_name_orig; /**< @brief Device option name original value given at command line. */ const char *opt_name_help; /**< @brief Device option name help description. */ char * opt_value_arg; /**< @brief Device option value. */ char * opt_value_orig; /**< @brief Device option value original value given at command line. */ const char *opt_value_help; /**< @brief Device option value help description. */ int with_compression_flag; /**< @brief Compress a X509Certificate before importing it into the device or detect compressed certificates when listing objects (default=off). */ const char *with_compression_help; /**< @brief Compress a X509Certificate before importing it into the device or detect compressed certificates when listing objects help description. */ char * subject_arg; /**< @brief The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/. */ char * subject_orig; /**< @brief The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/ original value given at command line. */ const char *subject_help; /**< @brief The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/ help description. */ char * in_arg; /**< @brief Input data (filename) (default='-'). */ char * in_orig; /**< @brief Input data (filename) original value given at command line. */ const char *in_help; /**< @brief Input data (filename) help description. */ char * out_arg; /**< @brief Output data (filename) (default='-'). */ char * out_orig; /**< @brief Output data (filename) original value given at command line. */ const char *out_help; /**< @brief Output data (filename) help description. */ enum enum_informat informat_arg; /**< @brief Input format (default='default'). */ char * informat_orig; /**< @brief Input format original value given at command line. */ const char *informat_help; /**< @brief Input format help description. */ enum enum_outformat outformat_arg; /**< @brief Input and output format (default='default'). */ char * outformat_orig; /**< @brief Input and output format original value given at command line. */ const char *outformat_help; /**< @brief Input and output format help description. */ char * config_file_arg; /**< @brief Configuration file to read (default=''). */ char * config_file_orig; /**< @brief Configuration file to read original value given at command line. */ const char *config_file_help; /**< @brief Configuration file to read help description. */ char ** connector_arg; /**< @brief List of connectors to use. */ char ** connector_orig; /**< @brief List of connectors to use original value given at command line. */ unsigned int connector_min; /**< @brief List of connectors to use's minimum occurreces */ unsigned int connector_max; /**< @brief List of connectors to use's maximum occurreces */ const char *connector_help; /**< @brief List of connectors to use help description. */ char * cacert_arg; /**< @brief HTTPS cacert for connector. */ char * cacert_orig; /**< @brief HTTPS cacert for connector original value given at command line. */ const char *cacert_help; /**< @brief HTTPS cacert for connector help description. */ char * cert_arg; /**< @brief HTTPS client certificate to authenticate with. */ char * cert_orig; /**< @brief HTTPS client certificate to authenticate with original value given at command line. */ const char *cert_help; /**< @brief HTTPS client certificate to authenticate with help description. */ char * key_arg; /**< @brief HTTPS client certificate key. */ char * key_orig; /**< @brief HTTPS client certificate key original value given at command line. */ const char *key_help; /**< @brief HTTPS client certificate key help description. */ char * proxy_arg; /**< @brief Proxy server to use for connector. */ char * proxy_orig; /**< @brief Proxy server to use for connector original value given at command line. */ const char *proxy_help; /**< @brief Proxy server to use for connector help description. */ char * noproxy_arg; /**< @brief Comma separated list of hosts ignore proxy for. */ char * noproxy_orig; /**< @brief Comma separated list of hosts ignore proxy for original value given at command line. */ const char *noproxy_help; /**< @brief Comma separated list of hosts ignore proxy for help description. */ int verbose_arg; /**< @brief Print more information (default='0'). */ char * verbose_orig; /**< @brief Print more information original value given at command line. */ const char *verbose_help; /**< @brief Print more information help description. */ int pre_connect_flag; /**< @brief Connect immediately in interactive mode (default=off). */ const char *pre_connect_help; /**< @brief Connect immediately in interactive mode help description. */ char ** device_pubkey_arg; /**< @brief List of device public keys allowed for asymmetric authentication. */ char ** device_pubkey_orig; /**< @brief List of device public keys allowed for asymmetric authentication original value given at command line. */ unsigned int device_pubkey_min; /**< @brief List of device public keys allowed for asymmetric authentication's minimum occurreces */ unsigned int device_pubkey_max; /**< @brief List of device public keys allowed for asymmetric authentication's maximum occurreces */ const char *device_pubkey_help; /**< @brief List of device public keys allowed for asymmetric authentication help description. */ unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ unsigned int action_given ; /**< @brief Whether action was given. */ unsigned int password_given ; /**< @brief Whether password was given. */ unsigned int authkey_given ; /**< @brief Whether authkey was given. */ unsigned int object_id_given ; /**< @brief Whether object-id was given. */ unsigned int label_given ; /**< @brief Whether label was given. */ unsigned int domains_given ; /**< @brief Whether domains was given. */ unsigned int capabilities_given ; /**< @brief Whether capabilities was given. */ unsigned int object_type_given ; /**< @brief Whether object-type was given. */ unsigned int ykhsmauth_label_given ; /**< @brief Whether ykhsmauth-label was given. */ unsigned int ykhsmauth_reader_given ; /**< @brief Whether ykhsmauth-reader was given. */ unsigned int delegated_given ; /**< @brief Whether delegated was given. */ unsigned int new_password_given ; /**< @brief Whether new-password was given. */ unsigned int algorithm_given ; /**< @brief Whether algorithm was given. */ unsigned int oaep_given ; /**< @brief Whether oaep was given. */ unsigned int mgf1_given ; /**< @brief Whether mgf1 was given. */ unsigned int nonce_given ; /**< @brief Whether nonce was given. */ unsigned int iv_given ; /**< @brief Whether iv was given. */ unsigned int count_given ; /**< @brief Whether count was given. */ unsigned int duration_given ; /**< @brief Whether duration was given. */ unsigned int wrap_id_given ; /**< @brief Whether wrap-id was given. */ unsigned int include_seed_given ; /**< @brief Whether include-seed was given. */ unsigned int template_id_given ; /**< @brief Whether template-id was given. */ unsigned int attestation_id_given ; /**< @brief Whether attestation-id was given. */ unsigned int log_index_given ; /**< @brief Whether log-index was given. */ unsigned int opt_name_given ; /**< @brief Whether opt-name was given. */ unsigned int opt_value_given ; /**< @brief Whether opt-value was given. */ unsigned int with_compression_given ; /**< @brief Whether with-compression was given. */ unsigned int subject_given ; /**< @brief Whether subject was given. */ unsigned int in_given ; /**< @brief Whether in was given. */ unsigned int out_given ; /**< @brief Whether out was given. */ unsigned int informat_given ; /**< @brief Whether informat was given. */ unsigned int outformat_given ; /**< @brief Whether outformat was given. */ unsigned int config_file_given ; /**< @brief Whether config-file was given. */ unsigned int connector_given ; /**< @brief Whether connector was given. */ unsigned int cacert_given ; /**< @brief Whether cacert was given. */ unsigned int cert_given ; /**< @brief Whether cert was given. */ unsigned int key_given ; /**< @brief Whether key was given. */ unsigned int proxy_given ; /**< @brief Whether proxy was given. */ unsigned int noproxy_given ; /**< @brief Whether noproxy was given. */ unsigned int verbose_given ; /**< @brief Whether verbose was given. */ unsigned int pre_connect_given ; /**< @brief Whether pre-connect was given. */ unsigned int device_pubkey_given ; /**< @brief Whether device-pubkey was given. */ } ; /** @brief The additional parameters to pass to parser functions */ struct cmdline_parser_params { int override; /**< @brief whether to override possibly already present options (default 0) */ int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ int check_required; /**< @brief whether to check that all required options were provided (default 1) */ int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ } ; /** @brief the purpose string of the program */ extern const char *gengetopt_args_info_purpose; /** @brief the usage string of the program */ extern const char *gengetopt_args_info_usage; /** @brief the description string of the program */ extern const char *gengetopt_args_info_description; /** @brief all the lines making the help output */ extern const char *gengetopt_args_info_help[]; /** * The command line parser * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info); /** * The command line parser (version with additional parameters - deprecated) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_ext() instead */ int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required); /** * The command line parser (version with additional parameters) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params); /** * Save the contents of the option struct into an already open FILE stream. * @param outfile the stream where to dump options * @param args_info the option struct to dump * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info); /** * Save the contents of the option struct into a (text) file. * This file can be read by the config file parser (if generated by gengetopt) * @param filename the file where to save * @param args_info the option struct to save * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info); /** * Print the help */ void cmdline_parser_print_help(void); /** * Print the version */ void cmdline_parser_print_version(void); /** * Initializes all the fields a cmdline_parser_params structure * to their default values * @param params the structure to initialize */ void cmdline_parser_params_init(struct cmdline_parser_params *params); /** * Allocates dynamically a cmdline_parser_params structure and initializes * all its fields to their default values * @return the created and initialized cmdline_parser_params structure */ struct cmdline_parser_params *cmdline_parser_params_create(void); /** * Initializes the passed gengetopt_args_info structure's fields * (also set default values for options that have a default) * @param args_info the structure to initialize */ void cmdline_parser_init (struct gengetopt_args_info *args_info); /** * Deallocates the string fields of the gengetopt_args_info structure * (but does not deallocate the structure itself) * @param args_info the structure to deallocate */ void cmdline_parser_free (struct gengetopt_args_info *args_info); /** * The config file parser (deprecated version) * @param filename the name of the config file * @param args_info the structure where option information will be stored * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_config_file() instead */ int cmdline_parser_configfile (const char *filename, struct gengetopt_args_info *args_info, int override, int initialize, int check_required); /** * The config file parser * @param filename the name of the config file * @param args_info the structure where option information will be stored * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_config_file (const char *filename, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params); /** * Checks that all the required options were specified * @param args_info the structure to check * @param prog_name the name of the program that will be used to print * possible errors * @return */ int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name); extern const char *cmdline_parser_action_values[]; /**< @brief Possible values for action. */ extern const char *cmdline_parser_informat_values[]; /**< @brief Possible values for informat. */ extern const char *cmdline_parser_outformat_values[]; /**< @brief Possible values for outformat. */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* CMDLINE_H */ yubihsm-shell-2.7.3/src/commands.c0000644000175000017500000036075615167357110016051 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "commands.h" #include "yubihsm-shell.h" #include "../common/insecure_memzero.h" #include "../common/parsing.h" #include "time_win.h" #include "hash.h" #include "util.h" #include "cmd_util.h" #include "openssl-compat.h" #ifdef __WIN32 #include #include #else #include #include #include #include #endif #include #include #include #include #include #include static format_t fmt_to_fmt(cmd_format fmt) { switch (fmt) { case fmt_base64: return _base64; case fmt_binary: return _binary; case fmt_hex: return _hex; case fmt_PEM: return _PEM; default: return 0; } } static bool is_compressed(yh_session *session, uint16_t id, yh_algorithm algorithm) { if (algorithm == YH_ALGO_OPAQUE_X509_CERTIFICATE) { uint8_t out[16384] = {0}; size_t out_len = sizeof(out); size_t stored_len = 0; yh_rc yrc = yh_util_get_opaque_ex(session, id, out, &out_len, &stored_len, true); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get opaque data. Object compression status might " "not be accurate: %s\n", yh_strerror(yrc)); return false; } #ifdef ENABLE_CERT_COMPRESS if (out_len != stored_len) { return true; } #else if (out_len > 2 && out[0] == 0x1f && out[1] == 0x8b) { return true; } #endif } return false; } // NOTE(adma): Extract log entries // argc = 1 // arg 0: e:session int yh_com_audit(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint16_t unlogged_boot = 0; uint16_t unlogged_auth = 0; yh_log_entry logs[YH_MAX_LOG_ENTRIES] = {0}; size_t n_items = sizeof(logs) / sizeof(logs[0]); switch (fmt) { case fmt_binary: case fmt_PEM: case fmt_base64: case fmt_password: fprintf(stderr, "The selected output format is not supported for this operation. " "Supported format are \"ASCII\", \"hex\" and \"default\"\n"); return -1; default: break; } yh_rc yrc = yh_util_get_log_entries(argv[0].e, &unlogged_boot, &unlogged_auth, logs, &n_items); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get logs: %s\n", yh_strerror(yrc)); return -1; } char digest_buf[(2 * YH_LOG_DIGEST_SIZE) + 1] = {0}; switch (fmt) { case fmt_hex: fprintf(ctx->out, "%04x%04x", unlogged_boot, unlogged_auth); for (size_t i = 0; i < n_items; i++) { format_digest(logs[i].digest, digest_buf, YH_LOG_DIGEST_SIZE); fprintf(ctx->out, "%04x%02x%04x%04x%04x%04x%02x%08lx%s", logs[i].number, logs[i].command, logs[i].length, logs[i].session_key, logs[i].target_key, logs[i].second_key, logs[i].result, (unsigned long) logs[i].systick, digest_buf); } fprintf(ctx->out, "\n"); break; case fmt_ASCII: default: fprintf(ctx->out, "%d unlogged boots found\n", unlogged_boot); fprintf(ctx->out, "%d unlogged authentications found\n", unlogged_auth); if (n_items == 0) { fprintf(ctx->out, "No logs to extract\n"); return 0; } else if (n_items == 1) { fprintf(ctx->out, "Found 1 item\n"); } else { fprintf(ctx->out, "Found %zu items\n", n_items); } for (size_t i = 0; i < n_items; i++) { format_digest(logs[i].digest, digest_buf, YH_LOG_DIGEST_SIZE); fprintf(ctx->out, "item: %5u -- cmd: 0x%02x -- length: %4u -- session key: " "0x%04x -- target key: 0x%04x -- second key: 0x%04x -- " "result: 0x%02x -- tick: %lu -- hash: %s\n", logs[i].number, logs[i].command, logs[i].length, logs[i].session_key, logs[i].target_key, logs[i].second_key, logs[i].result, (unsigned long) logs[i].systick, digest_buf); } break; } return 0; } // NOTE: Set the log index // argc = 2 // arg 0: e:session // arg 1: w:index int yh_com_set_log_index(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_set_log_index(argv[0].e, argv[1].w); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to set log index: %s\n", yh_strerror(yrc)); return -1; } return 0; } // NOTE: Blink the device // argc = 2 // arg 0: e:session // arg 1: b:seconds int yh_com_blink(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); yh_rc yrc = yh_util_blink_device(argv[0].e, argv[1].b); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to blink the device: %s\n", yh_strerror(yrc)); return -1; } return 0; } // NOTE(adma): Close a session with a connector // argc = 1 // arg 0: e:session int yh_com_close_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); uint8_t session_id = 0; yh_rc yrc = yh_get_session_id(argv[0].e, &session_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get session id: %s\n", yh_strerror(yrc)); return -1; } yrc = yh_util_close_session(argv[0].e); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to close session: %s\n", yh_strerror(yrc)); return -1; } yrc = yh_destroy_session(&argv[0].e); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy session: %s\n", yh_strerror(yrc)); return -1; } ctx->sessions[session_id] = NULL; return 0; } // NOTE(adma): Connect to a connector // argc = 0 int yh_com_connect(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); ctx->connector = NULL; for (int i = 0; ctx->connector_list[i]; i++) { if (ctx->connector) { yh_disconnect(ctx->connector); ctx->connector = NULL; } yh_rc yrc = yh_init_connector(ctx->connector_list[i], &ctx->connector); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed initializing connector %s: %s\n", ctx->connector_list[i], yh_strerror(yrc)); break; } if (ctx->cacert) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_HTTPS_CA, ctx->cacert) != YHR_SUCCESS) { fprintf(stderr, "Failed setting HTTPS CA\n"); break; } } if (ctx->cert) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_HTTPS_CERT, ctx->cert) != YHR_SUCCESS) { fprintf(stderr, "Failed setting HTTPS cert\n"); break; } } if (ctx->key) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_HTTPS_KEY, ctx->key) != YHR_SUCCESS) { fprintf(stderr, "Failed setting HTTPS key\n"); break; } } if (ctx->proxy) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_PROXY_SERVER, ctx->proxy) != YHR_SUCCESS) { fprintf(stderr, "Failed setting proxy server\n"); break; } } if (ctx->noproxy) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_NOPROXY, ctx->noproxy) != YHR_SUCCESS) { fprintf(stderr, "Failed setting noproxy\n"); break; } } yrc = yh_connect(ctx->connector, 0); if (yrc == YHR_SUCCESS) { yh_com_keepalive_on(NULL, NULL, fmt_nofmt, fmt_nofmt); return 0; } fprintf(stderr, "Failed connecting '%s': %s\n", ctx->connector_list[i], yh_strerror(yrc)); } if (ctx->connector) { yh_disconnect(ctx->connector); ctx->connector = NULL; } return -1; } // NOTE(adma): Enable all debug messages // argc = 0 int yh_com_debug_all(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); yh_set_verbosity(ctx->connector, YH_VERB_ALL); fprintf(stderr, "Debug messages enabled\n"); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_error(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_ERR; if (yh_verbosity & YH_VERB_ERR) fprintf(stderr, "Error messages on\n"); else fprintf(stderr, "Error messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_INFO; if (yh_verbosity & YH_VERB_INFO) fprintf(stderr, "Info messages on\n"); else fprintf(stderr, "Info messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_intermediate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_INTERMEDIATE; if (yh_verbosity & YH_VERB_INTERMEDIATE) fprintf(stderr, "Intermediate messages on\n"); else fprintf(stderr, "Intermediate messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_none(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); yh_set_verbosity(ctx->connector, YH_VERB_QUIET); fprintf(stderr, "Debug messages disabled\n"); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_raw(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_RAW; if (yh_verbosity & YH_VERB_RAW) fprintf(stderr, "Raw messages on\n"); else fprintf(stderr, "Raw messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_crypto(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_CRYPTO; if (yh_verbosity & YH_VERB_CRYPTO) fprintf(stderr, "Crypto messages on\n"); else fprintf(stderr, "Crypto messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Decrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_decrypt_pkcs1v1_5(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_decrypt_pkcs1v1_5(argv[0].e, argv[1].w, argv[2].x, argv[2].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Do a ECDH key exchange // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:pubkey int yh_com_derive_ecdh(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); yh_algorithm algo = 0; uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); if (!read_public_key(argv[2].x, argv[2].len, &algo, data, &data_len)) { fprintf(stderr, "Failed to load public key\n"); return -1; } uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_derive_ecdh(argv[0].e, argv[1].w, data, data_len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to do key exchange: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Decrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_decrypt_aesccm(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_unwrap_data(argv[0].e, argv[1].w, argv[2].x, argv[2].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Encrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_encrypt_aesccm(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_wrap_data(argv[0].e, argv[1].w, argv[2].x, argv[2].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to encrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Decrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_decrypt_aes_ecb(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); yh_rc yrc = yh_util_decrypt_aes_ecb(argv[0].e, argv[1].w, argv[2].x, argv[2].len, argv[2].x, &argv[2].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(argv[2].x, argv[2].len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Encrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: s:iv // arg 3: i:data int yh_com_encrypt_aes_cbc(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t iv[16] = {0}; size_t iv_len = sizeof(iv); if (hex_decode(argv[2].s, iv, &iv_len) == false) { fprintf(stderr, "Failed to decode IV\n"); return -1; } yh_rc yrc = yh_util_encrypt_aes_cbc(argv[0].e, argv[1].w, iv, argv[3].x, argv[3].len, argv[3].x, &argv[3].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to encrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(argv[3].x, argv[3].len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Decrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: s:iv // arg 3: i:data int yh_com_decrypt_aes_cbc(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t iv[16] = {0}; size_t iv_len = sizeof(iv); if (hex_decode(argv[2].s, iv, &iv_len) == false) { fprintf(stderr, "Failed to decode IV\n"); return -1; } yh_rc yrc = yh_util_decrypt_aes_cbc(argv[0].e, argv[1].w, iv, argv[3].x, argv[3].len, argv[3].x, &argv[3].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(argv[3].x, argv[3].len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Encrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_encrypt_aes_ecb(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); yh_rc yrc = yh_util_encrypt_aes_ecb(argv[0].e, argv[1].w, argv[2].x, argv[2].len, argv[2].x, &argv[2].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to encrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(argv[2].x, argv[2].len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Disconnect from a connector // argc = 0 int yh_com_disconnect(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = YHR_SUCCESS; for (size_t i = 0; i < sizeof(ctx->sessions) / sizeof(ctx->sessions[0]); i++) { if (ctx->sessions[i]) { yrc = yh_util_close_session(ctx->sessions[i]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to close session: %s\n", yh_strerror(yrc)); } yrc = yh_destroy_session(&ctx->sessions[i]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy session: %s\n", yh_strerror(yrc)); } ctx->sessions[i] = NULL; } } if (ctx->connector) { yrc = yh_disconnect(ctx->connector); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Unable to disconnect: %s\n", yh_strerror(yrc)); return -1; } ctx->connector = NULL; } return 0; } // NOTE(adma): Send authenticated echo // argc = 3 // arg 0: e:session // arg 1: b:byte // arg 2: w:count int yh_com_echo(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = 0; uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = 0; yh_cmd response_cmd = 0; uint8_t byte = argv[1].b; uint16_t count = argv[2].w; if (count > YH_MSG_BUF_SIZE) { fprintf(stderr, "Count must be in [0, %d]\n", YH_MSG_BUF_SIZE); return -1; } memset(data, byte, count); data_len = count; response_len = sizeof(response); yh_rc yrc = yh_send_secure_msg(argv[0].e, YHC_ECHO, data, data_len, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to send ECHO command: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Response (%zu bytes):\n", response_len); for (size_t i = 0; i < response_len; i++) { if (i && !(i % 64)) fprintf(ctx->out, "\n"); else if (i && !(i % 8)) fprintf(ctx->out, " "); fprintf(ctx->out, "%02x", response[i]); } fprintf(ctx->out, "\n"); return 0; } // Generate a Symmetric Key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm int yh_com_generate_symmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc; if (yh_is_aes(argv[5].a)) { yrc = yh_util_generate_aes_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); } else { fprintf(stderr, "Invalid algorithm %d\n", argv[5].a); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate symmetric key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated symmetric key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Generate an Asymmetric Key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm int yh_com_generate_asymmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = YHR_SUCCESS; if (yh_is_rsa(argv[5].a)) { yrc = yh_util_generate_rsa_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); } else if (yh_is_ec(argv[5].a)) { yrc = yh_util_generate_ec_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); } else if (yh_is_ed(argv[5].a)) { yrc = yh_util_generate_ed_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); } else { fprintf(stderr, "Invalid algorithm %d\n", argv[5].a); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate asymmetric key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated Asymmetric key 0x%04x\n", argv[1].w); return 0; } // NOTE: Generate HMAC key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm int yh_com_generate_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (!yh_is_hmac(argv[5].a)) { fprintf(stderr, "Invalid algorithm: %d\n", argv[5].a); return -1; } yh_rc yrc = yh_util_generate_hmac_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate HMAC key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated HMAC key 0x%04x\n", argv[1].w); return 0; } // NOTE: Generate wrap key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: a:algorithm int yh_com_generate_wrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_generate_wrap_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[6].a, &argv[5].c); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate wrapping key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated Wrap key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Get an opaque object // argc = 2 // arg 0: e:session, // arg 1: w:object_id // arg 2: F:file int yh_com_get_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); yh_object_descriptor desc = {0}; uint8_t response[16384] = {0}; size_t response_len = sizeof(response); size_t stored_len = 0; int ret = -1; yh_util_get_object_info(argv[0].e, argv[1].w, YH_OPAQUE, &desc); yh_rc yrc = yh_util_get_opaque_ex(argv[0].e, argv[1].w, response, &response_len, &stored_len, desc.algorithm == YH_ALGO_OPAQUE_X509_CERTIFICATE); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get opaque object: %s\n", yh_strerror(yrc)); return -1; } if (stored_len != response_len) { fprintf(stderr, "Successfully read compressed data\n"); } if (fmt == fmt_PEM) { const unsigned char *ptr = response; X509 *x509 = d2i_X509(NULL, &ptr, response_len); if (!x509) { fprintf(stderr, "Failed parsing x509 information\n"); } else { if (PEM_write_X509(ctx->out, x509) == 1) { ret = 0; } else { fprintf(stderr, "Failed writing x509 information\n"); } } X509_free(x509); } else { if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { ret = 0; } } return ret; } // NOTE(adma): Get a global option value // argc = 2 // arg 0: o:session // arg 1: s:option int yh_com_get_option(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_get_option(argv[0].e, argv[1].o, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get option: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Option value is: "); for (size_t i = 0; i < response_len; i++) { fprintf(ctx->out, "%02x", response[i]); } fprintf(ctx->out, "\n"); return 0; } // NOTE(adma): Get pseudo-random bytes // argc = 2 // arg 0: e:session // arg 1: w:count int yh_com_get_random(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_get_pseudo_random(argv[0].e, argv[1].w, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get pseudo random bytes: %s\n", yh_strerror(yrc)); return -1; } if (response_len != argv[1].w) { fprintf(stderr, "Wrong response length\n"); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Obtain storage information // argc = 1 // arg 0: e:session int yh_com_get_storage(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint16_t total_records = 0, free_records = 0, free_pages = 0, total_pages = 0, page_size = 0; yh_rc yrc = yh_util_get_storage_info(argv[0].e, &total_records, &free_records, &total_pages, &free_pages, &page_size); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get storage stats: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "free records: %d/%d, free pages: %d/%d page size: %d bytes\n", free_records, total_records, free_pages, total_pages, page_size); return 0; } // NOTE: Get public key // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: t:key_type // arg 3: f:filename int yh_com_get_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_algorithm algo = 0; EVP_PKEY *public_key = NULL; yh_rc yrc = yh_util_get_public_key_ex(argv[0].e, argv[2].t, argv[1].w, response, &response_len, &algo); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get public key: %s\n", yh_strerror(yrc)); return -1; } if (yh_is_rsa(algo) || (yh_is_ec(algo))) { if (!get_pubkey_evp(response, response_len, algo, &public_key)) { fprintf(stderr, "Failed to encode public key\n"); return -1; } } else { // NOTE(adma): ED25519, there is (was) no support for this in // OpenSSL, so we manually export them EVP_PKEY_free(public_key); if (write_ed25519_key(response, response_len, ctx->out, fmt_to_fmt(fmt)) == false) { fprintf(stderr, "Unable to format ed25519 key\n"); return -1; } return 0; } if (fmt == fmt_PEM) { if (PEM_write_PUBKEY(ctx->out, public_key) != 1) { fprintf(stderr, "Failed to write public key in PEM format\n"); EVP_PKEY_free(public_key); return -1; } } else if (fmt == fmt_binary) { i2d_PUBKEY_fp(ctx->out, public_key); } else if (fmt == fmt_base64) { bool error = false; BIO *b64 = BIO_new(BIO_f_base64()); if (b64 == NULL) { fprintf(stderr, "Unable to allocate buffer\n"); error = true; goto getpk_base64_cleanup; } BIO *bio = BIO_new_fp(ctx->out, BIO_NOCLOSE); if (bio == NULL) { fprintf(stderr, "Unable to allocate BIO\n"); error = true; goto getpk_base64_cleanup; } bio = BIO_push(b64, bio); i2d_PUBKEY_bio(bio, public_key); if (BIO_flush(bio) != 1) { fprintf(stderr, "Unable to flush BIO\n"); error = true; goto getpk_base64_cleanup; } getpk_base64_cleanup: BIO_free_all(b64); if (error) { EVP_PKEY_free(public_key); return -1; } } // FIXME: other formats or error. EVP_PKEY_free(public_key); return 0; } // NOTE: Get device public key // argc = 0 int yh_com_get_device_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_algorithm algo = 0; yh_rc yrc = yh_util_get_device_pubkey(ctx->connector, response, &response_len, &algo); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get device pubkey: %s\n", yh_strerror(yrc)); return -1; } if (fmt == fmt_hex) { for (size_t i = 0; i < response_len; i++) { fprintf(ctx->out, "%02x", response[i]); } fprintf(ctx->out, "\n"); return 0; } int nid = algo2nid(algo); EC_GROUP *group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) { fprintf(stderr, "Invalid device public key algorithm\n"); return -1; } EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); EC_KEY *eckey = EC_KEY_new(); EC_KEY_set_group(eckey, group); EC_POINT *point = EC_POINT_new(group); EC_POINT_oct2point(group, point, response, response_len, NULL); EC_KEY_set_public_key(eckey, point); EVP_PKEY *public_key = EVP_PKEY_new(); EVP_PKEY_set1_EC_KEY(public_key, eckey); EC_POINT_free(point); EC_KEY_free(eckey); EC_GROUP_free(group); if (fmt == fmt_PEM) { PEM_write_PUBKEY(ctx->out, public_key); } else if (fmt == fmt_binary) { i2d_PUBKEY_fp(ctx->out, public_key); } else if (fmt == fmt_base64) { bool error = false; BIO *b64 = BIO_new(BIO_f_base64()); if (b64 == NULL) { fprintf(stderr, "Unable to allocate buffer\n"); error = true; goto getdpk_base64_cleanup; } BIO *bio = BIO_new_fp(ctx->out, BIO_NOCLOSE); if (bio == NULL) { fprintf(stderr, "Unable to allocate BIO\n"); BIO_free_all(b64); error = true; goto getdpk_base64_cleanup; } bio = BIO_push(b64, bio); i2d_PUBKEY_bio(bio, public_key); if (BIO_flush(bio) != 1) { fprintf(stderr, "Unable to flush BIO\n"); BIO_free_all(b64); error = true; goto getdpk_base64_cleanup; } BIO_free_all(bio); getdpk_base64_cleanup: if (error) { EVP_PKEY_free(public_key); return -1; } } // FIXME: other formats or error. EVP_PKEY_free(public_key); return 0; } // NOTE: Get object information // argc = 3 // arg 0: e:session // arg 1: w:id // arg 2: t:type int yh_com_get_object_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { yh_object_descriptor object = {0}; UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_get_object_info(argv[0].e, argv[1].w, argv[2].b, &object); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get object info: %s\n", yh_strerror(yrc)); return -1; } char domains[256] = {0}; const char *cap[sizeof(yh_capability) / sizeof(yh_capability[0])] = {0}; size_t n_cap = sizeof(yh_capability) / sizeof(yh_capability[0]); const char *type = 0; const char *algorithm = ""; const char *compressed_str = ""; const char *extra_algo = ""; char *label = object.label; size_t label_len = strlen(label); yh_type_to_string(object.type, &type); if (object.algorithm) { yh_algo_to_string(object.algorithm, &algorithm); if (is_compressed(argv[0].e, object.id, object.algorithm)) { compressed_str = "_compressed"; } extra_algo = ", algorithm: "; } yh_domains_to_string(object.domains, domains, 255); for (size_t i = 0; i < label_len; i++) { if (isprint(label[i]) == 0) { label[i] = '.'; } } fprintf(ctx->out, "id: 0x%04x, type: %s%s%s%s, label: \"%s\", length: %d, " "domains: %s, sequence: %hhu, origin: ", object.id, type, extra_algo, algorithm, compressed_str, label, object.len, domains, object.sequence); if (object.origin & YH_ORIGIN_GENERATED) { fprintf(ctx->out, "generated"); } if (object.origin & YH_ORIGIN_IMPORTED) { fprintf(ctx->out, "imported"); } if (object.origin & YH_ORIGIN_IMPORTED_WRAPPED) { fprintf(ctx->out, ":imported_wrapped"); } fprintf(ctx->out, ", capabilities: "); if (yh_capabilities_to_strings(&object.capabilities, cap, &n_cap) != YHR_SUCCESS) { for (size_t i = 0; i < YH_CAPABILITIES_LEN; i++) { fprintf(ctx->out, "0x%02x%s", object.capabilities.capabilities[i], i < YH_CAPABILITIES_LEN - 1 ? " " : ""); } } else { for (size_t i = 0; i < n_cap; i++) { fprintf(ctx->out, "%s%s", cap[i], i < n_cap - 1 ? ":" : ""); } } if (object.type == YH_WRAP_KEY || object.type == YH_PUBLIC_WRAP_KEY || object.type == YH_AUTHENTICATION_KEY) { fprintf(ctx->out, ", delegated_capabilities: "); n_cap = sizeof(yh_capability) / sizeof(yh_capability[0]); if (yh_capabilities_to_strings(&object.delegated_capabilities, cap, &n_cap) != YHR_SUCCESS) { for (size_t i = 0; i < YH_CAPABILITIES_LEN; i++) { fprintf(ctx->out, "0x%02x%s", object.delegated_capabilities.capabilities[i], i < YH_CAPABILITIES_LEN - 1 ? " " : ""); } } else { for (size_t i = 0; i < n_cap; i++) { fprintf(ctx->out, "%s%s", cap[i], i < n_cap - 1 ? ":" : ""); } } } fprintf(ctx->out, "\n"); return 0; } // NOTE: Get an object under wrap // argc = 5 // arg 0: e:session // arg 1: w:keyid // arg 2: t:type // arg 3: w:id // arg 4: b:include_seed // arg 5: f:file int yh_com_get_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); UNUSED(in_fmt); uint8_t format = argv[4].b ? 1 : 0; yh_rc yrc = yh_util_export_wrapped_ex(argv[0].e, argv[1].w, argv[2].b, argv[3].w, format, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get wrapped object: %s\n", yh_strerror(yrc)); return -1; } if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { return 0; } return -1; } // NOTE: Get an RSA wrapped key or object // argc = 7 // arg 0: e:session // arg 1: w:keyid // arg 2: t:type // arg 3: w:id // arg 4: a:aes // arg 5: a:oaep // arg 6: a:mgf1 // arg 7: f:file static int do_rsa_wrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt, bool key_wrap) { UNUSED(in_fmt); int hash = 0; yh_algorithm aes = argv[4].a; yh_algorithm oaep = argv[5].a; yh_algorithm mgf1 = argv[6].a; yh_rc yrc; if (aes == 0) { aes = YH_ALGO_AES256; } switch (oaep) { case YH_ALGO_RSA_OAEP_SHA1: hash = _SHA1; break; case YH_ALGO_RSA_OAEP_SHA256: hash = _SHA256; break; case YH_ALGO_RSA_OAEP_SHA384: hash = _SHA384; break; case YH_ALGO_RSA_OAEP_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Unrecognized OAEP algorithm\n"); return -1; } uint8_t label[64] = {0}; size_t label_len = sizeof(label); if (hash_bytes(NULL, 0, hash, label, &label_len) == false) { fprintf(stderr, "Unable to hash data\n"); return -1; } uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); if (key_wrap) { yrc = yh_util_get_rsa_wrapped_key(argv[0].e, argv[1].w, argv[2].b, argv[3].w, aes, oaep, mgf1, label, label_len, response, &response_len); } else { yrc = yh_util_export_rsa_wrapped(argv[0].e, argv[1].w, argv[2].b, argv[3].w, aes, oaep, mgf1, label, label_len, response, &response_len); } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to encrypt data with OAEP: %s\n", yh_strerror(yrc)); return yrc; } if (!write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { fprintf(stderr, "Failed to write wrapped object to file"); return YHR_GENERIC_ERROR; } return YHR_SUCCESS; } int yh_com_get_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { return do_rsa_wrap(ctx, argv, in_fmt, fmt, false); } int yh_com_get_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { return do_rsa_wrap(ctx, argv, in_fmt, fmt, true); } // NOTE(adma): Get a template object // argc = 2 // arg 0: e:session, // arg 1: w:object_id int yh_com_get_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { uint8_t response[YH_MSG_BUF_SIZE]; size_t response_len = sizeof(response); UNUSED(in_fmt); yh_rc yrc = yh_util_get_template(argv[0].e, argv[1].w, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get template object: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): No operation command // argc = 0 int yh_com_noop(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); return 0; } // NOTE(adma): List capabilities // argc = 0 int yh_com_list_capabilities(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); for (size_t i = 0; i < sizeof(yh_capability) / sizeof(yh_capability[0]); i++) { fprintf(ctx->out, "%-30s (%016llx)\n", yh_capability[i].name, 1ULL << yh_capability[i].bit); } return 0; } // NOTE: List algorithms // argc = 0 int yh_com_list_algorithms(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); for (size_t i = 0; i < sizeof(yh_algorithms) / sizeof(yh_algorithms[0]); i++) { fprintf(ctx->out, "%s\n", yh_algorithms[i].name); } return 0; } // NOTE: List types // argc = 0 int yh_com_list_types(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); for (uint16_t i = 0; i < sizeof(yh_types) / sizeof(yh_types[0]); i++) { fprintf(ctx->out, "%s\n", yh_types[i].name); } return 0; } // NOTE(adma): List sessions // argc = 0 int yh_com_list_sessions(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } for (size_t i = 0; i < sizeof(ctx->sessions) / sizeof(ctx->sessions[0]); i++) { if (ctx->sessions[i] != NULL) { fprintf(stderr, "Session %zu\n", i); } } return 0; } static int compare_objects(const void *p1, const void *p2) { const yh_object_descriptor *a = p1; const yh_object_descriptor *b = p2; return a->id - b->id; } // NOTE: List object according to a filter // argc = 7 // arg 0: e:session // arg 1: w:id // arg 2: t:type // arg 3: w:domains // arg 4: u:capabilities // arg 5: a:algorithm // arg 6: b:with-compression // arg 7: s:label int yh_com_list_objects(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { yh_object_descriptor objects[YH_MAX_ITEMS_COUNT] = {0}; size_t num_objects = YH_MAX_ITEMS_COUNT; const char *label_arg = 0; UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (argv[7].len == 0) { label_arg = NULL; } else { label_arg = argv[7].s; } yh_rc yrc = yh_util_list_objects(argv[0].e, argv[1].w, argv[2].b, argv[3].w, &argv[4].c, argv[5].a, label_arg, objects, &num_objects); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to list objects: %s\n", yh_strerror(yrc)); return -1; } qsort(objects, num_objects, sizeof(yh_object_descriptor), compare_objects); fprintf(ctx->out, "Found %zu object(s)\n", num_objects); for (size_t i = 0; i < num_objects; i++) { yrc = yh_util_get_object_info(argv[0].e, objects[i].id, objects[i].type, &objects[i]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get object info: %s\n", yh_strerror(yrc)); return -1; } const char *type = ""; yh_type_to_string(objects[i].type, &type); const char *algo = ""; yh_algo_to_string(objects[i].algorithm, &algo); const char *compressed = ""; if (argv[6].b && is_compressed(argv[0].e, objects[i].id, objects[i].algorithm)) { compressed = "_compressed"; } fprintf(ctx->out, "id: 0x%04x, type: %s, algo: %s%s, sequence: %hhu, label: %s\n", objects[i].id, type, algo, compressed, objects[i].sequence, objects[i].label); } return 0; } // NOTE(adma): Open a session with a connector using an Authentication Key // argc = 2 // arg 0: w:authkey // arg 1: i:password int yh_com_open_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } yh_session *ses = NULL; yh_rc yrc = YHR_SUCCESS; if (in_fmt == fmt_password) { yrc = yh_create_session_derived(ctx->connector, argv[0].w, argv[1].x, argv[1].len, false, &ses); } else { yrc = yh_create_session(ctx->connector, argv[0].w, argv[1].x, argv[1].len / 2, argv[1].x + argv[1].len / 2, argv[1].len / 2, false, &ses); } insecure_memzero(argv[1].x, argv[1].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); return -1; } uint8_t session_id = 0; yrc = yh_get_session_id(ses, &session_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get session id: %s\n", yh_strerror(yrc)); return -1; } if (ctx->sessions[session_id] != NULL) { yrc = yh_destroy_session(&ctx->sessions[session_id]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy old session with same id (%d): %s\n", session_id, yh_strerror(yrc)); return -1; } } ctx->sessions[session_id] = ses; fprintf(stderr, "Created session %d\n", session_id); return 0; } // NOTE: Open a session with a connector using an Asymmetric // Authentication Key argc = 2 arg 0: w:authkey arg 1: i:password int yh_com_open_session_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } uint16_t authkey = argv[0].w; uint8_t privkey[YH_EC_P256_PRIVKEY_LEN] = {0}; yh_rc yrc = YHR_SUCCESS; if (in_fmt == fmt_password) { uint8_t pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; yrc = yh_util_derive_ec_p256_key(argv[1].x, argv[1].len, privkey, sizeof(privkey), pubkey, sizeof(pubkey)); insecure_memzero(argv[1].x, argv[1].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to derive asymmetric authentication key: %s\n", yh_strerror(yrc)); return -1; } } else if (in_fmt == fmt_PEM) { yh_algorithm algo; size_t len = sizeof(privkey); if (!read_private_key(argv[1].x, argv[1].len, &algo, privkey, &len, false)) { fprintf(stderr, "Failed to PEM decode asymmetric authentication key\n"); return -1; } if (len != sizeof(privkey)) { fprintf(stderr, "Invalid asymmetric authentication key\n"); return -1; } } else if (argv[1].len <= sizeof(privkey)) { memset(privkey, 0, sizeof(privkey) - argv[1].len); memcpy(privkey + sizeof(privkey) - argv[1].len, argv[1].x, argv[1].len); insecure_memzero(argv[1].x, argv[1].len); } else { insecure_memzero(argv[1].x, argv[1].len); fprintf(stderr, "Invalid asymmetric authkey: %s\n", yh_strerror(YHR_INVALID_PARAMETERS)); return -1; } uint8_t device_pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; size_t device_pubkey_len = sizeof(device_pubkey); yrc = yh_util_get_device_pubkey(ctx->connector, device_pubkey, &device_pubkey_len, NULL); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to retrieve device pubkey: %s\n", yh_strerror(yrc)); return -1; } if (device_pubkey_len != YH_EC_P256_PUBKEY_LEN) { fprintf(stderr, "Invalid device pubkey\n"); return -1; } int matched = 0; for (uint8_t **pubkey = ctx->device_pubkey_list; *pubkey; pubkey++) { if (!memcmp(*pubkey, device_pubkey, device_pubkey_len)) { matched++; break; } } if (ctx->device_pubkey_list[0] == NULL) { fprintf(stderr, "CAUTION: Device public key (PK.SD) not validated\n"); for (size_t i = 0; i < device_pubkey_len; i++) fprintf(stderr, "%02x", device_pubkey[i]); fprintf(stderr, "\n"); } else if (matched == 0) { fprintf(stderr, "Failed to validate device pubkey\n"); return -1; } yh_session *ses = NULL; yrc = yh_create_session_asym(ctx->connector, authkey, privkey, sizeof(privkey), device_pubkey, device_pubkey_len, &ses); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); return -1; } uint8_t session_id = 0; yrc = yh_get_session_id(ses, &session_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get session id: %s\n", yh_strerror(yrc)); return -1; } if (ctx->sessions[session_id] != NULL) { yrc = yh_destroy_session(&ctx->sessions[session_id]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy old session with same id (%d): %s\n", session_id, yh_strerror(yrc)); return -1; } } ctx->sessions[session_id] = ses; fprintf(stderr, "Created session %d\n", session_id); return 0; } // NOTE: Open a session using a key stored on YubiKey // argc = 3 // arg 0: w:authkey // arg 1: s:name // arg 2: i:password // arg 3: s:reader int yh_com_open_yksession(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } ykhsmauth_rc ykhsmauthrc = ykhsmauth_connect(ctx->state, argv[3].s); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to connect to the YubiKey: %s\n", ykhsmauth_strerror(ykhsmauthrc)); return -1; } uint8_t host_challenge[YH_EC_P256_PUBKEY_LEN] = {0}; size_t host_challenge_len = sizeof(host_challenge); uint8_t major = 0, minor = 0, patch = 0; ykhsmauthrc = ykhsmauth_get_version_ex(ctx->state, &major, &minor, &patch); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to get YubiKey firmware version: %s\n", ykhsmauth_strerror(ykhsmauthrc)); ykhsmauth_disconnect(ctx->state); return -1; } if (major > 5 || (major == 5 && minor > 7) || (major == 5 && minor == 7 && patch >= 1) || (major == 0 && minor == 0 && patch == 1)) { ykhsmauthrc = ykhsmauth_get_challenge_ex(ctx->state, argv[1].s, argv[2].x, argv[2].len, host_challenge, &host_challenge_len); } else { ykhsmauthrc = ykhsmauth_get_challenge(ctx->state, argv[1].s, host_challenge, &host_challenge_len); } if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to get host challenge from the YubiKey: %s\n", ykhsmauth_strerror(ykhsmauthrc)); ykhsmauth_disconnect(ctx->state); return -1; } uint8_t card_pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; size_t card_pubkey_len = 0; yh_rc yrc = YHR_SUCCESS; if (host_challenge_len == YH_EC_P256_PUBKEY_LEN) { card_pubkey_len = sizeof(card_pubkey); yrc = yh_util_get_device_pubkey(ctx->connector, card_pubkey, &card_pubkey_len, NULL); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to retrieve device pubkey: %s\n", yh_strerror(yrc)); ykhsmauth_disconnect(ctx->state); return -1; } if (card_pubkey_len != YH_EC_P256_PUBKEY_LEN) { fprintf(stderr, "Invalid device pubkey\n"); ykhsmauth_disconnect(ctx->state); return -1; } int matched = 0; for (uint8_t **pubkey = ctx->device_pubkey_list; *pubkey; pubkey++) { if (!memcmp(*pubkey, card_pubkey, card_pubkey_len)) { matched++; break; } } if (ctx->device_pubkey_list[0] == NULL) { fprintf(stderr, "CAUTION: Device public key (PK.SD) not validated\n"); for (size_t i = 0; i < card_pubkey_len; i++) fprintf(stderr, "%02x", card_pubkey[i]); fprintf(stderr, "\n"); } else if (matched == 0) { fprintf(stderr, "Failed to validate device pubkey\n"); ykhsmauth_disconnect(ctx->state); return -1; } } uint8_t card_cryptogram[YH_KEY_LEN] = {0}; size_t card_cryptogram_len = sizeof(card_cryptogram); uint8_t *yh_context = 0; yh_session *ses = NULL; yrc = yh_begin_create_session(ctx->connector, argv[0].w, &yh_context, host_challenge, &host_challenge_len, card_cryptogram, &card_cryptogram_len, &ses); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); ykhsmauth_disconnect(ctx->state); return -1; } uint8_t key_s_enc[YH_KEY_LEN] = {0}; uint8_t key_s_mac[YH_KEY_LEN] = {0}; uint8_t key_s_rmac[YH_KEY_LEN] = {0}; uint8_t retries = 0; ykhsmauthrc = ykhsmauth_calculate_ex(ctx->state, argv[1].s, yh_context, 2 * host_challenge_len, card_pubkey, card_pubkey_len, card_cryptogram, card_cryptogram_len, argv[2].x, argv[2].len, key_s_enc, sizeof(key_s_enc), key_s_mac, sizeof(key_s_mac), key_s_rmac, sizeof(key_s_rmac), &retries); insecure_memzero(argv[2].x, argv[2].len); ykhsmauth_disconnect(ctx->state); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to get session keys from the YubiKey: %s", ykhsmauth_strerror(ykhsmauthrc)); if (ykhsmauthrc == YKHSMAUTHR_WRONG_PW) { fprintf(stderr, ", %d attempts remaining", retries); } fprintf(stderr, "\n"); return -1; } yrc = yh_finish_create_session(ses, key_s_enc, sizeof(key_s_enc), key_s_mac, sizeof(key_s_mac), key_s_rmac, sizeof(key_s_rmac), card_cryptogram, card_cryptogram_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); return -1; } uint8_t session_id = 0; yrc = yh_get_session_id(ses, &session_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); return -1; } if (ctx->sessions[session_id] != NULL) { yrc = yh_destroy_session(&ctx->sessions[session_id]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy old session with same id (%d): %s\n", session_id, yh_strerror(yrc)); return -1; } } ctx->sessions[session_id] = ses; fprintf(stderr, "Created session %d\n", session_id); return 0; } // NOTE(adma): Send unauthenticated echo // argc = 2 // arg 0: b:byte // arg 1: w:count int yh_com_pecho(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; uint16_t data_len = 0; uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = 0; yh_cmd response_cmd = 0; if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } uint8_t byte = argv[0].b; uint16_t count = argv[1].w; if (count > YH_MSG_BUF_SIZE) { fprintf(stderr, "Count must be in [0, %d]\n", YH_MSG_BUF_SIZE); return -1; } memset(data, byte, count); data_len = count; response_len = sizeof(response); yh_rc yrc = yh_send_plain_msg(ctx->connector, YHC_ECHO, data, data_len, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to send ECHO command: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Response (%zu bytes):\n", response_len); for (size_t i = 0; i < response_len; i++) { if (i && !(i % 64)) fprintf(ctx->out, "\n"); else if (i && !(i % 8)) fprintf(ctx->out, " "); fprintf(ctx->out, "%02x", response[i]); } fprintf(ctx->out, "\n"); return 0; } // Store a symmetric key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: i:key int yh_com_put_symmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc; if (yh_is_aes(argv[5].a)) { if ((argv[5].a == YH_ALGO_AES128 && argv[6].len != 16) || (argv[5].a == YH_ALGO_AES192 && argv[6].len != 24) || (argv[5].a == YH_ALGO_AES256 && argv[6].len != 32)) { fprintf(stderr, "Key length (%zu) not matching, should be 16, 24 or 32\n", argv[6].len); return -1; } yrc = yh_util_import_aes_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a, argv[6].x); } else { fprintf(stderr, "Invalid algorithm\n"); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store symmetric key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored symmetric key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Store an asymmetric key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: x:key int yh_com_put_asymmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t key[512] = {0}; size_t key_material_len = sizeof(key); yh_algorithm algorithm = 0; bool ret = read_private_key(argv[5].x, argv[5].len, &algorithm, key, &key_material_len, false); if (ret == false) { fprintf(stderr, "Unable to read asymmetric key\n"); return -1; } yh_rc yrc = YHR_SUCCESS; switch (algorithm) { case YH_ALGO_RSA_2048: case YH_ALGO_RSA_3072: case YH_ALGO_RSA_4096: yrc = yh_util_import_rsa_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algorithm, key, key + key_material_len / 2); break; case YH_ALGO_EC_P224: case YH_ALGO_EC_P256: case YH_ALGO_EC_P384: case YH_ALGO_EC_P521: case YH_ALGO_EC_K256: case YH_ALGO_EC_BP256: case YH_ALGO_EC_BP384: case YH_ALGO_EC_BP512: yrc = yh_util_import_ec_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algorithm, key); break; case YH_ALGO_EC_ED25519: yrc = yh_util_import_ed_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algorithm, key); break; default: fprintf(stderr, "Unsupported algorithm\n"); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store asymmetric key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Asymmetric key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Store an authentication key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: x:password int yh_com_put_authentication(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_import_authentication_key_derived(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, &argv[5].c, argv[6].x, argv[6].len); insecure_memzero(argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store authkey: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Authentication key 0x%04x\n", argv[1].w); return 0; } // NOTE: Store an asymmetric authentication key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: x:password int yh_com_put_authentication_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(fmt); yh_rc yrc = YHR_SUCCESS; uint8_t pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; if (in_fmt == fmt_password) { uint8_t privkey[YH_EC_P256_PRIVKEY_LEN] = {0}; yrc = yh_util_derive_ec_p256_key(argv[6].x, argv[6].len, privkey, sizeof(privkey), pubkey, sizeof(pubkey)); insecure_memzero(argv[6].x, argv[6].len); insecure_memzero(privkey, sizeof(privkey)); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to derive asymmetric authentication key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Derived public key (PK.OCE)\n"); for (size_t i = 0; i < sizeof(pubkey); i++) fprintf(stderr, "%02x", pubkey[i]); fprintf(stderr, "\n"); } else if (in_fmt == fmt_PEM) { yh_algorithm algo = 0; size_t pubkey_len = sizeof(pubkey); if (!read_public_key(argv[6].x, argv[6].len, &algo, pubkey, &pubkey_len)) { fprintf(stderr, "Failed to load public key\n"); return -1; } if (pubkey_len != sizeof(pubkey)) { fprintf(stderr, "Invalid public key\n"); return -1; } } else if (argv[6].len <= sizeof(pubkey)) { memset(pubkey, 0, sizeof(pubkey) - argv[6].len); memcpy(pubkey + sizeof(pubkey) - argv[6].len, argv[6].x, argv[6].len); } else { fprintf(stderr, "Invalid asymmetric authkey: %s\n", yh_strerror(YHR_INVALID_PARAMETERS)); return -1; } yrc = yh_util_import_authentication_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, &argv[5].c, pubkey + 1, sizeof(pubkey) - 1, NULL, 0); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store asymmetric authkey: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Asymmetric Authentication key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Store an opaque object // argc = 6 // arg 0: e:session // arg 1: w:object_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: b:with-compression // 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[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 // explicitly set BIO *bio = BIO_new_mem_buf(data, len); if (!bio) { fprintf(stderr, "Couldn't wrap PEM-encoded certificate data\n"); return 0; } X509 *cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); if (!cert) { fprintf(stderr, "Couldn't parse PEM-encoded certificate\n"); BIO_free(bio); return 0; } BIO_free(bio); len = i2d_X509(cert, 0); if (len > sizeof(buf)) { fprintf(stderr, "Decoded certificate is too large: %zu\n", len); X509_free(cert); return 0; } data = buf; i2d_X509(cert, &data); data = buf; X509_free(cert); } else if (argv[5].a == YH_ALGO_OPAQUE_X509_CERTIFICATE) { // Enforce valid X.509 certificate const unsigned char *p = data; X509 *cert = d2i_X509(NULL, &p, len); if (!cert) { fprintf(stderr, "Couldn't parse DER-encoded certificate\n"); return 0; } X509_free(cert); } #ifdef ENABLE_CERT_COMPRESS if (argv[6].a && argv[5].a != YH_ALGO_OPAQUE_X509_CERTIFICATE) { fprintf(stderr, "Compression is only supported for X.509 certificates\n"); return -1; } #endif size_t import_len = 0; 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, data, len, argv[6].a ? COMPRESS : NO_COMPRESS, &import_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store opaque object: %s\n", yh_strerror(yrc)); #ifdef ENABLE_CERT_COMPRESS if (yrc == YHR_BUFFER_TOO_SMALL && !argv[6].a && argv[5].a == YH_ALGO_OPAQUE_X509_CERTIFICATE) { fprintf(stderr, "Try compressing the certificate by using the " "'with-compression' flag. Beware that " "compressed certificates cannot be used for attestation\n"); } #endif return -1; } fprintf(stderr, "Stored %zu bytes to Opaque object 0x%04x\n", import_len, argv[1].w); return 0; } // NOTE(adma): Set a global option value // argc = 3 // arg 0: e:session // arg 1: o:option // arg 2: x:value int yh_com_put_option(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_set_option(argv[0].e, argv[1].o, argv[2].len, argv[2].x); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store option: %s\n", yh_strerror(yrc)); return -1; } return 0; } // NOTE: Put a HMAC key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: x:key int yh_com_put_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (argv[6].len > 128) { fprintf(stderr, "Too long key supplied, max 128 bytes allowed\n"); return -1; } yh_rc yrc = yh_util_import_hmac_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a, argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store HMAC key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored HMAC key 0x%04x\n", argv[1].w); return 0; } // NOTE: Store a wrapping key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: x:key int yh_com_put_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_algorithm algo = 0; if (argv[6].len == 16) { algo = YH_ALGO_AES128_CCM_WRAP; } else if (argv[6].len == 24) { algo = YH_ALGO_AES192_CCM_WRAP; } else if (argv[6].len == 32) { algo = YH_ALGO_AES256_CCM_WRAP; } else { fprintf(stderr, "Key length not matching, should be 16, 24 or 32\n"); return -1; } yh_rc yrc = yh_util_import_wrap_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algo, &argv[5].c, argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapkey: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Wrap key 0x%04x\n", argv[1].w); return 0; } // NOTE: Store an RSA wrapping key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: x:key int yh_com_put_rsa_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t key[512] = {0}; size_t key_material_len = sizeof(key); yh_algorithm algo = 0; bool ret = read_private_key(argv[6].x, argv[6].len, &algo, key, &key_material_len, false); if (ret == false) { fprintf(stderr, "Unable to read wrap key\n"); return -1; } yh_rc yrc = yh_util_import_wrap_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algo, &argv[5].c, key, key_material_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapkey: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Wrap key 0x%04x\n", argv[1].w); return 0; } static bool read_rsa_pubkey(const uint8_t *buf, size_t len, uint8_t *bytes, size_t *bytes_len) { BIO *bio; if ((bio = BIO_new(BIO_s_mem())) == NULL) return false; if(BIO_write(bio, buf, len) <= 0) { fprintf(stderr, "%s: Failed to read RSA public key\n", __func__); BIO_free_all(bio); return false; } RSA *rsa = NULL; EVP_PKEY *pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); BIO_free_all(bio); if (pubkey == NULL || EVP_PKEY_base_id(pubkey) != EVP_PKEY_RSA || (rsa = EVP_PKEY_get1_RSA(pubkey)) == NULL) { fprintf(stderr, "Failed to parse RSA public key\n"); EVP_PKEY_free(pubkey); return false; } bool ret = false; const BIGNUM *n = NULL; RSA_get0_key(rsa, &n, NULL, NULL); if (n == NULL) { goto fail; } size_t nn = BN_num_bytes(n); if (*bytes_len < nn) { fprintf(stderr, "%s: insufficient dst buffer space\n", __func__); goto fail; } *bytes_len = (size_t) BN_bn2bin(n, bytes); ret = true; fail: RSA_free(rsa); EVP_PKEY_free(pubkey); return ret; } // NOTE: Store a public wrap key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: i:pubkey int yh_com_put_public_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t pubkey[512]; size_t pubkey_len = sizeof(pubkey); yh_algorithm algo = 0; if (!read_rsa_pubkey(argv[6].x, argv[6].len, pubkey, &pubkey_len)) { fprintf(stderr, "Failed to read public key\n"); return -1; } switch (pubkey_len) { case 256: algo = YH_ALGO_RSA_2048; break; case 384: algo = YH_ALGO_RSA_3072; break; case 512: algo = YH_ALGO_RSA_4096; break; default: fprintf(stderr, "Invalid public key length (%zu)\n", pubkey_len); return -1; } yh_rc yrc = yh_util_import_public_wrap_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algo, &argv[5].c, pubkey, pubkey_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store public wrap key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored public wrap key 0x%04x\n", argv[1].w); return 0; } // NOTE: Store a wrapped object // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_put_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_object_type object_type = 0; uint16_t object_id = 0; yh_rc yrc = yh_util_import_wrapped(argv[0].e, argv[1].w, argv[2].x, argv[2].len, &object_type, &object_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapped object: %s\n", yh_strerror(yrc)); return -1; } const char *type = ""; yh_type_to_string(object_type, &type); fprintf(stderr, "Object imported as 0x%04x of type %s\n", object_id, type); return 0; } // NOTE: Store an asymetrically wrapped object // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: a:oaep // arg 3: a:mgf1 // arg 4: i:data int yh_com_put_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_object_type object_type = 0; uint16_t object_id = 0; yh_algorithm mgf1 = argv[3].a; yh_algorithm oaep = argv[2].a; int hash = 0; switch (oaep) { case YH_ALGO_RSA_OAEP_SHA1: hash = _SHA1; break; case YH_ALGO_RSA_OAEP_SHA256: hash = _SHA256; break; case YH_ALGO_RSA_OAEP_SHA384: hash = _SHA384; break; case YH_ALGO_RSA_OAEP_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Unrecognized OAEP algorithm\n"); return -1; } uint8_t label[64] = {0}; size_t label_len = sizeof(label); if (hash_bytes(NULL, 0, hash, label, &label_len) == false) { fprintf(stderr, "Unable to hash data.\n"); return -1; } yh_rc yrc = yh_util_import_rsa_wrapped(argv[0].e, argv[1].w, oaep, mgf1, label, label_len, argv[4].x, argv[4].len, &object_type, &object_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapped object: %s\n", yh_strerror(yrc)); return -1; } const char *type = ""; yh_type_to_string(object_type, &type); fprintf(stderr, "Object imported as 0x%04x of type %s\n", object_id, type); return 0; } // NOTE: Store an asymetrically wrapped key object // argc = 3 // arg 0: e:session // arg 1: w:wrapkey_id // arg 2: t:type // arg 3: w:key_id // arg 4: a:key_algorithm // arg 5: s:label // arg 6: w:domains // arg 7: c:capabilities // arg 8: a:oaep // arg 9: a:mgf1 // arg 10: i:data int yh_com_put_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_object_type object_type = argv[2].t; uint16_t object_id = argv[3].w; yh_algorithm mgf1 = argv[9].a; yh_algorithm oaep = argv[8].a; int hash = 0; switch (oaep) { case YH_ALGO_RSA_OAEP_SHA1: hash = _SHA1; break; case YH_ALGO_RSA_OAEP_SHA256: hash = _SHA256; break; case YH_ALGO_RSA_OAEP_SHA384: hash = _SHA384; break; case YH_ALGO_RSA_OAEP_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Unrecognized OAEP algorithm\n"); return -1; } uint8_t label[64] = {0}; size_t label_len = sizeof(label); if (hash_bytes(NULL, 0, hash, label, &label_len) == false) { fprintf(stderr, "Unable to hash data\n"); return -1; } yh_rc yrc = yh_util_put_rsa_wrapped_key(argv[0].e, argv[1].w, object_type, &object_id, argv[4].a, argv[5].s, argv[6].w, &argv[7].c, oaep, mgf1, label, label_len, argv[10].x, argv[10].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapped object: %s\n", yh_strerror(yrc)); return -1; } const char *type = ""; yh_type_to_string(object_type, &type); fprintf(stderr, "Object imported as 0x%04x of type %s\n", object_id, type); return 0; } // NOTE(adma): Store a template object // argc = 7 // arg 0: e:session // arg 1: w:object_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: i:datafile int yh_com_put_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_import_template(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a, argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store template object: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Template object 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Sign data using ECDSA // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: i:datafile int yh_com_sign_ecdsa(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); int hash = 0; switch (argv[2].a) { case YH_ALGO_EC_ECDSA_SHA1: hash = _SHA1; break; case YH_ALGO_EC_ECDSA_SHA256: hash = _SHA256; break; case YH_ALGO_EC_ECDSA_SHA384: hash = _SHA384; break; case YH_ALGO_EC_ECDSA_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Invalid hash algorithm\n"); return -1; } if (hash_bytes(argv[3].x, argv[3].len, hash, data, &data_len) == false) { fprintf(stderr, "Unable to hash file\n"); return -1; } yh_rc yrc = yh_util_sign_ecdsa(argv[0].e, argv[1].w, data, data_len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with ecdsa: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Sign data using EDDSA // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: i:datafile int yh_com_sign_eddsa(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); if (argv[2].a != YH_ALGO_EC_ED25519) { fprintf(stderr, "Invalid algorithm\n"); return -1; } yh_rc yrc = yh_util_sign_eddsa(argv[0].e, argv[1].w, argv[3].x, argv[3].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with eddsa: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Sign data using RSASSA-PKCS#1v1.5 // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: f:datafile int yh_com_sign_pkcs1v1_5(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); int hash = 0; switch (argv[2].a) { case YH_ALGO_RSA_PKCS1_SHA1: hash = _SHA1; break; case YH_ALGO_RSA_PKCS1_SHA256: hash = _SHA256; break; case YH_ALGO_RSA_PKCS1_SHA384: hash = _SHA384; break; case YH_ALGO_RSA_PKCS1_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Invalid hash algorithm\n"); return -1; } if (hash_bytes(argv[3].x, argv[3].len, hash, data, &data_len) == false) { fprintf(stderr, "Unable to hash file\n"); return -1; } yh_rc yrc = yh_util_sign_pkcs1v1_5(argv[0].e, argv[1].w, true, data, data_len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with PKCS#1v1.5: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Sign data using RSASSA-PSS // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: f:datafile int yh_com_sign_pss(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); int hash = 0; yh_algorithm mgf = 0; switch (argv[2].a) { case YH_ALGO_RSA_PSS_SHA1: hash = _SHA1; mgf = YH_ALGO_MGF1_SHA1; break; case YH_ALGO_RSA_PSS_SHA256: hash = _SHA256; mgf = YH_ALGO_MGF1_SHA256; break; case YH_ALGO_RSA_PSS_SHA384: hash = _SHA384; mgf = YH_ALGO_MGF1_SHA384; break; case YH_ALGO_RSA_PSS_SHA512: hash = _SHA512; mgf = YH_ALGO_MGF1_SHA512; break; default: fprintf(stderr, "Invalid hash algorithm\n"); return -1; } if (hash_bytes(argv[3].x, argv[3].len, hash, data, &data_len) == false) { fprintf(stderr, "Unable to hash file\n"); return -1; } // NOTE(adma): Salt length always matches the length of the hash yh_rc yrc = yh_util_sign_pss(argv[0].e, argv[1].w, data, data_len, response, &response_len, data_len, mgf); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with PSS: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Extract the version number, serial number and supported // algorithms // argc = 0 int yh_com_get_device_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } yh_device_info device_info = {0}; yh_rc yrc = yh_util_get_device_info_ex(ctx->connector, &device_info); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get device info: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Version number:\t\t%hhu.%hhu.%hhu\n", device_info.major, device_info.minor, device_info.patch); fprintf(ctx->out, "Serial number:\t\t%u\n", device_info.serial); fprintf(ctx->out, "Log used:\t\t%d/%d\n", device_info.log_used, device_info.log_total); fprintf(ctx->out, "Supported algorithms:\t"); for (size_t i = 0; i < device_info.n_algorithms; i++) { const char *algo_str; yh_algo_to_string(device_info.algorithms[i], &algo_str); fprintf(ctx->out, "%s, ", algo_str); if ((i + 1) % 3 == 0 && i != 0) { fprintf(ctx->out, "\n\t\t\t"); } } fprintf(ctx->out, "\n"); char part_number[256] = {0}; size_t part_number_len = sizeof(part_number); yrc = yh_util_get_partnumber(ctx->connector, part_number, &part_number_len); if (yrc == YHR_SUCCESS && part_number_len > 0) { fprintf(ctx->out, "Part number:\t\t%s\n", part_number); } return 0; } // NOTE: HMAC data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: x:data int yh_com_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_sign_hmac(argv[0].e, argv[1].w, argv[2].x, argv[2].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to HMAC data: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Reset device // argc = 1 // arg 0: e:session int yh_com_reset(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_reset_device(argv[0].e); if (yrc != YHR_CONNECTOR_ERROR && yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to reset device: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Device successfully reset\n"); return 0; } // NOTE: Delete an object // argc = 3 // arg 0: e:session // arg 1: w:id // arg 2: t:type int yh_com_delete(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_delete_object(argv[0].e, argv[1].w, argv[2].t); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to delete object: %s\n", yh_strerror(yrc)); return -1; } // TODO(adma): the order of the arguments should be changed to id and type return 0; } // NOTE(adma): Sign an SSH public key // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: w:template_id // arg 3: a:algorithm // arg 4: i:datafile int yh_com_sign_ssh_certificate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); // TODO: respect output format uint8_t data[YH_MSG_BUF_SIZE + 1024] = {0}; size_t response_len = sizeof(data); if (argv[4].len > YH_MSG_BUF_SIZE) { fprintf(stderr, "Failed to sign ssh certificate: %s. Data too long\n", yh_strerror(YHR_BUFFER_TOO_SMALL)); return -1; } const size_t certdata_offset = 4 + 256; // 4 bytes timestamp + 256 byte signature if(argv[4].len < certdata_offset) { fprintf(stderr, "Failed to sign ssh certificate: %s. Data too short.\n", yh_strerror(YHR_WRONG_LENGTH)); return -1; } memcpy(data, argv[4].x, argv[4].len); response_len -= argv[4].len; yh_rc yrc = yh_util_sign_ssh_certificate(argv[0].e, argv[1].w, argv[2].w, argv[3].a, data, argv[4].len, data + argv[4].len, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get certificate signature: %s\n", yh_strerror(yrc)); return -1; } BIO *b64 = BIO_new(BIO_f_base64()); if (b64 == NULL) { fprintf(stderr, "Failed to sign SSH certificate.\n"); return -1; } BIO *bio = BIO_new(BIO_s_mem()); if (bio == NULL) { fprintf(stderr, "Failed to sign SSH certificate.\n"); BIO_free_all(b64); return -1; } bio = BIO_push(b64, bio); int ret = 0; int cert_len = argv[4].len - certdata_offset + response_len; BUF_MEM *bufferPtr = 0; BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); if (BIO_write(bio, data + certdata_offset, cert_len) != cert_len) { fprintf(stderr, "Failed to write SSH certificate.\n"); ret = -1; goto clean_bio; } if (BIO_flush(bio) != 1) { fprintf(stderr, "Failed to sign SSH certificate.\n"); ret = -1; goto clean_bio; } BIO_get_mem_ptr(bio, &bufferPtr); const char *ssh_cert_str = "ssh-rsa-cert-v01@openssh.com "; // TODO(adma): ECDSA if (fwrite(ssh_cert_str, 1, strlen(ssh_cert_str), ctx->out) != strlen(ssh_cert_str) || ferror(ctx->out)) { fprintf(stderr, "Unable to write data to file\n"); ret = -1; goto clean_bio; } if (fwrite(bufferPtr->data, 1, bufferPtr->length, ctx->out) != bufferPtr->length || ferror(ctx->out)) { fprintf(stderr, "Unable to write data to file\n"); ret = -1; goto clean_bio; } if (fwrite("\n", 1, 1, ctx->out) != 1 || ferror(ctx->out)) { fprintf(stderr, "Unable to write data to file\n"); ret = -1; } clean_bio: BIO_free_all(bio); return ret; } static void time_elapsed(struct timeval *after, struct timeval *before, struct timeval *result) { result->tv_sec = after->tv_sec - before->tv_sec; result->tv_usec = after->tv_usec - before->tv_usec; if (result->tv_usec < 0) { result->tv_sec--; result->tv_usec += 1000000; } } static void time_add(struct timeval *a, struct timeval *b, struct timeval *result) { result->tv_sec = a->tv_sec + b->tv_sec; result->tv_usec = a->tv_usec + b->tv_usec; if (result->tv_usec >= 1000000) { result->tv_sec++; result->tv_usec -= 1000000; } } static void time_average(struct timeval *in, size_t num, struct timeval *result) { time_t remains = in->tv_sec % num; result->tv_sec = in->tv_sec / num; result->tv_usec = in->tv_usec / num; if (remains) { remains *= 1000000; result->tv_usec += remains / num; } } static double time_tps(struct timeval *in, size_t num) { double time = in->tv_sec + (double) in->tv_usec / 1000000; return num / time; } static bool time_less(struct timeval *a, struct timeval *b) { if (a->tv_sec < b->tv_sec) { return true; } else if (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec) { return true; } else { return false; } } static int compare_algorithm(const void *a, const void *b) { return (*(const yh_algorithm *) a - *(const yh_algorithm *) b); } static yh_algorithm *algorithm_search(yh_algorithm key, const yh_algorithm *arr, size_t count) { return bsearch(&key, arr, count, sizeof(key), compare_algorithm); } // NOTE: Run a set of benchmarks // argc = 3 // arg 0: e:session // arg 1: d:count // arg 2: w:key_id // arg 3: a:algorithm int yh_com_benchmark(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); struct { yh_algorithm algo; yh_algorithm algo2; uint16_t bytes; const char *special; } benchmarks[] = { {YH_ALGO_RSA_2048, YH_ALGO_RSA_PKCS1_SHA256, 32, ""}, {YH_ALGO_RSA_3072, YH_ALGO_RSA_PKCS1_SHA384, 48, ""}, {YH_ALGO_RSA_4096, YH_ALGO_RSA_PKCS1_SHA512, 64, ""}, {YH_ALGO_RSA_2048, YH_ALGO_RSA_PSS_SHA256, 32, ""}, {YH_ALGO_RSA_3072, YH_ALGO_RSA_PSS_SHA384, 48, ""}, {YH_ALGO_RSA_4096, YH_ALGO_RSA_PSS_SHA512, 64, ""}, {YH_ALGO_EC_P224, YH_ALGO_EC_ECDSA_SHA1, 20, ""}, {YH_ALGO_EC_P256, YH_ALGO_EC_ECDSA_SHA256, 32, ""}, {YH_ALGO_EC_P384, YH_ALGO_EC_ECDSA_SHA384, 48, ""}, {YH_ALGO_EC_P521, YH_ALGO_EC_ECDSA_SHA512, 66, ""}, {YH_ALGO_EC_K256, YH_ALGO_EC_ECDSA_SHA256, 32, ""}, {YH_ALGO_EC_BP256, YH_ALGO_EC_ECDSA_SHA256, 32, ""}, {YH_ALGO_EC_BP384, YH_ALGO_EC_ECDSA_SHA384, 48, ""}, {YH_ALGO_EC_BP512, YH_ALGO_EC_ECDSA_SHA512, 64, ""}, {YH_ALGO_EC_P224, YH_ALGO_EC_ECDH, 56, ""}, {YH_ALGO_EC_P256, YH_ALGO_EC_ECDH, 64, ""}, {YH_ALGO_EC_P384, YH_ALGO_EC_ECDH, 96, ""}, {YH_ALGO_EC_P521, YH_ALGO_EC_ECDH, 132, ""}, {YH_ALGO_EC_K256, YH_ALGO_EC_ECDH, 64, ""}, {YH_ALGO_EC_BP256, YH_ALGO_EC_ECDH, 64, ""}, {YH_ALGO_EC_BP384, YH_ALGO_EC_ECDH, 96, ""}, {YH_ALGO_EC_BP512, YH_ALGO_EC_ECDH, 128, ""}, {YH_ALGO_EC_ED25519, 0, 32, "32 bytes data"}, {YH_ALGO_EC_ED25519, 0, 64, "64 bytes data"}, {YH_ALGO_EC_ED25519, 0, 128, "128 bytes data"}, {YH_ALGO_EC_ED25519, 0, 256, "256 bytes data"}, {YH_ALGO_EC_ED25519, 0, 512, "512 bytes data"}, {YH_ALGO_EC_ED25519, 0, 1024, "1024 bytes data"}, {YH_ALGO_HMAC_SHA1, 0, 64, ""}, {YH_ALGO_HMAC_SHA256, 0, 64, ""}, {YH_ALGO_HMAC_SHA384, 0, 128, ""}, {YH_ALGO_HMAC_SHA512, 0, 128, ""}, {YH_ALGO_AES128_CCM_WRAP, 0, 0, ""}, {YH_ALGO_AES192_CCM_WRAP, 0, 0, ""}, {YH_ALGO_AES256_CCM_WRAP, 0, 0, ""}, {YH_ALGO_AES128_CCM_WRAP, 0, 128, "1024 bytes data"}, {YH_ALGO_AES192_CCM_WRAP, 0, 128, "1024 bytes data"}, {YH_ALGO_AES256_CCM_WRAP, 0, 128, "1024 bytes data"}, {YH_ALGO_AES128_YUBICO_OTP, 0, 0, ""}, {YH_ALGO_AES192_YUBICO_OTP, 0, 0, ""}, {YH_ALGO_AES256_YUBICO_OTP, 0, 0, ""}, {YH_ALGO_AES128, YH_ALGO_AES_ECB, 128, ""}, {YH_ALGO_AES192, YH_ALGO_AES_ECB, 128, ""}, {YH_ALGO_AES256, YH_ALGO_AES_ECB, 128, ""}, {YH_ALGO_AES128, YH_ALGO_AES_CBC, 128, ""}, {YH_ALGO_AES192, YH_ALGO_AES_CBC, 128, ""}, {YH_ALGO_AES256, YH_ALGO_AES_CBC, 128, ""}, {0, 0, 8, "Random 8 bytes"}, {0, 0, 16, "Random 16 bytes"}, {0, 0, 32, "Random 32 bytes"}, {0, 0, 64, "Random 64 bytes"}, {0, 0, 128, "Random 128 bytes"}, {0, 0, 256, "Random 256 bytes"}, {0, 0, 512, "Random 512 bytes"}, {0, 0, 1024, "Random 1024 bytes"}, {YH_ALGO_AES128_YUBICO_AUTHENTICATION, 0, 0, ""}, {YH_ALGO_EC_P256_YUBICO_AUTHENTICATION, 0, 0, ""}, }; // this is some data for the OTP benchmark const uint8_t otp_key[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; const uint8_t otp_id[] = "\x01\x02\x03\x04\x05\x06"; const uint8_t otp[] = "\x2f\x5d\x71\xa4\x91\x5d\xec\x30\x4a\xa1\x3c\xcf\x97\xbb\x0d\xbb"; const uint8_t password[] = "benchmark"; if (argv[1].d == 0) { fprintf(stderr, "Benchmark with 0 rounds seems pointless\n"); return -1; } yh_algorithm algorithms[YH_MAX_ALGORITHM_COUNT]; size_t n_algorithms = sizeof(algorithms) / sizeof(algorithms[0]); if (yh_util_get_device_info(ctx->connector, NULL, NULL, NULL, NULL, NULL, NULL, algorithms, &n_algorithms) != YHR_SUCCESS) { fprintf(stderr, "Could not fetch supported algorithms\n"); return -1; } for (size_t i = 0; i < sizeof(benchmarks) / sizeof(benchmarks[0]); i++) { struct timeval total = {0, 0}; struct timeval avg = {0, 0}; struct timeval max = {0, 0}; struct timeval min = {0, 0}; yh_capabilities capabilities = {{0}}; yh_rc yrc = YHR_SUCCESS; uint8_t algo_data[1024] = {0}; size_t algo_len = sizeof(algo_data); const char *str1 = NULL, *str2 = "", *str3 = ""; uint16_t id = argv[2].w; char label[YH_OBJ_LABEL_LEN + 1] = {0}; uint8_t sk_oce[YH_EC_P256_PRIVKEY_LEN], pk_oce[YH_EC_P256_PUBKEY_LEN], pk_sd[YH_EC_P256_PUBKEY_LEN]; size_t pk_sd_len = sizeof(pk_sd); yh_object_type type = 0; #ifndef _WIN32 size_t chars = 0; #endif if (argv[3].a != 0) { if (argv[3].a != benchmarks[i].algo && argv[3].a != benchmarks[i].algo2) { continue; } } if (benchmarks[i].algo) { yh_algo_to_string(benchmarks[i].algo, &str1); } if (benchmarks[i].algo2) { str2 = " "; yh_algo_to_string(benchmarks[i].algo2, &str3); } if (str1) { snprintf(label, YH_OBJ_LABEL_LEN, "Benchmark: %s%s%s", str1, str2, str3); } if ((benchmarks[i].algo && !algorithm_search(benchmarks[i].algo, algorithms, n_algorithms)) || (benchmarks[i].algo2 && !algorithm_search(benchmarks[i].algo2, algorithms, n_algorithms))) { fprintf(stderr, "%s%s%s skipped (disabled or unsupported)\n", str1, str2, str3); continue; } if (str1) { #ifndef _WIN32 chars = #endif fprintf(stderr, "Doing benchmark setup for %s%s%s...", str1, str2, str3); } if (yh_is_rsa(benchmarks[i].algo)) { if (benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA256 || benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA384 || benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA512) { yh_string_to_capabilities("sign-pkcs", &capabilities); } else if (benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA256 || benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA384 || benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA512) { yh_string_to_capabilities("sign-pss", &capabilities); } else { fprintf(stderr, "Unknown benchmark algorithms\n"); return -1; } type = YH_ASYMMETRIC_KEY; yrc = yh_util_generate_rsa_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); } else if (yh_is_ec(benchmarks[i].algo)) { if (benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA1 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA256 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA384 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA512) { yh_string_to_capabilities("sign-ecdsa", &capabilities); } else if (benchmarks[i].algo2 == YH_ALGO_EC_ECDH) { yh_string_to_capabilities("derive-ecdh", &capabilities); yrc = yh_util_generate_ec_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed ECDH setup\n"); return -1; } algo_len--; yrc = yh_util_get_public_key_ex(argv[0].e, YH_ASYMMETRIC_KEY, id, algo_data + 1, &algo_len, NULL); if (yrc != YHR_SUCCESS || algo_len != benchmarks[i].bytes) { fprintf(stderr, "Failed to get ECDH pubkey (%zu)\n", algo_len); return -1; } algo_data[0] = 0x04; // this is a hack to make it look correct.. algo_len++; yrc = yh_util_delete_object(argv[0].e, id, YH_ASYMMETRIC_KEY); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed deleting temporary ec key\n"); return -1; } } else { fprintf(stderr, "Unknown benchmark algorithms\n"); return -1; } type = YH_ASYMMETRIC_KEY; yrc = yh_util_generate_ec_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); } else if (benchmarks[i].algo == YH_ALGO_EC_ED25519) { yh_string_to_capabilities("sign-eddsa", &capabilities); type = YH_ASYMMETRIC_KEY; yrc = yh_util_generate_ed_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); str2 = " "; str3 = benchmarks[i].special; } else if (yh_is_hmac(benchmarks[i].algo)) { type = YH_HMAC_KEY; yh_string_to_capabilities("sign-hmac", &capabilities); yrc = yh_util_generate_hmac_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); } else if (benchmarks[i].algo == YH_ALGO_AES128_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES192_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES256_CCM_WRAP) { type = YH_WRAP_KEY; yh_string_to_capabilities( "export-wrapped,exportable-under-wrap,wrap-data", &capabilities); yrc = yh_util_generate_wrap_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo, &capabilities); if (benchmarks[i].bytes > 0) { str2 = " "; str3 = benchmarks[i].special; } } else if (benchmarks[i].algo == YH_ALGO_AES128_YUBICO_OTP || benchmarks[i].algo == YH_ALGO_AES192_YUBICO_OTP || benchmarks[i].algo == YH_ALGO_AES256_YUBICO_OTP) { type = YH_OTP_AEAD_KEY; yh_string_to_capabilities("decrypt-otp,create-otp-aead", &capabilities); yrc = yh_util_generate_otp_aead_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo, 0x12345678); if (yrc == YHR_SUCCESS) { yrc = yh_util_create_otp_aead(argv[0].e, id, otp_key, otp_id, algo_data, &algo_len); } } else if (yh_is_aes(benchmarks[i].algo)) { type = YH_SYMMETRIC_KEY; yh_string_to_capabilities( "decrypt-ecb,encrypt-ecb,decrypt-cbc,encrypt-cbc", &capabilities); yrc = yh_util_generate_aes_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); } else if (strncmp(benchmarks[i].special, "Random ", 7) == 0) { str1 = benchmarks[i].special; } else if (benchmarks[i].algo == YH_ALGO_AES128_YUBICO_AUTHENTICATION) { type = YH_AUTHENTICATION_KEY; yh_string_to_capabilities("", &capabilities); yrc = yh_util_import_authentication_key_derived(argv[0].e, &id, label, 0xffff, &capabilities, &capabilities, password, sizeof(password) - 1); } else if (benchmarks[i].algo == YH_ALGO_EC_P256_YUBICO_AUTHENTICATION) { type = YH_AUTHENTICATION_KEY; yh_string_to_capabilities("", &capabilities); yrc = yh_util_generate_ec_p256_key(sk_oce, sizeof(sk_oce), pk_oce, sizeof(pk_oce)); if (yrc == YHR_SUCCESS) { yrc = yh_util_import_authentication_key(argv[0].e, &id, label, 0xffff, &capabilities, &capabilities, pk_oce + 1, sizeof(pk_oce) - 1, NULL, 0); if (yrc == YHR_SUCCESS) { pk_sd_len = sizeof(pk_sd); yrc = yh_util_get_device_pubkey(ctx->connector, pk_sd, &pk_sd_len, NULL); } } } else { fprintf(stderr, "Unknown benchmark algorithms\n"); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed benchmark setup for %s%s%s\n", str1, str2, str3); return -1; } memset(&min, 0x7f, sizeof(min)); for (uint32_t j = 0; j < argv[1].d; j++) { uint8_t data[1024]; uint8_t out[1024]; size_t out_len = sizeof(out); struct timeval before, after, result; memset(data, j, sizeof(data)); gettimeofday(&before, NULL); if (yh_is_rsa(benchmarks[i].algo) && (benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA256 || benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA384 || benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA512)) { yrc = yh_util_sign_pkcs1v1_5(argv[0].e, id, true, data, benchmarks[i].bytes, out, &out_len); } else if (yh_is_rsa(benchmarks[i].algo) && (benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA256 || benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA384 || benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA512)) { yrc = yh_util_sign_pss(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len, benchmarks[i].bytes, YH_ALGO_MGF1_SHA1); } else if (yh_is_ec(benchmarks[i].algo) && (benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA1 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA256 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA384 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA512)) { yrc = yh_util_sign_ecdsa(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (yh_is_ec(benchmarks[i].algo) && benchmarks[i].algo2 == YH_ALGO_EC_ECDH) { yrc = yh_util_derive_ecdh(argv[0].e, id, algo_data, algo_len, out, &out_len); } else if (benchmarks[i].algo == YH_ALGO_EC_ED25519) { yrc = yh_util_sign_eddsa(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (yh_is_hmac(benchmarks[i].algo)) { yrc = yh_util_sign_hmac(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (benchmarks[i].bytes > 0 && (benchmarks[i].algo == YH_ALGO_AES128_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES192_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES256_CCM_WRAP)) { yrc = yh_util_wrap_data(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (benchmarks[i].algo == YH_ALGO_AES128_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES192_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES256_CCM_WRAP) { yrc = yh_util_export_wrapped(argv[0].e, id, YH_WRAP_KEY, id, out, &out_len); } else if (benchmarks[i].algo == YH_ALGO_AES128_YUBICO_OTP || benchmarks[i].algo == YH_ALGO_AES192_YUBICO_OTP || benchmarks[i].algo == YH_ALGO_AES256_YUBICO_OTP) { yrc = yh_util_decrypt_otp(argv[0].e, id, algo_data, algo_len, otp, NULL, NULL, NULL, NULL); } else if (yh_is_aes(benchmarks[i].algo)) { if (benchmarks[i].algo2 == YH_ALGO_AES_ECB) { yrc = yh_util_encrypt_aes_ecb(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (benchmarks[i].algo2 == YH_ALGO_AES_CBC) { yrc = yh_util_encrypt_aes_cbc(argv[0].e, id, data, data, benchmarks[i].bytes, out, &out_len); } else { fprintf(stderr, "Unknown benchmark algorithms\n"); return -1; } } else if (strncmp(benchmarks[i].special, "Random ", 7) == 0) { yrc = yh_util_get_pseudo_random(argv[0].e, benchmarks[i].bytes, out, &out_len); } else if (benchmarks[i].algo == YH_ALGO_AES128_YUBICO_AUTHENTICATION) { yh_session *ses = NULL; yrc = yh_create_session_derived(ctx->connector, id, password, sizeof(password) - 1, false, &ses); if (yrc == YHR_SUCCESS) { yrc = yh_util_close_session(ses); } } else if (benchmarks[i].algo == YH_ALGO_EC_P256_YUBICO_AUTHENTICATION) { yh_session *ses = NULL; yrc = yh_create_session_asym(ctx->connector, id, sk_oce, sizeof(sk_oce), pk_sd, pk_sd_len, &ses); if (yrc == YHR_SUCCESS) { yrc = yh_util_close_session(ses); } } else { fprintf(stderr, "Unknown benchmark algorithm\n"); return -1; } gettimeofday(&after, NULL); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed running benchmark %u for %s%s%s\n", j, str1, str2, str3); return -1; } time_elapsed(&after, &before, &result); if (time_less(&result, &min)) { min = result; } if (time_less(&max, &result)) { max = result; } time_add(&result, &total, &total); time_average(&total, j + 1, &avg); #ifndef _WIN32 struct winsize w; ioctl(fileno(stderr), TIOCGWINSZ, &w); if (chars > w.ws_col) { // move the cursor up and to column 1 fprintf(stderr, "\33[%zuF", chars / w.ws_col); } else { // if we're still on same line, just move to column 1 fprintf(stderr, "\33[1G"); } // clear display from cursor fprintf(stderr, "\33[J"); chars = fprintf(stderr, "%s%s%s (%u/%d times) total: %lld.%06ld avg: %lld.%06ld " "min: %lld.%06ld max: %lld.%06ld tps: %.06f", str1, str2, str3, j + 1, argv[1].w, (long long) total.tv_sec, (long) total.tv_usec, (long long) avg.tv_sec, (long) avg.tv_usec, (long long) min.tv_sec, (long) min.tv_usec, (long long) max.tv_sec, (long) max.tv_usec, time_tps(&total, j + 1)); fflush(stderr); #endif } #ifdef _WIN32 fprintf(stderr, "%s%s%s (%d times) total: %lld.%06ld avg: %lld.%06ld " "min: %lld.%06ld max: %lld.%06ld tps: %.06f", str1, str2, str3, argv[1].w, (long long) total.tv_sec, (long) total.tv_usec, (long long) avg.tv_sec, (long) avg.tv_usec, (long long) min.tv_sec, (long) min.tv_usec, (long long) max.tv_sec, (long) max.tv_usec, time_tps(&total, argv[1].w)); #endif fprintf(stderr, "\n"); if (type != 0) { yh_util_delete_object(argv[0].e, id, type); } } return 0; } // NOTE: create aead from OTP parameters // argc = 5 // arg 0: e:session // arg 1: w:key_id // arg 2: x:key // arg 3: x:private_id // arg 4: f:aead int yh_com_otp_aead_create(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); if (argv[2].len != 16) { fprintf(stderr, "Wrong length key supplied, has to be 16 bytes\n"); return -1; } if (argv[3].len != 6) { fprintf(stderr, "Wrong length id supplied, has to be 6 bytes\n"); return -1; } yh_rc yrc = yh_util_create_otp_aead(argv[0].e, argv[1].w, argv[2].x, argv[3].x, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create OTP AEAD: %s\n", yh_strerror(yrc)); return -1; } if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { return 0; } return -1; } // NOTE: create aead from OTP parameters // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: f:aead int yh_com_otp_aead_random(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_randomize_otp_aead(argv[0].e, argv[1].w, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create OTP AEAD: %s\n", yh_strerror(yrc)); return -1; } if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { return 0; } return -1; } // NOTE: decrypt OTP with AEAD // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: s:otp // arg 3: i:aead int yh_com_otp_decrypt(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (argv[2].len != 32) { fprintf(stderr, "Wrong length OTP supplied, has to be 16 bytes in hex\n"); return -1; } uint8_t otp[16] = {0}; size_t otp_len = sizeof(otp); if (hex_decode(argv[2].s, otp, &otp_len) == false) { fprintf(stderr, "Failed to decode OTP\n"); return -1; } uint16_t useCtr = 0; uint8_t sessionCtr = 0; uint8_t tstph = 0; uint16_t tstpl = 0; yh_rc yrc = yh_util_decrypt_otp(argv[0].e, argv[1].w, argv[3].x, argv[3].len, otp, &useCtr, &sessionCtr, &tstph, &tstpl); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt OTP: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "OTP decoded, useCtr:%d, sessionCtr:%d, tstph:%d, tstpl:%d\n", useCtr, sessionCtr, tstph, tstpl); return 0; } // NOTE: rewrap OTP AEAD to a different key // argc = 5 // arg 0: e:session // arg 1: w:id_from // arg 2: w:id_to // arg 3: i:aead_in // arg 4: F:aead_out int yh_com_otp_rewrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); UNUSED(ctx); UNUSED(in_fmt); yh_rc yrc = yh_util_rewrap_otp_aead(argv[0].e, argv[1].w, argv[2].w, argv[3].x, argv[3].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to rewrap OTP AEAD: %s\n", yh_strerror(yrc)); return -1; } if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { return 0; } return -1; } // NOTE: decrypt OTP with AEAD // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: 2:attest_id int yh_com_sign_attestation_certificate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); int ret = -1; yh_rc yrc = yh_util_sign_attestation_certificate(argv[0].e, argv[1].w, argv[2].w, data, &data_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to attest asymmetric key: %s\n", yh_strerror(yrc)); yh_object_descriptor desc = {0}; yrc = yh_util_get_object_info(argv[0].e, argv[1].w, YH_OPAQUE, &desc); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get object info: %s\n", yh_strerror(yrc)); return -1; } if (desc.algorithm != YH_ALGO_OPAQUE_X509_CERTIFICATE) { fprintf(stderr, "Certificate template is not stored as a certificate\n"); } else if (is_compressed(argv[0].e, argv[1].w, YH_ALGO_OPAQUE_X509_CERTIFICATE)) { fprintf(stderr, "Stored X509 certificated used as template is a compressed " "certificate. Compressed X509 certificates cannot be used as " "template for attestation. Try to re-import it without " "compression\n"); } return -1; } const unsigned char *ptr = data; X509 *x509 = d2i_X509(NULL, &ptr, data_len); if (!x509) { fprintf(stderr, "Failed parsing x509 information\n"); } else { if (fmt == fmt_base64 || fmt == fmt_PEM) { if (PEM_write_X509(ctx->out, x509) == 1) { ret = 0; } else { fprintf(stderr, "Failed writing x509 information\n"); } } else if (fmt == fmt_binary) { if (i2d_X509_fp(ctx->out, x509) == 1) { ret = 0; } else { fprintf(stderr, "Failed writing x509 information\n"); } } } X509_free(x509); return ret; } // NOTE: put OTP AEAD key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: d:nonce_id // arg 6: x:key int yh_com_put_otp_aead_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (argv[6].len != 16 && argv[6].len != 24 && argv[6].len != 32) { fprintf(stderr, "Key length (%zu) not matching, should be 16, 24 or 32\n", argv[6].len); return -1; } yh_rc yrc = yh_util_import_otp_aead_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].d, argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store OTP AEAD key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored OTP AEAD key 0x%04x\n", argv[1].w); return 0; } // NOTE: generate OTP AEAD key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: d:nonce_id int yh_com_generate_otp_aead_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_generate_otp_aead_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a, argv[6].d); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate OTP AEAD key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated OTP AEAD key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Decrypt data using RSAES-OAEP // argc = 5 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: f:datafile // arg 4: s:label int yh_com_decrypt_oaep(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); int hash = 0; yh_algorithm mgf = 0; switch (argv[2].a) { case YH_ALGO_RSA_OAEP_SHA1: hash = _SHA1; mgf = YH_ALGO_MGF1_SHA1; break; case YH_ALGO_RSA_OAEP_SHA256: hash = _SHA256; mgf = YH_ALGO_MGF1_SHA256; break; case YH_ALGO_RSA_OAEP_SHA384: hash = _SHA384; mgf = YH_ALGO_MGF1_SHA384; break; case YH_ALGO_RSA_OAEP_SHA512: hash = _SHA512; mgf = YH_ALGO_MGF1_SHA512; break; default: fprintf(stderr, "Invalid hash algorithm\n"); return -1; } uint8_t label[64] = {0}; size_t label_len = sizeof(label); if (hash_bytes((const uint8_t *) argv[4].s, argv[4].len, hash, label, &label_len) == false) { fprintf(stderr, "Unable to hash data\n"); return -1; } uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_decrypt_oaep(argv[0].e, argv[1].w, argv[3].x, argv[3].len, response, &response_len, label, label_len, mgf); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data with OAEP: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Set ca cert for https validation // argc = 1 // arg 0: s:filename int yh_com_set_cacert(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->cacert) { free(ctx->cacert); } ctx->cacert = strdup(argv[0].s); return 0; } // NOTE: Set https client cert // argc = 1 // arg 0: s:filename int yh_com_set_cert(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->cert) { free(ctx->cert); } ctx->cert = strdup(argv[0].s); return 0; } // NOTE: Set https client key // argc = 1 // arg 0: s:filename int yh_com_set_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->key) { free(ctx->key); } ctx->key = strdup(argv[0].s); return 0; } // NOTE: Set proxy server to use for connector // argc = 1 // arg 0: s:proxy int yh_com_set_proxy(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->proxy) { free(ctx->proxy); } ctx->proxy = strdup(argv[0].s); return 0; } // NOTE: Set noproxy list to use for connector // argc = 1 // arg 0: s:proxy int yh_com_set_noproxy(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->noproxy) { free(ctx->noproxy); } ctx->noproxy = strdup(argv[0].s); return 0; } // NOTE: Change authentication key // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:password int yh_com_change_authentication_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); yh_rc yrc = yh_util_change_authentication_key_derived(argv[0].e, &argv[1].w, argv[2].x, argv[2].len); insecure_memzero(argv[2].x, argv[2].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to change authentication key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Changed Authentication key 0x%04x\n", argv[1].w); return 0; } // NOTE: Change asymmetric authentication key // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:password int yh_com_change_authentication_key_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(fmt); UNUSED(ctx); uint8_t pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; yh_rc yrc = YHR_SUCCESS; if (in_fmt == fmt_password) { uint8_t privkey[YH_EC_P256_PRIVKEY_LEN]; yrc = yh_util_derive_ec_p256_key(argv[2].x, argv[2].len, privkey, sizeof(privkey), pubkey, sizeof(pubkey)); insecure_memzero(argv[2].x, argv[2].len); insecure_memzero(privkey, sizeof(privkey)); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to derive asymmetric authentication key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Derived public key (PK.OCE)\n"); for (size_t i = 0; i < sizeof(pubkey); i++) fprintf(stderr, "%02x", pubkey[i]); fprintf(stderr, "\n"); } else if (in_fmt == fmt_PEM) { yh_algorithm algo = 0; size_t pubkey_len = sizeof(pubkey); if (!read_public_key(argv[2].x, argv[2].len, &algo, pubkey, &pubkey_len)) { fprintf(stderr, "Failed to load public key\n"); return -1; } if (pubkey_len != sizeof(pubkey)) { fprintf(stderr, "Invalid public key\n"); return -1; } } else if (argv[2].len <= sizeof(pubkey)) { memset(pubkey, 0, sizeof(pubkey) - argv[2].len); memcpy(pubkey + sizeof(pubkey) - argv[2].len, argv[2].x, argv[2].len); } else { fprintf(stderr, "Invalid asymmetric authkey: %s\n", yh_strerror(YHR_INVALID_PARAMETERS)); return -1; } yrc = yh_util_change_authentication_key(argv[0].e, &argv[1].w, pubkey + 1, sizeof(pubkey) - 1, NULL, 0); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to change asymmetric authentication key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Changed Asymmetric Authentication key 0x%04x\n", argv[1].w); return 0; } // NOTE: Generate a Certificate Signing Request // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: s:subject // arg 3: f:out_filename int yh_com_generate_csr(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { #if !(OPENSSL_VERSION_NUMBER >= 0x10100000L) fprintf(stderr, "Generating CSR is only supported with OpenSSL 3.0 or higher\n"); return -1; #endif UNUSED(in_fmt); X509_REQ *req = NULL; X509_NAME *name = NULL; EVP_PKEY *public_key = NULL; const EVP_MD *md = NULL; yh_algorithm algorithm; uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_get_public_key(argv[0].e, argv[1].w, response, &response_len, &algorithm); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get public key: %s\n", yh_strerror(yrc)); return -1; } if (!get_pubkey_evp(response, response_len, algorithm, &public_key)) { fprintf(stderr, "Failed to encode public key\n"); return -1; } req = X509_REQ_new(); if (!req) { fprintf(stderr, "Failed to allocate request structure.\n"); goto request_out; } if (algorithm != YH_ALGO_EC_ED25519) { md = EVP_sha256(); if (md == NULL) { goto request_out; } } if (!X509_REQ_set_pubkey(req, public_key)) { fprintf(stderr, "Failed setting the request public key.\n"); goto request_out; } if (X509_REQ_set_version(req, 0) != 1) { fprintf(stderr, "Failed setting the certificate request version.\n"); } name = parse_subject_name(argv[2].s); if (!name) { fprintf(stderr, "Failed encoding subject as name.\n"); goto request_out; } if (!X509_REQ_set_subject_name(req, name)) { fprintf(stderr, "Failed setting the request subject.\n"); goto request_out; } if (algorithm == YH_ALGO_EC_ED25519) { // Generate a dummy ED25519 to sign with OpenSSL EVP_PKEY *ed_key = NULL; EVP_PKEY_CTX *ed_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL); EVP_PKEY_keygen_init(ed_ctx); EVP_PKEY_keygen(ed_ctx, &ed_key); EVP_PKEY_CTX_free(ed_ctx); // Sign the request object using the dummy key if (X509_REQ_sign(req, ed_key, md) == 0) { fprintf(stderr, "Failed signing certificate.\n"); ERR_print_errors_fp(stderr); EVP_PKEY_free(ed_key); goto request_out; } EVP_PKEY_free(ed_key); // Extract the request data without the signature unsigned char *tbs_data = NULL; int tbs_len = i2d_re_X509_REQ_tbs(req, &tbs_data); // Sign the request data using the YubiKey unsigned char yh_sig[64] = {0}; size_t yh_siglen = sizeof(yh_sig); yrc = yh_util_sign_eddsa(argv[0].e, argv[1].w, tbs_data, tbs_len, yh_sig, &yh_siglen); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed signing tbs request portion: %s\n", yh_strerror(yrc)); goto request_out; } // Replace the dummy signature with the signature from the yubikey ASN1_BIT_STRING *psig; const X509_ALGOR *palg; X509_REQ_get0_signature(req, (const ASN1_BIT_STRING **) &psig, &palg); ASN1_BIT_STRING_set(psig, yh_sig, yh_siglen); } else { /* With opaque structures we can not touch whatever we want, but we need * to embed the sign_data function in the RSA/EC key structures */ EVP_PKEY *sk = wrap_public_key(argv[0].e, algorithm, public_key, argv[1].w); if (X509_REQ_sign(req, sk, md) == 0) { fprintf(stderr, "Failed signing request.\n"); ERR_print_errors_fp(stderr); EVP_PKEY_free(sk); goto request_out; } EVP_PKEY_free(sk); } if (fmt == fmt_PEM) { if (PEM_write_X509_REQ(ctx->out, req) != 1) { fprintf(stderr, "Failed writing certificate request\n"); ERR_print_errors_fp(stderr); } } else { fprintf(stderr, "Only PEM support available for certificate requests.\n"); } request_out: EVP_PKEY_free(public_key); if (req != NULL) { X509_REQ_free(req); } if (name != NULL) { X509_NAME_free(name); } return 0; } yubihsm-shell-2.7.3/src/main.c0000644000175000017500000035071615167357110015167 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "parsing.h" #include "commands.h" #include "insecure_memzero.h" #include //#include #define PROMPT "yubihsm> " #define ARGS_BUFFER_SIZE 4096 #define COMPLETION_CANDIDATES 256 #define MAX_COMMAND_NAME 32 #define MAX_ARGUMENTS 32 #include "yubihsm-shell.h" #define SPACES " \f\n\r\t\v" #ifdef __WIN32 #include #include #include // TODO: cheat on windows, cheat better? #define S_ISLNK S_ISREG #else #include #include #include #include #include #include History *g_hist; #endif #ifdef _MSVC #define S_ISREG(m) (((m) &S_IFMT) == S_IFREG) #define strcasecmp _stricmp #define strncasecmp _strnicmp #endif #define UNUSED(x) (void) (x) #define LIB_SUCCEED_OR_DIE(x, s) \ if ((x) != YHR_SUCCESS) { \ fprintf(stderr, s "%s\n", yh_strerror(x)); \ rc = EXIT_FAILURE; \ break; \ } #define COM_SUCCEED_OR_DIE(x, s) \ if ((x) != 0) { \ fprintf(stderr, s "\n"); \ rc = EXIT_FAILURE; \ break; \ } static bool calling_device = false; static yubihsm_context g_ctx = {0}; int yh_com_help(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_history(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_quit(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_informat(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_outformat(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); typedef struct Command Command; // NOTE(adma): supported values for the argument list are as follow // u: unsigned integer (either decimal or hex if starts with 0x) // w: unsigned short // b: unsigned byte // f: out filename // F: in filename // s: string // e: session struct Command { char *name; /* Command name to match against */ CommandFunction *func; /* Documentation for the function */ char *args; /* Argument string */ cmd_format in_fmt; /* Default input format for command */ cmd_format out_fmt; /* Default output format for command */ char *doc; /* Function to call to do the job */ Command *subcommands; /* List of subcommands */ Command *next; /* Pointer to next command */ }; typedef Command *CommandList; // NOTE(adma): push command to list and return the new head static Command *register_command(CommandList list, Command command) { Command *c = calloc(1, sizeof(Command)); if (c == NULL) { fprintf(stderr, "Failed to allocate memory\n"); exit(EXIT_FAILURE); } assert(strlen(command.name) <= MAX_COMMAND_NAME); memcpy(c, &command, sizeof(Command)); c->next = list; return c; } static void register_subcommand(Command *parent, Command command) { Command *c = malloc(sizeof(Command)); if (c == NULL) { fprintf(stderr, "Failed to allocate memory\n"); exit(EXIT_FAILURE); } memcpy(c, &command, sizeof(Command)); c->next = parent->subcommands; parent->subcommands = c; } static CommandList msort_list(CommandList list) { Command *left; Command *right; Command *e; int in_size; int left_size; int right_size; // NOTE(adma): do nothing on an empty list if (!list) { return NULL; } in_size = 1; while (1) { Command *tail = NULL; left = list; list = NULL; int n_merges = 0; while (left != NULL) { n_merges++; right = left; left_size = 0; for (int i = 0; i < in_size; i++) { left_size++; right = right->next; if (right == NULL) { break; } } right_size = in_size; while (left_size > 0 || (right_size > 0 && right)) { if (left_size == 0) { e = right; right = right->next; right_size--; } else if (right_size == 0 || !right) { e = left; left = left->next; left_size--; } else if (strcmp(left->name, right->name) <= 0) { e = left; left = left->next; left_size--; } else { e = right; right = right->next; right_size--; } if (tail) { tail->next = e; } else { list = e; } tail = e; } left = right; } if (tail != NULL) { tail->next = NULL; } if (n_merges <= 1) { return list; } in_size *= 2; } } static void create_command_list(CommandList *c) { // NOTE(adma): initialize *c = NULL; *c = register_command(*c, (Command){"audit", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Deal with audit log", NULL, NULL}); register_subcommand(*c, (Command){"get", yh_com_audit, "e:session,F:file=-", fmt_ASCII, fmt_nofmt, "Extract log entries", NULL, NULL}); register_subcommand(*c, (Command){"set", yh_com_set_log_index, "e:session,w:index", fmt_nofmt, fmt_nofmt, "Set the log index", NULL, NULL}); *c = register_command(*c, (Command){"connect", yh_com_connect, NULL, fmt_nofmt, fmt_nofmt, "Connect to a connector", NULL, NULL}); *c = register_command(*c, (Command){"debug", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Change debug settings", NULL, NULL}); register_subcommand(*c, (Command){"all", yh_com_debug_all, NULL, fmt_nofmt, fmt_nofmt, "Enable all debug messages", NULL, NULL}); register_subcommand(*c, (Command){"crypto", yh_com_debug_crypto, NULL, fmt_nofmt, fmt_nofmt, "Toggle crypto debug messages", NULL, NULL}); register_subcommand(*c, (Command){"error", yh_com_debug_error, NULL, fmt_nofmt, fmt_nofmt, "Toggle error debug messages", NULL, NULL}); register_subcommand(*c, (Command){"info", yh_com_debug_info, NULL, fmt_nofmt, fmt_nofmt, "Toggle info debug messages", NULL, NULL}); register_subcommand(*c, (Command){"intermediate", yh_com_debug_intermediate, NULL, fmt_nofmt, fmt_nofmt, "Toggle intermediate debug messages", NULL, NULL}); register_subcommand(*c, (Command){"none", yh_com_debug_none, NULL, fmt_nofmt, fmt_nofmt, "Disable all debug messages", NULL, NULL}); register_subcommand(*c, (Command){"raw", yh_com_debug_raw, NULL, fmt_nofmt, fmt_nofmt, "Toggle raw debug messages", NULL, NULL}); *c = register_command(*c, (Command){"decrypt", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Decrypt data", NULL, NULL}); register_subcommand(*c, (Command){"pkcs1v1_5", yh_com_decrypt_pkcs1v1_5, "e:session,w:key_id,i:data=-", fmt_binary, fmt_base64, "Decrypt data using RSAES-PKCS#1v1.5", NULL, NULL}); register_subcommand( *c, (Command){"oaep", yh_com_decrypt_oaep, "e:session,w:key_id,a:algorithm,i:data=-,s:label=", fmt_binary, fmt_base64, "Decrypt data using RSAES-OAEP", NULL, NULL}); register_subcommand(*c, (Command){"aesccm", yh_com_decrypt_aesccm, "e:session,w:key_id,i:data=-", fmt_base64, fmt_binary, "Decrypt data using Yubico-AES-CCM", NULL, NULL}); register_subcommand( *c, (Command){"aescbc", yh_com_decrypt_aes_cbc, "e:session,w:key_id,s:iv,i:data=-", fmt_base64, fmt_binary, "Decrypt data using an AES symmetric key in CBC mode", NULL, NULL}); register_subcommand( *c, (Command){"aesecb", yh_com_decrypt_aes_ecb, "e:session,w:key_id,i:data=-", fmt_base64, fmt_binary, "Decrypt data using an AES symmetric key in ECB mode", NULL, NULL}); *c = register_command(*c, (Command){"derive", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Derive data", NULL, NULL}); register_subcommand(*c, (Command){"ecdh", yh_com_derive_ecdh, "e:session,w:key_id,i:pubkey=-", fmt_PEM, fmt_hex, "Perform a ECDH key exchange", NULL, NULL}); *c = register_command(*c, (Command){"encrypt", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Encrypt data", NULL, NULL}); register_subcommand(*c, (Command){"aesccm", yh_com_encrypt_aesccm, "e:session,w:key_id,i:data=-", fmt_binary, fmt_base64, "Encrypt data using Yubico-AES-CCM", NULL, NULL}); register_subcommand( *c, (Command){"aescbc", yh_com_encrypt_aes_cbc, "e:session,w:key_id,s:iv,i:data=-", fmt_binary, fmt_base64, "Encrypt data using an AES symmetric key in CBC mode", NULL, NULL}); register_subcommand( *c, (Command){"aesecb", yh_com_encrypt_aes_ecb, "e:session,w:key_id,i:data=-", fmt_binary, fmt_base64, "Encrypt data using an AES symmetric key in ECB mode", NULL, NULL}); *c = register_command(*c, (Command){"disconnect", yh_com_disconnect, NULL, fmt_nofmt, fmt_nofmt, "Disconnect from a connector", NULL, NULL}); *c = register_command(*c, (Command){"echo", yh_com_echo, "e:session,b:byte,w:count", fmt_nofmt, fmt_nofmt, "Send an ECHO command over a given session", NULL, NULL}); *c = register_command(*c, (Command){"generate", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Generate key", NULL, NULL}); register_subcommand(*c, (Command){"asymmetric", yh_com_generate_asymmetric, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm", fmt_nofmt, fmt_nofmt, "Generate an asymmetric key", NULL, NULL}); register_subcommand(*c, (Command){"csr", yh_com_generate_csr, "e:session,w:key_id,s:subject,F:file=-", fmt_nofmt, fmt_PEM, "Generate a certificate signing request", NULL, NULL}); register_subcommand(*c, (Command){"hmackey", yh_com_generate_hmac, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm", fmt_nofmt, fmt_nofmt, "Generate HMAC key", NULL, NULL}); register_subcommand( *c, (Command){"wrapkey", yh_com_generate_wrap, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,a:algorithm", fmt_nofmt, fmt_nofmt, "Generate wrap key", NULL, NULL}); register_subcommand(*c, (Command){"otpaeadkey", yh_com_generate_otp_aead_key, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm,u:nonce_id", fmt_nofmt, fmt_nofmt, "Generate OTP AEAD key", NULL, NULL}); register_subcommand(*c, (Command){"symmetric", yh_com_generate_symmetric, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm", fmt_nofmt, fmt_nofmt, "Generate a symmetric key", NULL, NULL}); *c = register_command(*c, (Command){"get", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Retrieve data", NULL, NULL}); register_subcommand(*c, (Command){"opaque", yh_com_get_opaque, "e:session,w:object_id,F:file=-", fmt_nofmt, fmt_binary, "Get an opaque object", NULL, NULL}); register_subcommand(*c, (Command){"option", yh_com_get_option, "e:session,o:option", fmt_nofmt, fmt_nofmt, // FIXME: output "Get a global option value", NULL, NULL}); register_subcommand(*c, (Command){"random", yh_com_get_random, "e:session,w:count,F:out=-", fmt_nofmt, fmt_hex, "Get pseudo-random bytes", NULL, NULL}); register_subcommand(*c, (Command){"storage", yh_com_get_storage, "e:session", fmt_nofmt, fmt_nofmt, "Get storages stats", NULL, NULL}); register_subcommand(*c, (Command){"pubkey", yh_com_get_pubkey, "e:session,w:key_id,t:key_type=asymmetric-key,F:file=-", fmt_nofmt, fmt_PEM, "Get a public key", NULL, NULL}); register_subcommand(*c, (Command){"objectinfo", yh_com_get_object_info, "e:session,w:id,t:type", fmt_nofmt, fmt_nofmt, "Get information about an object", NULL, NULL}); register_subcommand(*c, (Command){"wrapped", yh_com_get_wrapped, "e:session,w:wrapkey_id,t:type,w:id,b:include_seed=0,F:file=-", fmt_nofmt, fmt_base64, "Get an object under wrap", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapped", yh_com_get_rsa_wrapped, "e:session,w:wrapkey_id,t:type,w:id,a:aes=aes256,a:hash=rsa-oaep-sha256,a:mgf1=mgf1-sha256,F:file=-", fmt_nofmt, fmt_binary, "Get an object under RSA wrap", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapped_key", yh_com_get_rsa_wrapped_key, "e:session,w:wrapkey_id,t:type,w:id,a:aes=aes256,a:hash=rsa-oaep-sha256,a:mgf1=mgf1-sha256,F:file=-", fmt_nofmt, fmt_binary, "Get a (a)symmetric key under RSA wrap", NULL, NULL}); register_subcommand(*c, (Command){"deviceinfo", yh_com_get_device_info, NULL, fmt_nofmt, fmt_nofmt, "Extract the version number, serial number " "and supported algorithms", NULL, NULL}); register_subcommand(*c, (Command){"template", yh_com_get_template, "e:session,w:object_id,F:out=-", fmt_nofmt, fmt_base64, "Get a template object", NULL, NULL}); register_subcommand(*c, (Command){"devicepubkey", yh_com_get_device_pubkey, NULL, fmt_nofmt, fmt_PEM, "Get the device public key for asymmetric " "authentication", NULL, NULL}); *c = register_command(*c, (Command){"help", yh_com_help, "s:command=", fmt_nofmt, fmt_nofmt, "Display help text", NULL, NULL}); *c = register_command(*c, (Command){"history", yh_com_history, NULL, fmt_nofmt, fmt_nofmt, "Display the command history", NULL, NULL}); *c = register_command(*c, (Command){"list", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "List information", NULL, NULL}); register_subcommand(*c, (Command){"capabilities", yh_com_list_capabilities, NULL, fmt_nofmt, fmt_nofmt, "Prints a list of possible capabilities", NULL, NULL}); register_subcommand(*c, (Command){"algorithms", yh_com_list_algorithms, NULL, fmt_nofmt, fmt_nofmt, "Prints a list of possible algorithms", NULL, NULL}); register_subcommand(*c, (Command){"types", yh_com_list_types, NULL, fmt_nofmt, fmt_nofmt, "Prints a list of possible types", NULL, NULL}); register_subcommand(*c, (Command){"sessions", yh_com_list_sessions, NULL, fmt_nofmt, fmt_nofmt, "List the open session", NULL, NULL}); register_subcommand(*c, (Command){"objects", yh_com_list_objects, "e:session,w:id=0,t:type=any,d:domains=0,c:" "capabilities=0,a:algorithm=any,b:with-compression=0,s:label=", fmt_nofmt, fmt_nofmt, "List objects according to filter", NULL, NULL}); *c = register_command(*c, (Command){"plain", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Send unencrypted and unauthenticated commands", NULL, NULL}); register_subcommand(*c, (Command){"echo", yh_com_pecho, "b:byte,w:count", fmt_nofmt, fmt_nofmt, "Send a plain echo command", NULL, NULL}); *c = register_command(*c, (Command){"put", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Store data", NULL, NULL}); register_subcommand(*c, (Command){"asymmetric", yh_com_put_asymmetric, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,i:key=-", fmt_PEM, fmt_nofmt, "Store an asymmetric key", NULL, NULL}); register_subcommand(*c, (Command){"authkey", yh_com_put_authentication, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:" "password=-", fmt_password, fmt_nofmt, "Store an authentication key", NULL, NULL}); register_subcommand(*c, (Command){"authkey_asym", yh_com_put_authentication_asym, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:" "pubkey=-", 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,b:with-compression=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, "Set a global option value", NULL, NULL}); register_subcommand(*c, (Command){"hmackey", yh_com_put_hmac, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm,i:key", fmt_hex, fmt_nofmt, "Store a HMAC key", NULL, NULL}); register_subcommand(*c, (Command){"wrapkey", yh_com_put_wrapkey, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:key", fmt_hex, fmt_nofmt, "Store a wrapping key", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapkey", yh_com_put_rsa_wrapkey, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:key=-", fmt_PEM, fmt_nofmt, "Store an RSA wrapping key", NULL, NULL}); register_subcommand(*c, (Command){"pub_wrapkey", yh_com_put_public_wrapkey, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:key=-", fmt_PEM, fmt_nofmt, "Store an RSA wrapping key", NULL, NULL}); register_subcommand(*c, (Command){"wrapped", yh_com_put_wrapped, "e:session,w:wrapkey_id,i:data=-", fmt_base64, fmt_nofmt, "Store a wrapped object", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapped", yh_com_put_rsa_wrapped, "e:session,w:wrapkey_id,a:hash=rsa-oaep-sha256,a:mgf1=mgf1-sha256,i:data=-", fmt_binary, fmt_nofmt, "Store a wrapped object", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapped_key", yh_com_put_rsa_wrapped_key, "e:session,w:wrapkey_id,t:type,w:key_id,a:algorithm,s:label,d:domains,c:capabilities,a:hash=rsa-oaep-sha256,a:mgf1=mgf1-sha256,i:data=-", fmt_binary, fmt_nofmt, "Store a wrapped object", NULL, NULL}); register_subcommand(*c, (Command){"template", yh_com_put_template, "e:session,w:object_id,s:label,d:domains,c:" "capabilities,a:algorithm,i:data=-", fmt_base64, fmt_nofmt, "Store a template object", NULL, NULL}); register_subcommand(*c, (Command){"otpaeadkey", yh_com_put_otp_aead_key, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,u:nonce_id,i:key", fmt_hex, fmt_nofmt, "Store a OTP AEAD key", NULL, NULL}); register_subcommand(*c, (Command){"symmetric", yh_com_put_symmetric, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm,i:key", fmt_hex, fmt_nofmt, "Store a symmetric key", NULL, NULL}); *c = register_command(*c, (Command){"quit", yh_com_quit, NULL, fmt_nofmt, fmt_nofmt, "Quit yubihsm-shell", NULL, NULL}); *c = register_command(*c, (Command){"exit", yh_com_quit, NULL, fmt_nofmt, fmt_nofmt, "Quit yubihsm-shell", NULL, NULL}); *c = register_command(*c, (Command){"session", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Manage sessions", NULL, NULL}); register_subcommand(*c, (Command){"close", yh_com_close_session, "e:session", fmt_nofmt, fmt_nofmt, "Close a session with a connector", NULL, NULL}); register_subcommand(*c, (Command){"open", yh_com_open_session, "w:authkey,i:password=-", fmt_password, fmt_nofmt, "Open a session with a device using a " "specific Authentication Key", NULL, NULL}); register_subcommand(*c, (Command){"open_asym", yh_com_open_session_asym, "w:authkey,i:privkey=-", fmt_PEM, fmt_nofmt, "Open a session with a device using a " "specific Asymmetric Authentication Key", NULL, NULL}); register_subcommand(*c, (Command){"ykopen", yh_com_open_yksession, "w:authkey,s:label,i:password=-,s:reader=", fmt_password, fmt_nofmt, "Open a session with a device using an " "Authentication in a YubiKey", NULL, NULL}); *c = register_command(*c, (Command){"sign", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Sign data", NULL, NULL}); register_subcommand( *c, (Command){"ecdsa", yh_com_sign_ecdsa, "e:session,w:key_id,a:algorithm,i:data=-,F:out=-", fmt_binary, fmt_base64, "Sign data using ECDSA", NULL, NULL}); register_subcommand( *c, (Command){"eddsa", yh_com_sign_eddsa, "e:session,w:key_id,a:algorithm,i:data=-,F:out=-", fmt_binary, fmt_base64, "Sign data using EDDSA", NULL, NULL}); register_subcommand( *c, (Command){"pkcs1v1_5", yh_com_sign_pkcs1v1_5, "e:session,w:key_id,a:algorithm,i:data=-,F:out=-", fmt_binary, fmt_base64, "Sign data using RSASSA-PKCS#1v1.5", NULL, NULL}); register_subcommand( *c, (Command){"pss", yh_com_sign_pss, "e:session,w:key_id,a:algorithm,i:data=-,F:out=-", fmt_binary, fmt_base64, "Sign data using RSASSA-PSS", NULL, NULL}); *c = register_command(*c, (Command){"hmac", yh_com_hmac, "e:session,w:key_id,i:data=-,F:out=-", fmt_hex, fmt_hex, "Hmac data", NULL, NULL}); *c = register_command(*c, (Command){"reset", yh_com_reset, "e:session", fmt_nofmt, fmt_nofmt, "Reset device", NULL, NULL}); *c = register_command(*c, (Command){"delete", yh_com_delete, "e:session,w:id,t:type", fmt_nofmt, fmt_nofmt, "Delete data", NULL, NULL}); *c = register_command(*c, (Command){"certify", yh_com_sign_ssh_certificate, "e:session,w:key_id,w:template_id,a:" "algorithm,i:infile=-,F:outfile=-", fmt_binary, fmt_binary, // TODO: correct default formats? "Sign SSH certificates", NULL, NULL}); *c = register_command(*c, (Command){"benchmark", yh_com_benchmark, "e:session,u:count,w:key_id=0,a:algorithm=any", fmt_nofmt, fmt_nofmt, "Run a set of benchmarks", NULL, NULL}); *c = register_command(*c, (Command){"otp", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "OTP commands", NULL, NULL}); register_subcommand(*c, (Command){"aead_create", yh_com_otp_aead_create, "e:session,w:key_id,i:key,i:private_id,F:aead", fmt_hex, fmt_binary, "Create an OTP AEAD", NULL, NULL}); register_subcommand(*c, (Command){"aead_random", yh_com_otp_aead_random, "e:session,w:key_id,F:aead", fmt_nofmt, fmt_binary, "Create a random OTP AEAD", NULL, NULL}); register_subcommand(*c, (Command){"decrypt", yh_com_otp_decrypt, "e:session,w:key_id,s:otp,i:aead", fmt_binary, fmt_nofmt, "Decrypt an OTP with AEAD", NULL, NULL}); register_subcommand( *c, (Command){"rewrap", yh_com_otp_rewrap, "e:session,w:id_from,w:id_to,i:aead_in,F:aead_out", fmt_binary, fmt_binary, "Rewrap an OTP aead to a different key", NULL, NULL}); *c = register_command(*c, (Command){"attest", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Attest device objects", NULL, NULL}); register_subcommand(*c, (Command){"asymmetric", yh_com_sign_attestation_certificate, "e:session,w:key_id,w:attest_id=0,F:file=-", fmt_nofmt, fmt_PEM, "Sign attestation certificate", NULL, NULL}); *c = register_command(*c, (Command){"keepalive", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Change keepalive settings", NULL, NULL}); register_subcommand(*c, (Command){"on", yh_com_keepalive_on, NULL, fmt_nofmt, fmt_nofmt, "Enable keepalive", NULL, NULL}); register_subcommand(*c, (Command){"off", yh_com_keepalive_off, NULL, fmt_nofmt, fmt_nofmt, "Disable keepalive", NULL, NULL}); *c = register_command(*c, (Command){"set", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Set preferences", NULL, NULL}); register_subcommand(*c, (Command){"informat", yh_com_set_informat, "I:format", fmt_nofmt, fmt_nofmt, "Set input format", NULL, NULL}); register_subcommand(*c, (Command){"outformat", yh_com_set_outformat, "I:format", fmt_nofmt, fmt_nofmt, "Set output format", NULL, NULL}); register_subcommand(*c, (Command){"cacert", yh_com_set_cacert, "s:file", fmt_nofmt, fmt_nofmt, "Set CA cert to use for https to connector", NULL, NULL}); register_subcommand(*c, (Command){"cert", yh_com_set_cert, "s:file", fmt_nofmt, fmt_nofmt, "Set client cert to use for https to connector", NULL, NULL}); register_subcommand(*c, (Command){"key", yh_com_set_key, "s:file", fmt_nofmt, fmt_nofmt, "Set client key to use for https to connector", NULL, NULL}); register_subcommand(*c, (Command){"proxy", yh_com_set_proxy, "s:proxy", fmt_nofmt, fmt_nofmt, "Set proxyserver to use for connector", NULL, NULL}); register_subcommand(*c, (Command){"noproxy", yh_com_set_noproxy, "s:noproxy", fmt_nofmt, fmt_nofmt, "Set noproxy list to use for connector", NULL, NULL}); *c = register_command(*c, (Command){"blink", yh_com_blink, "e:session,b:seconds=10", fmt_nofmt, fmt_nofmt, "Blink the device", NULL, NULL}); *c = register_command(*c, (Command){"change", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Change objects", NULL, NULL}); register_subcommand(*c, (Command){"authkey", yh_com_change_authentication_key, "e:session,w:key_id,i:password=-", fmt_password, fmt_nofmt, "Change an authentication key", NULL, NULL}); register_subcommand(*c, (Command){"authkey_asym", yh_com_change_authentication_key_asym, "e:session,w:key_id,i:pubkey=-", fmt_PEM, fmt_nofmt, "Change an asymmetric authentication key", NULL, NULL}); *c = msort_list(*c); for (Command *t = *c; t != NULL; t = t->next) { if (t->subcommands != NULL) { t->subcommands = msort_list(t->subcommands); } } } // NOTE(adma): the prototype for el functions is fixed, no way to pass // in parameters, we must use globals CommandList g_commands; static bool g_running = true; static cmd_format g_in_fmt, g_out_fmt; // NOTE(adma): Print the command history // argc = 0 int yh_com_history(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); UNUSED(argv); #ifndef __WIN32 HistEvent ev; int rv; for (rv = history(g_hist, &ev, H_LAST); rv != -1; rv = history(g_hist, &ev, H_PREV)) { fprintf(ctx->out, "%4d %s", ev.num, ev.str); } #endif return 0; } static const char *fmt_to_string(cmd_format fmt) { for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { if (formats[i].format == fmt) { return formats[i].name; } } return "No format"; } // NOTE(adma): Print information about a command // argc = 1 // arg 0: s:command int yh_com_help(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); bool match = false; // TODO(adma): once we have optional commands we can have a real help for (Command *command = g_commands; command; command = command->next) { if (strncmp(argv[0].s, command->name, strlen(argv[0].s)) == 0) { match = true; printf("%-25s%s\n", command->name, command->doc); if (strlen(argv[0].s)) { if (command->args) { printf("%-5s%s", "", command->args); if (command->in_fmt != fmt_nofmt) { printf(" (default input format: %s)", fmt_to_string(command->in_fmt)); } printf("\n"); } for (Command *subcommand = command->subcommands; subcommand; subcommand = subcommand->next) { printf("%-5s%-25s%s", "", subcommand->name, subcommand->doc); if (subcommand->args) { if (subcommand->in_fmt != fmt_nofmt) { printf(" (default input format: %s)", fmt_to_string(subcommand->in_fmt)); } printf("\n%-30s%s\n", "", subcommand->args); } else { printf("\n"); } } } } } if (match == false) { printf("Help for command %s not found\n", argv[0].s); } return 0; } // NOTE(adma): Quit // argc = 0 int yh_com_quit(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); UNUSED(argv); g_running = false; return 0; } static bool probe_session(yubihsm_context *ctx, size_t index) { if (ctx->sessions[index]) { uint8_t data = 0xff; uint8_t response[YH_MSG_BUF_SIZE]; size_t response_len = sizeof(response); yh_cmd response_cmd; yh_rc yrc; // silently ignore transmit errors..? if ((yrc = yh_send_secure_msg(ctx->sessions[index], YHC_ECHO, &data, 1, &response_cmd, response, &response_len)) != YHR_SUCCESS) { yh_destroy_session(&ctx->sessions[index]); fprintf(stderr, "Failed to probe session %zu: %s\n", index, yh_strerror(yrc)); return false; } return true; } else { return false; } } #ifdef __WIN32 static void WINAPI timer_handler(void *lpParam, unsigned char TimerOrWaitFired) { UNUSED(TimerOrWaitFired); #else static void timer_handler(int signo __attribute__((unused))) { #endif if (calling_device == true || g_ctx.connector == NULL) { return; } for (size_t i = 0; i < sizeof(g_ctx.sessions) / sizeof(g_ctx.sessions[0]); i++) { probe_session(&g_ctx, i); } } static int set_keepalive(uint16_t seconds) { #ifdef __WIN32 HANDLE timer; static HANDLE timerQueue = NULL; if (timerQueue != NULL) { DeleteTimerQueue(timerQueue); } timerQueue = CreateTimerQueue(); if (timerQueue == NULL) { fprintf(stderr, "Failed to setup timer\n"); return 1; } CreateTimerQueueTimer(&timer, timerQueue, timer_handler, NULL, seconds * 1000, seconds * 1000, 0); if (timer == NULL) { fprintf(stderr, "Failed to start time\n"); return 1; } #else struct itimerval itimer; itimer.it_interval.tv_sec = seconds; itimer.it_interval.tv_usec = 0; itimer.it_value.tv_sec = seconds; itimer.it_value.tv_usec = 0; if (setitimer(ITIMER_REAL, &itimer, NULL) != 0) { fprintf(stderr, "Failed to setup timer\n"); return 1; } #endif fprintf(stderr, "Session keepalive set up to run every %d seconds\n", seconds); return 0; } // NOTE: Enable keepalive // argc = 0 int yh_com_keepalive_on(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); return set_keepalive(15); } // NOTE: Disable keepalive // argc = 0 int yh_com_keepalive_off(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); return set_keepalive(0); } int yh_com_set_informat(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { if (strcasecmp(argv[0].s, formats[i].name) == 0) { g_in_fmt = formats[i].format; return 0; } } fprintf(stderr, "Failed to parse input format\n"); return -1; } int yh_com_set_outformat(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { if (strcasecmp(argv[0].s, formats[i].name) == 0) { if (formats[i].format == fmt_password) { break; } g_out_fmt = formats[i].format; return 0; } } fprintf(stderr, "Failed to parse output format\n"); return -1; } static void find_lcp(const char *items[], int n_items, const char **lcp, int *lcp_len) { int min = 0; int max = 0; if (items == NULL || n_items == 0) { *lcp = NULL; *lcp_len = 0; } for (int i = 1; i < n_items; i++) { if (strcmp(items[i], items[min]) < 0) { min = i; } else if (strcmp(items[i], items[max]) > 0) { max = i; } } *lcp = items[min]; for (size_t i = 0; i < strlen(items[min]) && i < strlen(items[max]); i++) { if (items[min][i] != items[max][i]) { *lcp_len = i; return; } } *lcp_len = strlen(items[min]); } static int tokenize(char *line, char **toks, int max_toks, int *cursorc, int *cursoro, const char *space) { int i; int tok = 0; int length = strlen(line); int start_of_word = 0; enum states { WHITESPACE, WORD, QUOTE } state = WHITESPACE; toks[0] = line; // set up as fall-through for (i = 0; i <= length; i++) { char c = line[i]; if (cursorc && i == *cursorc && tok > 0) { if (state == WHITESPACE) { *cursoro = 0; *cursorc = tok; } else { *cursoro = i - start_of_word; *cursorc = tok - 1; } } if (c == '\0') { break; } if (tok >= max_toks) { return -1; } switch (state) { case WHITESPACE: { bool found = false; for (size_t j = 0; j < strlen(space); j++) { if (c == space[j]) { found = true; break; } } if (found) { break; } if (c == '"') { state = QUOTE; start_of_word = i + 1; } else if (c == '#') { return tok; } else { state = WORD; start_of_word = i; } toks[tok++] = line + start_of_word; } break; case QUOTE: if (c == '"') { line[i] = '\0'; state = WHITESPACE; } break; case WORD: for (size_t j = 0; j < strlen(space); j++) { if (c == space[j]) { line[i] = '\0'; state = WHITESPACE; } } break; } } return tok; } #ifndef __WIN32 static int compare_strings(const void *a, const void *b) { return strcmp(*(char *const *) a, *(char *const *) b); } static unsigned char complete_arg(EditLine *el, const char *arg, char *line, int cursoro) { const char *candidates[COMPLETION_CANDIDATES]; int n_candidates = 0; struct winsize w; const LineInfo *li = el_line(el); ioctl(fileno(stdout), TIOCGWINSZ, &w); int lines = (li->cursor - li->buffer + strlen(PROMPT)) / w.ws_col; switch (arg[0]) { case 'u': printf("\nnumber"); break; case 'w': printf("\nword"); break; case 'b': printf("\nbyte"); break; case 'i': printf("\ninput data"); break; case 'F': printf("\noutput filename"); break; case 's': printf("\nstring"); break; case 'k': printf("\nkey"); break; case 'e': printf("\nsession"); break; case 'd': printf("\ndomains"); break; case 'c': { char *toks[COMPLETION_CANDIDATES]; int cursorc = cursoro; int num_toks = tokenize(line, toks, COMPLETION_CANDIDATES, &cursorc, &cursoro, ":,;|"); if (cursorc == num_toks) { toks[cursorc] = ""; } for (size_t i = 0; i < sizeof(yh_capability) / sizeof(yh_capability[0]); i++) { if (strncasecmp(toks[cursorc], yh_capability[i].name, strlen(toks[cursorc])) == 0) { candidates[n_candidates++] = yh_capability[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } } break; case 'a': for (size_t i = 0; i < sizeof(yh_algorithms) / sizeof(yh_algorithms[0]); i++) { if (strncasecmp(line, yh_algorithms[i].name, strlen(line)) == 0) { candidates[n_candidates++] = yh_algorithms[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } break; case 't': for (size_t i = 0; i < sizeof(yh_types) / sizeof(yh_types[0]); i++) { if (strncasecmp(line, yh_types[i].name, strlen(line)) == 0) { candidates[n_candidates++] = yh_types[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } break; case 'o': for (size_t i = 0; i < sizeof(yh_options) / sizeof(yh_options[0]); i++) { if (strncasecmp(line, yh_options[i].name, strlen(line)) == 0) { candidates[n_candidates++] = yh_options[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } break; case 'I': for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { if (strncasecmp(line, formats[i].name, strlen(line)) == 0) { candidates[n_candidates++] = formats[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } break; case '\0': // NOTE(adma): completing an empty string, we reached the end, do // nothing return CC_ERROR; default: printf("\nunknown type"); break; } switch (n_candidates) { case 0: { int i = 1; while (arg[i] != '\0' && arg[i] != ',') { i++; } printf("%*.*s\n", i, i - 1, arg + 1); } break; case 1: el_insertstr(el, candidates[0] + cursoro); return CC_REDISPLAY; default: { const char *lcp; int lcp_len; qsort(candidates, n_candidates, sizeof(char *), compare_strings); find_lcp(candidates, n_candidates, &lcp, &lcp_len); if (cursoro == lcp_len) { // NOTE(adma): we already have lcp_len characters typed on // the prompt, display all the possible matches printf("\n"); for (int i = 0; i < n_candidates; i++) { printf("%s\n", candidates[i]); } } else { // NOTE(adma): we found an lcp, autocomplete with that char prefix[MAX_COMMAND_NAME]; strcpy(prefix, lcp + cursoro); prefix[lcp_len - cursoro] = '\0'; el_insertstr(el, prefix); return CC_REDISPLAY; } } } for (int i = 0; i < lines; i++) { printf("\n"); } return CC_REDISPLAY; } static unsigned char complete_command(EditLine *el, Command *to_complete, const char *line, int cursoro) { const char *candidates[COMPLETION_CANDIDATES]; int n_candidates = 0; // NOTE(adma): try to autocomplete the current command/subcomand for (Command *command = to_complete; command; command = command->next) { if (strncmp(line, command->name, strlen(line)) == 0) { // printf("%s\n", command->name); candidates[n_candidates++] = command->name; assert(n_candidates < COMPLETION_CANDIDATES); } else if (n_candidates != 0) { // NOTE(adma): the list is sorted no point in continuing, // bail out break; } } // printf("Found %d candidates\n", n_candidates); switch (n_candidates) { case 0: // NOTE(adma): no matches, do nothing return CC_ERROR; case 1: // NOTE(adma): only one match, autocomplete! el_insertstr(el, candidates[0] + cursoro); el_insertstr(el, " "); return CC_REDISPLAY; default: { // NOTE(adma): several matches, find longest common prefix const char *lcp; int lcp_len; find_lcp(candidates, n_candidates, &lcp, &lcp_len); if (cursoro == lcp_len) { // NOTE(adma): we already have lcp_len characters typed on // the prompt, display all the possible matches printf("\n"); for (int i = 0; i < n_candidates; i++) { printf("%s\n", candidates[i]); } } else { // NOTE(adma): we found an lcp, autocomplete with that char prefix[MAX_COMMAND_NAME]; strcpy(prefix, lcp + cursoro); prefix[lcp_len - cursoro] = '\0'; el_insertstr(el, prefix); } } return CC_REDISPLAY; } } static unsigned char yubihsm_complete(EditLine *el, int ch) { UNUSED(ch); const LineInfo *li; int argc, cursorc = 0, cursoro = 0; char *argv[64]; char data[ARGS_BUFFER_SIZE + 1] = {0}; li = el_line(el); cursorc = li->cursor - li->buffer; if (li->lastchar - li->buffer > 1024) { return CC_REDISPLAY; } memcpy(data, li->buffer, li->lastchar - li->buffer); argc = tokenize(data, argv, 64, &cursorc, &cursoro, SPACES); // printf("\nargc %d, cursorc: %d, cursoro: %d\n", argc, cursorc, cursoro); if (argc == 0) { // NOTE(adma): no prompt, don't even bother with finding a match, // just show all commands, one per line printf("\n"); for (Command *command = g_commands; command; command = command->next) { printf("%s\n", command->name); } return CC_REDISPLAY; } else { int i = 0; Command *command = g_commands; Command *to_complete = NULL; char *args = ""; bool completing_args = false; while (i < cursorc) { // NOTE(adma): match the first n-1 items if (completing_args == false) { // NOTE(adma): match subcommands if (strncmp(argv[i], command->name, strlen(argv[i])) == 0) { // printf("\nmatched %s\n", command->name); to_complete = command; // to_complete_position = i; if (command->subcommands != NULL) { // NOTE(adma): if we were matching subcommands, keep // matching subcommands if any command = command->subcommands; } else { // NOTE(adma): start matching arguments otherwise completing_args = true; if (command->args != NULL) { args = command->args; } else { // NOTE(adma): there are no args for this command break; } } i++; // NOTE(adma): next word } else { command = command->next; if (command == NULL) { // NOTE(adma): command not found break; } } } else { // NOTE(adma): match arguments while (*args != '\0' && *args != ',') { args++; } if (*args == ',') { args++; i++; // NOTE(adma): next word } else { break; } } } if (to_complete && cursorc != 0) { // NOTE(adma): 0 has a bit of a special meaning since the cursor // is after the last letter of the first word and we still want // to autocomplete commands and not subcommands nor args in that // case to_complete = to_complete->subcommands; } if (argc == cursorc) { if (to_complete && completing_args == false) { // NOTE(adma): cursor is after a command but there is no more // text to match, show all subcommands printf("\n"); for (Command *iter = to_complete; iter; iter = iter->next) { printf("%s\n", iter->name); } return CC_REDISPLAY; } else { // NOTE(adma): or show the current argument return complete_arg(el, args, "", 0); } } else { if (completing_args == false) { if (to_complete == NULL) { to_complete = g_commands; } return complete_command(el, to_complete, argv[i], cursoro); } else { return complete_arg(el, args, argv[i], cursoro); } } } return CC_ERROR; } static char *prompt(EditLine *el) { UNUSED(el); return PROMPT; } #else char *converting_fgets(char *s, int size, FILE *stream) { int translation = _setmode(_fileno(stream), _O_U16TEXT); if (translation == -1) { return NULL; } wchar_t *wide_str = calloc(size, sizeof(wchar_t)); if (wide_str == NULL) { _setmode(_fileno(stream), translation); return NULL; } fgetws(wide_str, sizeof(wchar_t) * size, stream); int len = WideCharToMultiByte(CP_UTF8, 0, wide_str, -1, s, size, NULL, NULL); free(wide_str); wide_str = NULL; _setmode(_fileno(stream), translation); if (len == 0) { return NULL; } return s; } #endif static FILE *open_file(const char *name, bool input) { if (input) { if (strcmp(name, "-") == 0) { return stdin; } else { return fopen(name, "rb"); } } else { if (strcmp(name, "-") == 0) { return stdout; } else { return fopen(name, "ab"); } } } static bool get_input_data(const char *name, uint8_t **out, size_t *len, cmd_format fmt) { const char *fname = strncasecmp(name, "file:", 5) ? name : name + 5; struct stat sb = {0}; int st_res = stat(fname, &sb); if (st_res == 0 && S_ISREG(sb.st_mode)) { *len = sb.st_size; } else { *len = ARGS_BUFFER_SIZE; } *out = calloc(*len + 1, 1); if (*out == 0) { fprintf(stderr, "Failed to allocate %zu bytes memory for %s\n", *len, fname); return false; } if (!strcmp(name, "-") || fname != name || (st_res == 0 && S_ISREG(sb.st_mode))) { bool ret = false; FILE *file = open_file(fname, true); if (!file) { return false; } if (file == stdin && fmt == fmt_password) { #ifndef __WIN32 // NOTE: we have to stop the timer around the call to // EVP_read_pw_string(), openssl gets sad if a signal hits while waiting // for input from the user. So we stop the timer and restore it when we're // done struct itimerval stoptimer, oldtimer; memset(&stoptimer, 0, sizeof(stoptimer)); if (setitimer(ITIMER_REAL, &stoptimer, &oldtimer) != 0) { fprintf(stderr, "Failed to setup timer\n"); return false; } #endif if (EVP_read_pw_string((char *) *out, *len - 1, "Enter password: ", 0) == 0) { *len = strlen((char *) *out); ret = true; } #ifndef __WIN32 if (setitimer(ITIMER_REAL, &oldtimer, NULL) != 0) { fprintf(stderr, "Failed to restore timer\n"); return false; } #endif } else if (read_file(file, *out, len)) { ret = true; } if (file != stdin) { fclose(file); } if (ret == false) { return ret; } } else { if (strlen(name) < *len) { memcpy(*out, name, strlen(name)); *len = strlen(name); } else { return false; } } switch (fmt) { case fmt_base64: if (base64_decode((char *) *out, *out, len)) { return true; } break; case fmt_hex: if (hex_decode((char *) *out, *out, len)) { return true; } break; case fmt_password: // If the password was read from a file, strip off \r\n if (*len > 0 && (*out)[*len - 1] == '\n') { (*len)--; } if (*len > 0 && (*out)[*len - 1] == '\r') { (*len)--; } (*out)[*len] = '\0'; return true; case fmt_binary: // these all require no extra work, just pass data on. case fmt_PEM: case fmt_ASCII: return true; case fmt_nofmt: default: return false; } return false; } static int validate_arg(yubihsm_context *ctx, char type, const char *value, Argument *parsed, cmd_format fmt) { switch (type) { case 'b': // byte case 'w': // word case 'e': // session case 'u': { // unsigned long uint32_t max = 0; if (type == 'b') { max = UCHAR_MAX; } else if (type == 'w' || type == 'e') { max = USHRT_MAX; } else if (type == 'u') { max = UINT_MAX; } // NOTE(adma): check that is a positive number in dec, hex or oct errno = 0; char *endptr; unsigned long num = strtoul(value, &endptr, 0); if ((errno == ERANGE || num > max) || (errno != 0 && num == 0)) { return -1; } if (endptr == value) { return -1; } if (type == 'b') { parsed->b = (uint8_t) num; } else if (type == 'e') { if (num >= sizeof(ctx->sessions) / sizeof(ctx->sessions[0]) || ctx->sessions[num] == NULL) { return -1; } parsed->e = ctx->sessions[num]; } else if (type == 'w') { parsed->w = (uint16_t) num; } else if (type == 'u') { parsed->d = (uint32_t) num; } parsed->len = 1; // NOTE(adma): doesn't really have a meaning } break; case 'F': parsed->s = value; parsed->len = strlen(value); ctx->out = open_file(value, false); if (!ctx->out) { return -1; } break; case 'i': if (get_input_data(value, &parsed->x, &parsed->len, fmt) == false) { return -1; } break; case 'I': case 's': // NOTE(adma): strings are pretty much always OK parsed->s = value; parsed->len = strlen(value); break; case 'd': if (yh_string_to_domains(value, &parsed->w) != YHR_SUCCESS) { return -1; } break; case 'c': if (yh_string_to_capabilities(value, &parsed->c) != YHR_SUCCESS) { return -1; } break; case 'a': if (yh_string_to_algo(value, &parsed->a) != YHR_SUCCESS) { return -1; } break; case 't': if (yh_string_to_type(value, &parsed->t) != YHR_SUCCESS) { return -1; } break; case 'o': if (yh_string_to_option(value, &parsed->o) != YHR_SUCCESS) { return -1; } break; default: // NOTE(adma): unknown type return -1; } return 0; } static int validate_and_call(yubihsm_context *ctx, CommandList l, const char *line) { int argc = 0; char *argv[64]; int i = 0; char data[ARGS_BUFFER_SIZE + 1]; char arg_data[ARGS_BUFFER_SIZE + 1] = {0}; Command *command = l; bool completing_args = false; const char *args = ""; Argument arguments[MAX_ARGUMENTS] = {{{0}, 0, 0}}; int n_arguments = 0; bool invalid_arg = false; int match; bool found = false; CommandFunction *func = NULL; memset(data, 0x0, sizeof(data)); memset(arg_data, 0x0, sizeof(data)); if (strlen(line) > ARGS_BUFFER_SIZE) { printf("Command too long\n"); return 0; } strcpy(data, line); argc = tokenize(data, argv, 64, NULL, NULL, SPACES); while (i < argc) { // NOTE(adma): match the first n-1 items if (completing_args == false) { // NOTE(adma): match subcommands match = strncmp(argv[i], command->name, strlen(argv[i])); if (match == 0) { if (command->subcommands != NULL) { // NOTE(adma): if we were matching subcommands, keep // matching subcommands if any command = command->subcommands; } else { // NOTE(adma): start matching arguments otherwise. Also keep // track of the function because that's the one we want to // call later on completing_args = true; func = command->func; if (command->args != NULL) { char *arg_toks[64]; args = command->args; strncpy(arg_data, args, ARGS_BUFFER_SIZE); // since tokenize() modifies the buffer.. int num_args = tokenize(arg_data, arg_toks, 64, NULL, NULL, ","); if (num_args + 1 + i != argc) { // some arguments might have default values for (int j = 0; j < num_args; j++) { if (j < argc - 1 - i) { continue; } char *str = strchr(arg_toks[j], '='); if (str == NULL) { break; } str++; argv[j + 1 + i] = str; argc++; } } } else { // NOTE(adma): there are no args for this command found = true; break; } } i++; // NOTE(adma): next word } else { // NOTE(adma): command not found command = command->next; if (match < 0 || command == NULL) { command = NULL; break; } } } else { // NOTE(adma): match arguments if (validate_arg(ctx, *args, argv[i], arguments + n_arguments++, g_in_fmt != fmt_nofmt ? g_in_fmt : command->in_fmt) != 0) { invalid_arg = true; break; } while (*args != '\0' && *args != ',') { args++; } if (*args == ',') { args++; i++; // NOTE(adma): next word } else { found = true; break; } } } if (found == true) { calling_device = true; func(ctx, arguments, g_in_fmt == fmt_nofmt ? command->in_fmt : g_in_fmt, g_out_fmt == fmt_nofmt ? command->out_fmt : g_out_fmt); calling_device = false; for (i = 0; i < n_arguments; i++) { if (arguments[i].x != NULL) { free(arguments[i].x); arguments[i].x = NULL; } } // NOTE: if ctx->in or ctx->out is changed, close and return state, // otherwise the next command that needs a file might get sad. if (ctx->out != stdout) { fclose(ctx->out); ctx->out = stdout; } } else { if (invalid_arg == true) { char arg[ARGS_BUFFER_SIZE + 1]; memset(arg, 0x0, sizeof(arg)); strncpy(arg, args, ARGS_BUFFER_SIZE); char *end = strchr(args, ','); if (end) { arg[end - args] = '\0'; } printf("Invalid argument %d: %s (%s)\n", i, argv[i], arg); } else if (command == NULL) { printf("Command %s%s%s not found\n", argv[0], i ? " " : "", i ? argv[1] : ""); } else if (*args != '\0' || argc - 1 == 0) { printf("Incomplete command\n"); for (i = 0; i < argc; i++) { arguments[i].s = argv[i]; } yh_com_help(NULL, arguments, fmt_nofmt, fmt_nofmt); } } return 0; } static void free_configured_connectors(yubihsm_context *ctx) { if (ctx->connector_list) { for (int i = 0; ctx->connector_list[i]; i++) { free(ctx->connector_list[i]); } free(ctx->connector_list); ctx->connector_list = NULL; } } static int parse_configured_connectors(yubihsm_context *ctx, char **connectors, int n_connectors) { ctx->connector_list = calloc(n_connectors + 1, sizeof(char *)); if (ctx->connector_list == NULL) { return -1; } for (int i = 0; i < n_connectors; i++) { ctx->connector_list[i] = strdup(connectors[i]); if (ctx->connector_list[i] == NULL) { free_configured_connectors(ctx); return -1; } } return 0; } static void free_configured_pubkeys(yubihsm_context *ctx) { if (ctx->device_pubkey_list) { for (int i = 0; ctx->device_pubkey_list[i]; i++) { free(ctx->device_pubkey_list[i]); } free(ctx->device_pubkey_list); ctx->device_pubkey_list = NULL; } } static int parse_configured_pubkeys(yubihsm_context *ctx, char **pubkeys, int n_pubkeys) { ctx->device_pubkey_list = calloc(n_pubkeys + 1, sizeof(uint8_t *)); if (ctx->device_pubkey_list == NULL) return -1; for (int i = 0; i < n_pubkeys; i++) { uint8_t pk[80]; size_t pk_len = sizeof(pk); hex_decode(pubkeys[i], pk, &pk_len); if (pk_len == YH_EC_P256_PUBKEY_LEN) { ctx->device_pubkey_list[i] = malloc(pk_len); } if (ctx->device_pubkey_list[i]) { memcpy(ctx->device_pubkey_list[i], pk, pk_len); } else { free_configured_pubkeys(ctx); return -1; } } return 0; } int main(int argc, char *argv[]) { yh_rc yrc; int comrc; int rc = EXIT_SUCCESS; struct gengetopt_args_info args_info; struct stat sb; struct cmdline_parser_params params; if (setlocale(LC_ALL, "") == NULL) { fprintf(stderr, "Warning, unable to reset locale\n"); } g_ctx.out = stdout; cmdline_parser_params_init(¶ms); params.initialize = 1; params.check_required = 0; if (cmdline_parser(argc, argv, &args_info) != 0) { return EXIT_FAILURE; } if (stat(args_info.config_file_arg, &sb) == 0) { if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) { params.initialize = 0; if (cmdline_parser_config_file(args_info.config_file_arg, &args_info, ¶ms) != 0) { return EXIT_FAILURE; } } } if (cmdline_parser_required(&args_info, argv[0]) != 0) { return EXIT_FAILURE; } switch (args_info.informat_arg) { case informat_arg_base64: g_in_fmt = fmt_base64; break; case informat_arg_binary: g_in_fmt = fmt_binary; break; case informat_arg_PEM: g_in_fmt = fmt_PEM; break; case informat_arg_password: g_in_fmt = fmt_password; break; case informat_arg_hex: g_in_fmt = fmt_hex; break; case informat__NULL: case informat_arg_default: default: g_in_fmt = fmt_nofmt; break; } switch (args_info.outformat_arg) { case outformat_arg_base64: g_out_fmt = fmt_base64; break; case outformat_arg_binary: g_out_fmt = fmt_binary; break; case outformat_arg_PEM: g_out_fmt = fmt_PEM; break; case outformat_arg_hex: g_out_fmt = fmt_hex; break; case outformat__NULL: case outformat_arg_default: default: g_out_fmt = fmt_nofmt; break; } if (parse_configured_connectors(&g_ctx, args_info.connector_arg, args_info.connector_given) == -1) { fprintf(stderr, "Unable to parse connector list\n"); rc = EXIT_FAILURE; goto main_exit; } if (parse_configured_pubkeys(&g_ctx, args_info.device_pubkey_arg, args_info.device_pubkey_given) == -1) { fprintf(stderr, "Unable to parse device pubkey list\n"); rc = EXIT_FAILURE; goto main_exit; } if (getenv("DEBUG") != NULL) { args_info.verbose_arg = YH_VERB_ALL; } yh_set_verbosity(g_ctx.connector, args_info.verbose_arg); yrc = yh_init(); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to initialize libyubihsm\n"); rc = EXIT_FAILURE; goto main_exit; } ykhsmauth_rc ykhsmauthrc; ykhsmauthrc = ykhsmauth_init(&g_ctx.state, 1); // TODO(adma): do something about verbosity if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to initialize libykhsmauth\n"); rc = EXIT_FAILURE; goto main_exit; } if (g_ctx.connector_list[0] == NULL) { fprintf(stderr, "Using default connector URL: %s\n", DEFAULT_CONNECTOR_URL); char *default_connector_url = DEFAULT_CONNECTOR_URL; free_configured_connectors(&g_ctx); parse_configured_connectors(&g_ctx, &default_connector_url, 1); } if (args_info.cacert_given) { g_ctx.cacert = strdup(args_info.cacert_arg); } if (args_info.cert_given) { g_ctx.cert = strdup(args_info.cert_arg); } if (args_info.key_given) { g_ctx.key = strdup(args_info.key_arg); } if (args_info.proxy_given) { g_ctx.proxy = strdup(args_info.proxy_arg); } if (args_info.noproxy_given) { g_ctx.noproxy = strdup(args_info.noproxy_arg); } #ifndef __WIN32 struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = timer_handler; act.sa_flags = SA_RESTART; sigaction(SIGALRM, &act, NULL); sigset_t set; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_UNBLOCK, &set, NULL); #endif if (args_info.action_given) { g_ctx.out = open_file(args_info.out_arg, false); if (g_ctx.out == NULL) { fprintf(stderr, "Unable to open output file %s\n", args_info.out_arg); rc = EXIT_FAILURE; goto main_exit; } yh_com_connect(&g_ctx, NULL, fmt_nofmt, fmt_nofmt); bool requires_session = false; for (unsigned i = 0; i < args_info.action_given; i++) { switch (args_info.action_arg[i]) { case action_arg_getMINUS_deviceMINUS_info: case action_arg_getMINUS_deviceMINUS_pubkey: requires_session = false; break; default: requires_session = true; } if (requires_session == true) { break; } } Argument arg[11] = {0}; if (requires_session == true) { uint8_t *buf = 0; size_t pw_len = 0; arg[0].w = args_info.authkey_arg; if (get_input_data(args_info.password_given ? args_info.password_arg : "-", &buf, &pw_len, fmt_password) == false) { fprintf(stderr, "Failed to get password\n"); rc = EXIT_FAILURE; goto main_exit; } if (args_info.ykhsmauth_label_given) { arg[1].s = args_info.ykhsmauth_label_arg; arg[1].len = strlen(args_info.ykhsmauth_label_arg); arg[2].x = buf; arg[2].len = pw_len; arg[3].s = args_info.ykhsmauth_reader_arg; arg[3].len = strlen(args_info.ykhsmauth_reader_arg); comrc = yh_com_open_yksession(&g_ctx, arg, fmt_password, fmt_nofmt); } else { arg[1].x = buf; arg[1].len = pw_len; comrc = yh_com_open_session(&g_ctx, arg, fmt_password, fmt_nofmt); } insecure_memzero(buf, pw_len); free(buf); if (comrc != 0) { fprintf(stderr, "Failed to open session\n"); rc = EXIT_FAILURE; goto main_exit; } } for (size_t i = 0; i < sizeof(g_ctx.sessions) / sizeof(g_ctx.sessions[0]); i++) { if (g_ctx.sessions[i] != NULL) { arg[0].e = g_ctx.sessions[i]; break; } } calling_device = true; for (unsigned i = 0; i < args_info.action_given; i++) { switch (args_info.action_arg[i]) { case action_arg_decryptMINUS_pkcs1v15: { arg[1].w = args_info.object_id_arg; if (get_input_data(args_info.in_arg, &arg[2].x, &arg[2].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_decrypt_pkcs1v1_5(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to decrypt data"); } break; case action_arg_decryptMINUS_oaep: { if (args_info.object_id_given == 0) { fprintf(stderr, "Missing object id\n"); rc = EXIT_FAILURE; break; } if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } arg[4].s = args_info.label_arg; arg[4].len = strlen(args_info.label_arg); comrc = yh_com_decrypt_oaep(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to decrypt data"); } break; case action_arg_deriveMINUS_ecdh: { arg[1].w = args_info.object_id_arg; if (get_input_data(args_info.in_arg, &arg[2].x, &arg[2].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_derive_ecdh(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_hex : g_out_fmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to perform ECDH key exchange"); } break; case action_arg_decryptMINUS_aesccm: case action_arg_encryptMINUS_aesccm: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); case action_arg_encryptMINUS_aescbc: case action_arg_decryptMINUS_aescbc: { if (args_info.iv_given == 0) { fprintf(stderr, "Missing argument IV\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.iv_arg; if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } if (args_info.action_arg[i] == action_arg_encryptMINUS_aescbc) { comrc = yh_com_encrypt_aes_cbc(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to encrypt input"); } else { comrc = yh_com_decrypt_aes_cbc(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to decrypt input"); } } break; case action_arg_encryptMINUS_aesecb: case action_arg_decryptMINUS_aesecb: { arg[1].w = args_info.object_id_arg; if (get_input_data(args_info.in_arg, &arg[2].x, &arg[2].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } if (args_info.action_arg[i] == action_arg_encryptMINUS_aesecb) { comrc = yh_com_encrypt_aes_ecb(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to encrypt input"); } else { comrc = yh_com_decrypt_aes_ecb(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to decrypt input"); } } break; case action_arg_generateMINUS_asymmetricMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); comrc = yh_com_generate_asymmetric(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate asymmetric key"); } break; case action_arg_generateMINUS_hmacMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); comrc = yh_com_generate_hmac(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate hmac key"); } break; case action_arg_generateMINUS_wrapMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } if (args_info.delegated_given == 0) { fprintf(stderr, "Missing delegated capabilities\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[6].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); comrc = yh_com_generate_wrap(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate wrap key"); } break; case action_arg_generateMINUS_otpMINUS_aeadMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } if (args_info.nonce_given == 0) { fprintf(stderr, "Missing argument nonce\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); arg[6].d = args_info.nonce_arg; comrc = yh_com_generate_otp_aead_key(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate otp key"); } break; case action_arg_generateMINUS_symmetricMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); comrc = yh_com_generate_symmetric(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate symmetric key"); } break; case action_arg_getMINUS_opaque: { arg[1].w = args_info.object_id_arg; comrc = yh_com_get_opaque(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get opaque object"); } break; case action_arg_getMINUS_pseudoMINUS_random: { arg[1].w = args_info.count_arg; comrc = yh_com_get_random(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_hex : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get random bytes"); } break; case action_arg_getMINUS_storageMINUS_info: comrc = yh_com_get_storage(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get storage stats"); break; case action_arg_getMINUS_publicMINUS_key: { arg[1].w = args_info.object_id_arg; if(args_info.object_type_given) { yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); } else { arg[2].t = YH_ASYMMETRIC_KEY; } arg[3].s = args_info.out_arg; arg[3].len = strlen(args_info.out_arg); comrc = yh_com_get_pubkey(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_PEM : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get public key"); } break; case action_arg_getMINUS_deviceMINUS_pubkey: comrc = yh_com_get_device_pubkey(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_PEM : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get device public key"); break; case action_arg_getMINUS_objectMINUS_info: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object type\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); comrc = yh_com_get_object_info(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get object info"); } break; case action_arg_getMINUS_wrapped: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object-type\n"); rc = EXIT_FAILURE; break; } if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); arg[3].w = args_info.object_id_arg; arg[4].b = args_info.include_seed_given; arg[5].s = args_info.out_arg; arg[5].len = strlen(args_info.out_arg); comrc = yh_com_get_wrapped(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get wrapped object"); } break; case action_arg_getMINUS_rsaMINUS_wrapped: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object-type\n"); rc = EXIT_FAILURE; break; } if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); arg[3].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[4].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); yrc = yh_string_to_algo(args_info.oaep_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: "); yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[6].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: "); arg[7].s = args_info.out_arg; arg[7].len = strlen(args_info.out_arg); comrc = yh_com_get_rsa_wrapped(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get wrapped object"); } break; case action_arg_getMINUS_rsaMINUS_wrappedMINUS_key: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object-type\n"); rc = EXIT_FAILURE; break; } if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); arg[3].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[4].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); yrc = yh_string_to_algo(args_info.oaep_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: "); yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[6].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: "); arg[7].s = args_info.out_arg; arg[7].len = strlen(args_info.out_arg); comrc = yh_com_get_rsa_wrapped_key(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get wrapped object"); } break; case action_arg_getMINUS_deviceMINUS_info: comrc = yh_com_get_device_info(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get device info"); break; case action_arg_getMINUS_template: { arg[1].w = args_info.object_id_arg; comrc = yh_com_get_template(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get template object"); } break; case action_arg_listMINUS_objects: { arg[1].w = args_info.object_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); arg[6].b = args_info.with_compression_given; arg[7].s = args_info.label_arg; arg[7].len = strlen(args_info.label_arg); comrc = yh_com_list_objects(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to list objects"); } break; case action_arg_putMINUS_authenticationMINUS_key: { if (args_info.new_password_given == 0) { fprintf(stderr, "Missing argument new-password\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); arg[6].x = (uint8_t *) args_info.new_password_arg; arg[6].len = strlen(args_info.new_password_arg); comrc = yh_com_put_authentication(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to store authentication key"); } break; case action_arg_putMINUS_asymmetricMINUS_key: { arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); if (get_input_data(args_info.in_arg, &arg[5].x, &arg[5].len, g_in_fmt == fmt_nofmt ? fmt_PEM : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_asymmetric(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[5].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store asymmetric key"); } break; case action_arg_putMINUS_opaque: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); arg[6].b = args_info.with_compression_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"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_opaque(&g_ctx, arg, g_in_fmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store opaque object"); } break; case action_arg_putMINUS_option: { if (args_info.opt_name_given == 0) { fprintf(stderr, "Missing argument opt-name\n"); rc = EXIT_FAILURE; break; } if (args_info.opt_value_given == 0) { fprintf(stderr, "Missing argument opt-value\n"); rc = EXIT_FAILURE; break; } yrc = yh_string_to_option(args_info.opt_name_arg, &arg[1].o); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse option name: "); arg[2].x = calloc(ARGS_BUFFER_SIZE, 1); arg[2].len = ARGS_BUFFER_SIZE; if (hex_decode(args_info.opt_value_arg, arg[2].x, &arg[2].len) == false) { fprintf(stderr, "Unable to decode option value\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_option(&g_ctx, arg, fmt_hex, fmt_nofmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to put option"); } break; case action_arg_getMINUS_option: { if (args_info.opt_name_given == 0) { fprintf(stderr, "Missing argument opt-name\n"); rc = EXIT_FAILURE; break; } yrc = yh_string_to_option(args_info.opt_name_arg, &arg[1].o); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse option name: "); comrc = yh_com_get_option(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get option"); } break; case action_arg_putMINUS_hmacMINUS_key: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_putMINUS_wrapMINUS_key: { if (args_info.delegated_given == 0) { fprintf(stderr, "Missing delegated capabilities\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len, g_in_fmt == fmt_nofmt ? fmt_hex : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_wrapkey(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to put wrapkey"); } break; case action_arg_putMINUS_rsaMINUS_wrapkey: { if (args_info.delegated_given == 0) { fprintf(stderr, "Missing delegated capabilities\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len, g_in_fmt == fmt_nofmt ? fmt_PEM : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_rsa_wrapkey(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to put wrapkey"); } break; case action_arg_putMINUS_publicMINUS_wrapkey: { if (args_info.delegated_given == 0) { fprintf(stderr, "Missing delegated capabilities\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len, g_in_fmt == fmt_nofmt ? fmt_PEM : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_public_wrapkey(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to put wrapkey"); } break; case action_arg_putMINUS_symmetricMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); 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, g_in_fmt == fmt_nofmt ? fmt_hex : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_symmetric(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store symmetric key"); } break; case action_arg_putMINUS_wrapped: { if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; if (get_input_data(args_info.in_arg, &arg[2].x, &arg[2].len, g_in_fmt == fmt_nofmt ? fmt_base64 : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_wrapped(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store wrapped object"); } break; case action_arg_putMINUS_rsaMINUS_wrapped: { if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_algo(args_info.oaep_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: "); yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[3].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: "); if (get_input_data(args_info.in_arg, &arg[4].x, &arg[4].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_rsa_wrapped(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[4].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store RSA wrapped object"); } break; case action_arg_putMINUS_rsaMINUS_wrappedMINUS_key: { if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument type\n"); rc = EXIT_FAILURE; break; } if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument key-algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse object type: "); arg[3].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[4].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse key algorithm: "); arg[5].s = args_info.label_arg; arg[5].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[6].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[7].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.oaep_arg, &arg[8].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: "); yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[9].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: "); if (get_input_data(args_info.in_arg, &arg[10].x, &arg[10].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_rsa_wrapped_key(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[10].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store RSA wrapped object"); } break; case action_arg_putMINUS_template: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); 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, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_template(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store template object"); } break; case action_arg_putMINUS_otpMINUS_aeadMINUS_key: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_signMINUS_eddsa: case action_arg_signMINUS_ecdsa: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } if (args_info.action_arg[i] == action_arg_signMINUS_ecdsa) { comrc = yh_com_sign_ecdsa(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); } else { comrc = yh_com_sign_eddsa(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); } free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to sign data"); } break; case action_arg_signMINUS_pkcs1v15: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_sign_pkcs1v1_5(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to sign data"); } break; case action_arg_signMINUS_pss: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_sign_pss(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to sign data"); } break; case action_arg_signMINUS_hmac: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_reset: { comrc = yh_com_reset(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to reset device"); } break; case action_arg_deleteMINUS_object: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object type\n"); rc = EXIT_FAILURE; break; } yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); arg[1].w = args_info.object_id_arg; comrc = yh_com_delete(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to delete object"); } break; case action_arg_signMINUS_sshMINUS_certificate: { if (args_info.template_id_given == 0) { fprintf(stderr, "Missing argument template-id\n"); rc = EXIT_FAILURE; break; } if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].w = args_info.template_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[3].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[4].x, &arg[4].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { // TODO: correct format? fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_sign_ssh_certificate(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[4].x); COM_SUCCEED_OR_DIE(comrc, "Unable to get ssh certificate"); } break; case action_arg_benchmark: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); case action_arg_createMINUS_otpMINUS_aead: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_randomizeMINUS_otpMINUS_aead: { arg[1].w = args_info.object_id_arg; arg[2].s = args_info.out_arg; arg[2].len = strlen(args_info.out_arg); comrc = yh_com_otp_aead_random(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get aead from random"); } break; case action_arg_decryptMINUS_otp: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_signMINUS_attestationMINUS_certificate: { if (args_info.attestation_id_given == 0) { fprintf(stderr, "Missing argument attestation-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].w = args_info.attestation_id_arg; comrc = yh_com_sign_attestation_certificate(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_PEM : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to attest asymmetric key"); } break; case action_arg_getMINUS_logs: { comrc = yh_com_audit(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_ASCII : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to extract logs"); } break; case action_arg_setMINUS_logMINUS_index: { if (args_info.log_index_given == 0) { fprintf(stderr, "Missing argument log-index\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.log_index_arg; comrc = yh_com_set_log_index(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_ASCII : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to set log index"); } break; case action_arg_blinkMINUS_device: { if (args_info.duration_arg < 0 || args_info.duration_arg > 0xff) { fprintf(stderr, "Duration must be in [0, 256]\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.duration_arg; comrc = yh_com_blink(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to blink device"); } break; case action_arg_generateMINUS_csr: { if (args_info.object_id_given == 0) { fprintf(stderr, "Missing argument object ID\n"); rc = EXIT_FAILURE; break; } if (args_info.subject_given == 0) { fprintf(stderr, "Missing argument subject\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.subject_arg; arg[2].len = strlen(args_info.subject_arg); arg[3].s = args_info.out_arg; arg[3].len = strlen(args_info.out_arg); comrc = yh_com_generate_csr(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_PEM : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate certificate request"); } break; case action__NULL: printf("ERROR !%u \n", args_info.action_given); rc = EXIT_FAILURE; } if (rc == EXIT_FAILURE) { break; } } calling_device = false; } else { int num = 0; #ifndef __WIN32 EditLine *el; HistEvent ev; g_hist = history_init(); history(g_hist, &ev, H_SETSIZE, 1000); // NOTE(adma): 1000 history items el = el_init(*argv, stdin, stdout, stderr); el_set(el, EL_EDITOR, "emacs"); #ifdef EL_PROMPT_ESC el_set(el, EL_PROMPT_ESC, prompt, '\1'); /* Set the prompt function */ #else el_set(el, EL_PROMPT, prompt); /* Set the prompt function */ #endif /* EL_PROMPT_ESC */ el_set(el, EL_HIST, history, g_hist); /* enable ctrl-R for reverse history search */ el_set(el, EL_BIND, "^R", "em-inc-search-prev", NULL); /* Add a user-defined function */ el_set(el, EL_ADDFN, "yh_complete", "Complete argument", yubihsm_complete); /* Bind tab to it */ el_set(el, EL_BIND, "^I", "yh_complete", NULL); el_source(el, NULL); // NOTE(adma): source the user's defaults file #endif create_command_list(&g_commands); if (args_info.pre_connect_flag) { yh_com_connect(&g_ctx, NULL, fmt_nofmt, fmt_nofmt); } while (g_running == true) { #ifdef __WIN32 fprintf(stdout, PROMPT); char data[1025]; char *buf = converting_fgets(data, sizeof(data), stdin); if (buf) { num = strlen(buf); } #else const char *buf = el_gets(el, &num); #endif if (buf == NULL) { // NOTE(adma): got Ctrl-D yh_com_quit(NULL, NULL, fmt_nofmt, fmt_nofmt); fprintf(stdout, "\n"); } else if (num > 0 && buf[0] != '\n' && buf[0] != '\r') { #ifndef __WIN32 history(g_hist, &ev, H_ENTER, buf); #endif validate_and_call(&g_ctx, g_commands, buf); } } #ifndef __WIN32 el_end(el); history_end(g_hist); #endif } main_exit: calling_device = true; for (size_t i = 0; i < sizeof(g_ctx.sessions) / sizeof(g_ctx.sessions[0]); i++) { if (g_ctx.sessions[i]) { yh_util_close_session(g_ctx.sessions[i]); yh_destroy_session(&g_ctx.sessions[i]); } } yh_disconnect(g_ctx.connector); cmdline_parser_free(&args_info); if (g_ctx.out != stdout && g_ctx.out != NULL) { fclose(g_ctx.out); } if (g_ctx.cacert) { free(g_ctx.cacert); } if (g_ctx.cert) { free(g_ctx.cert); } if (g_ctx.key) { free(g_ctx.key); } if (g_ctx.proxy) { free(g_ctx.proxy); } if (g_ctx.noproxy) { free(g_ctx.noproxy); } yh_exit(); ykhsmauth_done(g_ctx.state); g_ctx.state = NULL; free_configured_pubkeys(&g_ctx); free_configured_connectors(&g_ctx); return rc; } yubihsm-shell-2.7.3/src/version.rc.in0000644000175000017500000000215015167357110016501 0ustar aveenaveen #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM Shell" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "yubihsm-shell.exe" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "yubihsm-shell.exe" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.7.3/src/CMakeLists.txt0000644000175000017500000000617115167357110016630 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(${CMAKE_SOURCE_DIR}/cmake/openssl.cmake) find_libcrypto() set ( SOURCE commands.c main.c cmd_util.c ../common/util.c ../common/hash.c ../common/parsing.c ../common/openssl-compat.c ) if(WIN32) set(SOURCE ${SOURCE} cmdline.c) include(${CMAKE_SOURCE_DIR}/cmake/getopt.cmake) find_getopt() else(WIN32) include(gengetopt) find_gengetopt () add_gengetopt_files (cmdline "--conf-parser") set(SOURCE ${SOURCE} ${GGO_C}) endif(WIN32) include_directories ( ${LIBCRYPTO_INCLUDEDIR} ${LIBEDIT_INCLUDEDIR} ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../common ) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../ykhsmauth) set(YKHSMAUTH_LIB ykhsmauth) set(YKHSMAUTH_LIB_STATIC ykhsmauth_static) if(WIN32) list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) endif(WIN32) # NOTE(adma): required by gengetopt add_definitions (-DPACKAGE="yubihsm-shell") add_definitions (-DVERSION="${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") list(APPEND LCOV_REMOVE_PATTERNS "'${PROJECT_SOURCE_DIR}/src/cmdline.c'") add_executable (yubihsm-shell ${SOURCE}) if (ENABLE_STATIC AND NOT FUZZING) add_executable (yubihsm-shell_static ${SOURCE}) set_target_properties (yubihsm-shell_static PROPERTIES COMPILE_FLAGS "-DSTATIC") target_link_libraries(yubihsm-shell_static ${LIBCRYPTO_LDFLAGS} ${LIBEDIT_LDFLAGS} ${GETOPT_LIBS} yubihsm_static ${YKHSMAUTH_LIB_STATIC}) add_coverage (yubihsm-shell_static) endif () target_link_libraries ( yubihsm-shell ${LIBCRYPTO_LDFLAGS} ${LIBEDIT_LDFLAGS} ${GETOPT_LIBS} yubihsm ${YKHSMAUTH_LIB}) # Set install RPATH (Darwin default from root CMakeLists.txt is correct for bin/ targets) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_target_properties(yubihsm-shell PROPERTIES INSTALL_RPATH "${YUBIHSM_INSTALL_LIB_DIR}") endif() add_coverage (yubihsm-shell) install( TARGETS yubihsm-shell ARCHIVE DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" LIBRARY DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" RUNTIME DESTINATION "${YUBIHSM_INSTALL_BIN_DIR}") if (NOT WITHOUT_MANPAGES) include (help2man) add_help2man_manpage (yubihsm-shell.1 yubihsm-shell) add_custom_target (yubihsm-shell-man ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/yubihsm-shell.1 ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/yubihsm-shell.1" DESTINATION "${YUBIHSM_INSTALL_MAN_DIR}/man1") endif() add_subdirectory (tests) yubihsm-shell-2.7.3/src/commands.h0000644000175000017500000002773415167357110016052 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef COMMANDS_H #define COMMANDS_H #include #include "yubihsm.h" #include "yubihsm-shell.h" typedef struct { union { uint8_t b; uint16_t w; uint32_t d; const char *s; yh_session *e; yh_capabilities c; yh_algorithm a; yh_object_type t; yh_option o; }; uint8_t *x; size_t len; } Argument; typedef int CommandFunction(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_audit(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_log_index(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_close_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_connect(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_all(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_error(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_intermediate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_none(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_raw(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_crypto(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_pkcs1v1_5(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_oaep(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_derive_ecdh(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_aesccm(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_encrypt_aesccm(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_aes_ecb(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_encrypt_aes_ecb(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_aes_cbc(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_encrypt_aes_cbc(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_disconnect(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_echo(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_echo(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_symmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_asymmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_csr(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_wrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_otp_aead_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_option(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_random(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_storage(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_device_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_object_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_device_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_capabilities(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_algorithms(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_types(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_connectors(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_sessions(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_objects(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_open_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_open_session_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_open_yksession(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_pecho(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_symmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_asymmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_authentication(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_authentication_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_option(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_rsa_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_public_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_otp_aead_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_ecdsa(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_eddsa(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_pkcs1v1_5(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_pss(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_reset(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_delete(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_ssh_certificate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_benchmark(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_otp_aead_create(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_otp_aead_random(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_otp_decrypt(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_otp_rewrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_attestation_certificate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_keepalive_on(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_keepalive_off(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_noop(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_blink(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_cacert(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_cert(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_proxy(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_noproxy(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_change_authentication_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_change_authentication_key_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); #endif yubihsm-shell-2.7.3/src/cmd_util.h0000644000175000017500000000154715167357110016043 0ustar aveenaveen/* * Copyright 2025 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YUBIHSM_SHELL_CMD_UTIL_H #define YUBIHSM_SHELL_CMD_UTIL_H EVP_PKEY *wrap_public_key(yh_session *session, yh_algorithm algorithm, EVP_PKEY *public_key, uint16_t key_id); X509_NAME *parse_subject_name(const char *orig_name); #endif // YUBIHSM_SHELL_CMD_UTIL_H yubihsm-shell-2.7.3/src/tests/0000755000175000017500000000000015167357110015225 5ustar aveenaveenyubihsm-shell-2.7.3/src/tests/CMakeLists.txt0000644000175000017500000000200515167357110017762 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # find_program (BASH_PROGRAM bash) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/data.txt ${CMAKE_CURRENT_BINARY_DIR}/data.txt COPYONLY) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/sig.out ${CMAKE_CURRENT_BINARY_DIR}/sig.out COPYONLY) add_test( NAME bash_tests COMMAND ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/tests.sh ) add_test( NAME wrapped_tests COMMAND ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/wrapped_tests.sh ) yubihsm-shell-2.7.3/src/tests/tests.sh0000755000175000017500000000612115167357110016726 0ustar aveenaveen#!/bin/bash # # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set -e set -x TMPDIR=$(mktemp -d) #trap 'rm -rf "$TMPDIR"' INT TERM EXIT DATA="$TMPDIR/data" SIG="$TMPDIR/sig" BIN_SIG="$TMPDIR/bin_sig" PUBLIC_KEY="$TMPDIR/public" if [ -z ${DEFAULT_CONNECTOR_URL} ]; then DEFAULT_CONNECTOR_URL="http://localhost:12345" fi PROG="../yubihsm-shell --connector=${DEFAULT_CONNECTOR_URL}" if [ "x$(uname)" = "xFreeBSD" ]; then DECODE="b64decode -pr" else DECODE="base64 --decode -i" fi echo "Hello World!" >"$DATA" OUTPUT=$($PROG -a generate-asymmetric -A ecp256 -csign-ecdsa -p password 2>&1) OBJ_ID=$(echo "$OUTPUT" | grep -o -E '0x[a-f0-9]{4}$') $PROG -a sign-ecdsa -i $OBJ_ID -A ecdsa-sha256 --in "$DATA" --out "$SIG" -p password $DECODE "$SIG" >"$BIN_SIG" $PROG -a get-public-key -i $OBJ_ID --out "$PUBLIC_KEY" -p password openssl dgst -sha256 -verify "$PUBLIC_KEY" -signature "$BIN_SIG" "$DATA" truncate -s 0 "$SIG" truncate -s 0 "$PUBLIC_KEY" #$PROG -a generate-asymmetric -i 0x1234 -A ecp256 -csign_ecdsa $PROG -a sign-ecdsa -i $OBJ_ID -A ecdsa-sha1 --in "$DATA" --out "$SIG" -p password $DECODE "$SIG" >"$BIN_SIG" $PROG -a get-public-key -i $OBJ_ID --out "$PUBLIC_KEY" -p password openssl dgst -sha1 -verify "$PUBLIC_KEY" -signature "$BIN_SIG" "$DATA" truncate -s 0 "$SIG" truncate -s 0 "$PUBLIC_KEY" OUTPUT=$($PROG -a generate-asymmetric -A ecp384 -csign-ecdsa -p password 2>&1) OBJ_ID=$(echo "$OUTPUT" | grep -o -E '0x[a-f0-9]{4}$') $PROG -a sign-ecdsa -i $OBJ_ID -A ecdsa-sha384 --in "$DATA" --out "$SIG" -p password $DECODE "$SIG" >"$BIN_SIG" $PROG -a get-public-key -i $OBJ_ID --out "$PUBLIC_KEY" -p password openssl dgst -sha384 -verify "$PUBLIC_KEY" -signature "$BIN_SIG" "$DATA" truncate -s 0 "$SIG" truncate -s 0 "$PUBLIC_KEY" OUTPUT=$($PROG -a generate-asymmetric -A ecp521 -csign-ecdsa -p password 2>&1) OBJ_ID=$(echo "$OUTPUT" | grep -o -E '0x[a-f0-9]{4}$') $PROG -a sign-ecdsa -i $OBJ_ID -A ecdsa-sha512 --in "$DATA" --out "$SIG" -p password $DECODE "$SIG" >"$BIN_SIG" $PROG -a get-public-key -i $OBJ_ID --out "$PUBLIC_KEY" -p password openssl dgst -sha512 -verify "$PUBLIC_KEY" -signature "$BIN_SIG" "$DATA" $PROG -a blink-device -p password $PROG -a get-device-info $PROG -a get-storage-info -p password $PROG -a get-option -p password --opt-name command-audit $PROG -a put-option -p password --opt-name command-audit --opt-value 0101 $PROG -a get-option -p password --opt-name force-audit $PROG -a put-option -p password --opt-name force-audit --opt-value 00 $PROG -a get-option -p password --opt-name algorithm-toggle # no test for putting algorithm-toggle as that requires and empty device yubihsm-shell-2.7.3/src/tests/yubihsm_shell_tests.c0000644000175000017500000001332015167357110021461 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #define EXIT_SKIPPED 77; yh_device **devices; uint16_t n_devices; yh_session *ses; typedef struct { uint16_t len; double min; double max; double tot; } repetition_stats; #define DEFAULT_KEY \ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" #define N_REPS \ 8 // Data length for repetition i is 2^(1 + i) for i in [0, N_REPS-1] #define N_ITERATIONS 1000 #define ECHO_BYTE 0x0f int main() { yh_rc yrc; uint8_t key_enc[YH_KEY_LEN]; uint8_t key_mac[YH_KEY_LEN]; uint8_t key_dek[YH_KEY_LEN]; uint8_t host_challenge[YH_HOST_CHAL_LEN] = {0}; uint8_t yh_context[YH_CONTEXT_LEN]; struct timeval before, after; double this; repetition_stats rs[N_REPS], rs2[N_REPS]; uint8_t data[YH_MSG_BUF_SIZE]; uint8_t response[YH_MSG_BUF_SIZE]; uint16_t response_len; uint16_t len; uint8_t verbosity = 0; // YH_VERB_USB | YH_VERB_CRYPTO | YH_VERB_INTERMEDIATE // | YH_VERB_INFO | YH_VERB_ERR; yrc = yh_init(&devices, &n_devices); if (yrc != YH_SUCCESS) { fprintf(stderr, "Unable to initialize\n"); fprintf(stderr, "(Typically this happens if you don't have permissions to " "open the device\n"); fprintf(stderr, "try re-running as root/Administrator)\n"); return EXIT_SKIPPED; } if (n_devices == 0) { fprintf(stderr, "No suitable device found. Skipping this test\n"); return EXIT_SKIPPED; } yh_set_verbosity(verbosity); memset(data, ECHO_BYTE, 1024); // Plain commands len = 4; for (uint16_t rep = 0; rep < N_REPS; rep++) { len *= 2; rs[rep].len = len; fprintf(stderr, "now doing plain with len %d\n", len); for (uint16_t i = 0; i < N_ITERATIONS; i++) { response_len = sizeof(response); gettimeofday(&before, NULL); yrc = yh_send_plain_msg(devices[0], YHC_ECHO, data, rs[rep].len, response, &response_len); gettimeofday(&after, NULL); this = (after.tv_sec - before.tv_sec) * 1000; this += ((double) (after.tv_usec - before.tv_usec)) / 1000; if (i == 0) { rs[rep].max = rs[rep].min = this; rs[rep].tot = 0; } else { if (this > rs[rep].max) { rs[rep].max = this; } if (this < rs[rep].min) { rs[rep].min = this; } } rs[rep].tot += this; if (rs[rep].len != response_len || memcmp(data, response, rs[rep].len) != 0) { fprintf(stderr, "Data mismatch\n"); return EXIT_FAILURE; } } } // Auth commands memcpy(key_enc, DEFAULT_KEY, YH_KEY_LEN); // TODO: fix memcpy(key_mac, DEFAULT_KEY, YH_KEY_LEN); // TODO: fix memcpy(key_dek, DEFAULT_KEY, YH_KEY_LEN); // TODO: fix yrc = yh_open_device(devices[0]); if (yrc != YH_SUCCESS) { fprintf(stderr, "Unable to open device: %s\n", yh_strerror(yrc)); return EXIT_FAILURE; } yrc = yh_create_session(devices[0], 0, host_challenge, key_enc, 16, key_mac, 16, yh_context, &ses); if (yrc != YH_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); return EXIT_FAILURE; } len = 4; for (uint16_t rep = 0; rep < N_REPS; rep++) { len *= 2; rs2[rep].len = len; fprintf(stderr, "now doing auth with len %d\n", len); for (uint16_t i = 0; i < N_ITERATIONS; i++) { response_len = sizeof(response); gettimeofday(&before, NULL); yrc = yh_send_secure_msg(ses, YHC_ECHO, data, rs2[rep].len, response, &response_len); gettimeofday(&after, NULL); if (yrc != YH_SUCCESS) { fprintf(stderr, "Failed to send message: %d, %s\n", yrc, yh_strerror(yrc)); return EXIT_FAILURE; } this = (after.tv_sec - before.tv_sec) * 1000; this += ((double) (after.tv_usec - before.tv_usec)) / 1000; if (i == 0) { rs2[rep].max = rs2[rep].min = this; rs2[rep].tot = 0; } else { if (this > rs2[rep].max) { rs2[rep].max = this; } if (this < rs2[rep].min) { rs2[rep].min = this; } } rs2[rep].tot += this; if (rs2[rep].len != response_len || memcmp(data, response, rs2[rep].len) != 0) { fprintf(stderr, "Data mismatch\n"); return EXIT_FAILURE; } } } yh_exit(devices, n_devices); fprintf(stdout, "Iterations %d\n", N_ITERATIONS); fprintf(stdout, "| Len | min [ms] | max [ms] | avg [ms] | type |\n"); fprintf(stdout, "---------------------------------------------------\n"); for (uint16_t i = 0; i < N_REPS; i++) { fprintf(stdout, "| %6d | %8.02f | %8.02f | %8.02f | plain |\n", rs[i].len, rs[i].min, rs[i].max, rs[i].tot / N_ITERATIONS); } for (uint16_t i = 0; i < N_REPS; i++) { fprintf(stdout, "| %6d | %8.02f | %8.02f | %8.02f | auth |\n", rs2[i].len, rs2[i].min, rs2[i].max, rs2[i].tot / N_ITERATIONS); } return EXIT_SUCCESS; } yubihsm-shell-2.7.3/src/tests/data.txt0000644000175000017500000000001515167357110016673 0ustar aveenaveenHello World! yubihsm-shell-2.7.3/src/tests/wrapped_tests.sh0000755000175000017500000003711415167357110020456 0ustar aveenaveen#!/usr/bin/env bash # # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if [[ ! -z "$DEBUG" ]]; then set -x fi set -eo pipefail if [ -z ${DEFAULT_CONNECTOR_URL} ]; then DEFAULT_CONNECTOR_URL="http://localhost:12345" fi readonly TMPDIR=$(mktemp -d) trap 'rm -rf "$TMPDIR"' INT TERM EXIT echo ">>> TMPDIR=$TMPDIR" readonly YHSHELL="../yubihsm-shell --connector=${DEFAULT_CONNECTOR_URL}" readonly YHWRAP="../../yhwrap/yubihsm-wrap" put_yhwrapped_authkey() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r authid="0xbeef" local -r authkey="$TMPDIR/${FUNCNAME[0]}_authkey" local -r passfile="$TMPDIR/${FUNCNAME[0]}_passfile" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: put-wrap-key" openssl rand 32 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="all" --in="$wrapkey" --informat="binary" echo "${FUNCNAME[0]}: creating authkey" echo "password" > "$passfile" $YHWRAP --algorithm="aes128-yubico-authentication" --capabilities="all" \ --delegated="all" --domains="all" --id="$authid" --in="$passfile" \ --out="$authkey" --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$authid" --object-type="authentication-key" && { echo "${FUNCNAME[0]}: delete authkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$authid" --object-type="authentication-key" } echo "${FUNCNAME[0]}: put-wrapped authkey" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$authkey" --informat="base64" echo "${FUNCNAME[0]}: using put-wrapped authkey" $YHSHELL --action="get-pseudo-random" --password="$passfile" --authkey="$authid" \ --count=1 --out=/dev/null } put_yhwrapped_authkey_fail_cap() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r authid="0xbeef" local -r authkey="$TMPDIR/${FUNCNAME[0]}_authkey" local -r passfile="$TMPDIR/${FUNCNAME[0]}_passfile" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } openssl rand 16 > "$wrapkey" echo "${FUNCNAME[0]}: creating wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="none" \ --in="$wrapkey" --informat="binary" echo "${FUNCNAME[0]}: creating authkey" echo "password" > "$passfile" $YHWRAP --algorith="aes128-yubico-authentication" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$authid" --in="$passfile" --out="$authkey" \ --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" echo "${FUNCNAME[0]}: put-wrapped authkey" ! $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$authkey" --informat="base64" if [[ "${PIPESTATUS[0]}" != "1" ]]; then echo "put_yhwrapped_authkey_fail_caps: put-wrapped should have failed" exit 1 fi } put_yhwrapped_authkey_fail_domain() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r authid="0xbeef" local -r authkey="$TMPDIR/${FUNCNAME[0]}_authkey" local -r passfile="$TMPDIR/${FUNCNAME[0]}_passfile" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: creating restricted wrapkey" openssl rand 24 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="2" \ --capabilities="all" --delegated="all" \ --in="$wrapkey" --informat="binary" echo "${FUNCNAME[0]}: creating authkey" echo "password" > "$passfile" $YHWRAP --algorith="aes128-yubico-authentication" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$authid" --in="$passfile" --out="$authkey" \ --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$authid" --object-type="authentication-key" && { echo "${FUNCNAME[0]}: delete authkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$authid" --object-type="authentication-key" } echo "${FUNCNAME[0]}: put-wrapped authkey" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$authkey" --informat="base64" # NOTE(thorduri): Domains just get filtered. local domains domains="$( $YHSHELL --action="get-object-info" --password="password" \ --authkey="1" --object-type="authentication-key" --object-id="$authid" | grep "^id" \ | awk -F: '{print $7}' | awk -F, '{print $1}' | tr -d '[:space:]' )" if [[ "$domains" != "2" ]]; then echo "${FUNCNAME[0]}: domains not filtered: expected 2 got $domains" exit 1 fi } put_yhwrapped_asymmetric_rsa() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r keyid="0xfefe" local -r keyfile="$TMPDIR/${FUNCNAME[0]}_keyfile.pem" local -r keyfilew="$TMPDIR/${FUNCNAME[0]}_keyfile.wrapped" local -r sigbuf="$TMPDIR/${FUNCNAME[0]}_sigbuf" local -r signature="$TMPDIR/${FUNCNAME[0]}_signature" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: creating wrapkey" openssl rand 16 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="all" \ --in="$wrapkey" --informat="binary" local -r rsa=( "2048" "3072" "4096" ) for size in "${rsa[@]}"; do $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" && { echo "${FUNCNAME[0]}: delete rsa key" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" } echo "${FUNCNAME[0]}: creating rsa$size key" openssl genrsa -out "$keyfile.$size" $size $YHWRAP --algorithm="rsa$size" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$keyid" --in="$keyfile.$size" \ --out="$keyfilew.$size" --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" echo "${FUNCNAME[0]}: put-wrapped rsa$size asymmetric" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$keyfilew.$size" --informat="base64" echo "${FUNCNAME[0]}: comparing pubs rsa$size" openssl rsa -in "$keyfile.$size" -pubout > "$keyfile.$size.pub" $YHSHELL --action="get-public-key" --password="password" --authkey="1" \ --object-id="$keyid" --out="$keyfile.$size.pub.shell" diff -u "$keyfile.$size.pub" "$keyfile.$size.pub.shell" openssl rand 1024 > "$sigbuf" echo "${FUNCNAME[0]}: sign-pkcs1v15 rsa$size rsa-pkcs1-sha256" $YHSHELL --action="sign-pkcs1v15" --password="password" --authkey="1" \ --object-id="$keyid" --algorithm "rsa-pkcs1-sha256" --in="$sigbuf" --out "$signature.$size" --outformat="bin" echo "${FUNCNAME[0]}: verifying rsa$size sha256 signature" openssl dgst -sha256 -verify "$keyfile.$size.pub" -signature "$signature.$size" "$sigbuf" done } put_yhwrapped_asymmetric_ecdsa() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r keyid="0xfefe" local -r keyfile="$TMPDIR/${FUNCNAME[0]}_keyfile.pem" local -r keyfilew="$TMPDIR/${FUNCNAME[0]}_keyfile.wrapped" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: creating wrapkey" openssl rand 16 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="all" \ --in="$wrapkey" --informat="binary" curves="secp256k1 secp384r1 secp521r1 prime256v1" secp256k1=eck256 secp384r1=ecp384 secp521r1=ecp521 prime256v1=ecp256 if openssl ecparam -list_curves | grep -q brainpoolP256r1; then curves="$curves brainpoolP256r1 brainpoolP384r1 brainpoolP512r1" brainpoolP256r1=ecbp256 brainpoolP384r1=ecbp384 brainpoolP512r1=ecbp512 fi for curve in $curves; do $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" && { echo "${FUNCNAME[0]}: delete ec key" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" } echo "${FUNCNAME[0]}: creating ${!curve} key" openssl ecparam -genkey -noout -name $curve > "$keyfile.$curve" $YHWRAP --algorithm="${!curve}" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$keyid" --in="$keyfile.$curve" \ --out="$keyfilew.$curve" --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" echo "${FUNCNAME[0]}: put-wrapped ${!curve}" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$keyfilew.$curve" --informat="base64" echo "${FUNCNAME[0]}: comparing pubs ${!curve}" openssl ec -in "$keyfile.$curve" -pubout > "$keyfile.$curve.pub" $YHSHELL --action="get-public-key" --password="password" --authkey="1" \ --object-id="$keyid" --out="$keyfile.$curve.pub.shell" diff -u "$keyfile.$curve.pub" "$keyfile.$curve.pub.shell" done } put_yhwrapped_asymmetric_eddsa() { if [ $(openssl list -public-key-methods | grep -i ed25519 -c) -eq 0 ]; then echo "OpenSSL version without Ed25519, skipping put_yhwrapped_asymmetric_eddsa" return fi local -r edkeyid="0xeded" local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r keyid="0xfefe" local -r keyfile="$TMPDIR/${FUNCNAME[0]}_keyfile.pem" local -r keyfilew="$TMPDIR/${FUNCNAME[0]}_keyfile.wrapped" local -r sigfile1="$TMPDIR/${FUNCNAME[0]}_sig_1" local -r sigfile2="$TMPDIR/${FUNCNAME[0]}_sig_2" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: creating wrapkey" openssl rand 16 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="all" \ --in="$wrapkey" --informat="binary" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" && { echo "${FUNCNAME[0]}: delete ed key" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" } echo "${FUNCNAME[0]}: creating ed key" openssl genpkey -algorithm Ed25519 -out "$keyfile" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$edkeyid" --object-type="asymmetric-key" && { echo "${FUNCNAME[0]}: delete imported ed key" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$edkeyid" --object-type="asymmetric-key" } echo "${FUNCNAME[0]}: importing ed key" $YHSHELL --action="put-asymmetric-key" --password="password" --authkey="1" \ --object-id="$edkeyid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" \ --in="$keyfile" --informat="binary" echo "${FUNCNAME[0]}: signing with ed key" rm -f $sigfile1 $YHSHELL --action="sign-eddsa" --object-id="$edkeyid" --algorithm="ed25519" --in="$wrapkey" --out="$sigfile1" --password="password" $YHWRAP --algorithm="ed25519" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$keyid" --in="$keyfile" \ --out="$keyfilew" --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" echo "${FUNCNAME[0]}: put-wrapped ed25519" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$keyfilew" --informat="base64" echo "${FUNCNAME[0]}: comparing pubs ed25519" openssl pkey -in "$keyfile" -pubout > "$keyfile.pub" $YHSHELL --action="get-public-key" --password="password" --authkey="1" \ --object-id="$keyid" --out="$keyfile.pub.shell" diff -u "$keyfile.pub" "$keyfile.pub.shell" echo "${FUNCNAME[0]}: signing with wrapped ed key" rm -f "$sigfile2" $YHSHELL --action="sign-eddsa" --object-id="$keyid" --algorithm="ed25519" --in="$wrapkey" --out="$sigfile2" --password="password" diff -u "$sigfile1" "$sigfile2" } main() { put_yhwrapped_authkey put_yhwrapped_authkey_fail_cap put_yhwrapped_authkey_fail_domain put_yhwrapped_asymmetric_rsa put_yhwrapped_asymmetric_ecdsa put_yhwrapped_asymmetric_eddsa } main "$@" yubihsm-shell-2.7.3/src/tests/sig.out0000644000175000017500000000000015167357110016526 0ustar aveenaveenyubihsm-shell-2.7.3/src/cmdline.ggo0000644000175000017500000001713615167357110016204 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # option "action" a "Action to perform" values="benchmark", "blink-device", "create-otp-aead", "decrypt-aesccm", "decrypt-aescbc", "decrypt-aesecb", "decrypt-oaep", "decrypt-otp", "decrypt-pkcs1v15", "delete-object", "derive-ecdh", "encrypt-aesccm", "encrypt-aescbc", "encrypt-aesecb", "generate-asymmetric-key", "generate-csr", "generate-hmac-key", "generate-otp-aead-key", "generate-wrap-key", "generate-symmetric-key", "get-device-info", "get-logs", "get-object-info", "get-opaque", "get-option", "get-pseudo-random", "get-public-key", "get-storage-info", "get-template", "get-wrapped", "get-rsa-wrapped", "get-rsa-wrapped-key", "get-device-pubkey", "list-objects", "put-asymmetric-key", "put-authentication-key", "put-hmac-key", "put-opaque", "put-option", "put-otp-aead-key", "put-symmetric-key", "put-template", "put-wrap-key", "put-rsa-wrapkey", "put-public-wrapkey", "put-wrapped", "put-rsa-wrapped", "put-rsa-wrapped-key", "randomize-otp-aead", "reset", "set-log-index", "sign-attestation-certificate", "sign-ecdsa", "sign-eddsa", "sign-hmac", "sign-pkcs1v15", "sign-pss", "sign-ssh-certificate" enum optional multiple option "password" p "Authentication password" string optional option "authkey" - "Authentication key" short optional default="1" option "object-id" i "Object ID" short optional default="0" option "label" l "Object label" string optional default="" option "domains" d "Object domains" string optional default="1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16" option "capabilities" c "Capabilities for an object" string optional default="0" option "object-type" t "Object type" string optional default="any" option "ykhsmauth-label" y "Credential label on YubiKey (implicitly enables ykhsmauth)" string optional option "ykhsmauth-reader" r "Only use a matching YubiKey reader name" string optional default="" option "delegated" - "Delegated capabilities" string optional default="0" option "new-password" - "New authentication password" string optional option "algorithm" A "Operation algorithm" string optional default="any" option "oaep" - "OAEP algorithm. Used primarily with asymmetric wrap" string optional default="rsa-oaep-sha256" option "mgf1" - "MGF1 algorithm. Used primarily with asymmetric wrap" string optional default="mgf1-sha256" option "nonce" - "OTP nonce" int optional option "iv" - "An initialization vector as a hexadecimal string" string optional option "count" - "Number of bytes to request" int optional default="256" option "duration" - "Blink duration in seconds" int optional default="10" option "wrap-id" - "Wrap key ID" short optional option "include-seed" - "Include seed when exporting an ED25519 key under wrap" flag off option "template-id" - "Template ID" short optional option "attestation-id" - "Attestation ID" short 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 "with-compression" - "Compress a X509Certificate before importing it into the device or detect compressed certificates when listing objects" flag off option "subject" S "The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/" string optional option "in" - "Input data (filename)" string optional default="-" option "out" - "Output data (filename)" string optional default="-" option "informat" - "Input format" values="default","base64","binary","PEM","password","hex","ASCII" enum optional default="default" option "outformat" - "Input and output format" values="default","base64","binary","PEM","hex","ASCII" enum optional default="default" #option "enc-key" e "Encryption key to use" string optional default="404142434445464748494a4b4c4d4e4f" #option "mac-key" m "Mac key to use" string optional default="404142434445464748494a4b4c4d4e4f" option "config-file" f "Configuration file to read" string optional default="" option "connector" C "List of connectors to use" string optional multiple option "cacert" - "HTTPS cacert for connector" string optional option "cert" - "HTTPS client certificate to authenticate with" string optional option "key" - "HTTPS client certificate key" string optional option "proxy" - "Proxy server to use for connector" string optional option "noproxy" - "Comma separated list of hosts ignore proxy for" string optional option "verbose" v "Print more information" int optional default="0" option "pre-connect" P "Connect immediately in interactive mode" flag off option "device-pubkey" - "List of device public keys allowed for asymmetric authentication" string optional multiple yubihsm-shell-2.7.3/src/yubihsm-shell.h0000644000175000017500000000317715167357110017031 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YUBIHSM_SHELL_H #define YUBIHSM_SHELL_H #include #include #include #include #define UNUSED(x) (void) (x) typedef enum { fmt_nofmt, fmt_base64, fmt_binary, fmt_hex, fmt_PEM, fmt_password, fmt_ASCII } cmd_format; static const struct { const char *name; cmd_format format; } formats[] = { {"default", fmt_nofmt}, {"base64", fmt_base64}, {"binary", fmt_binary}, {"hex", fmt_hex}, {"PEM", fmt_PEM}, {"password", fmt_password}, {"ASCII", fmt_ASCII}, }; typedef struct { uint8_t **device_pubkey_list; char **connector_list; yh_connector *connector; yh_session *sessions[256]; ykhsmauth_state *state; FILE *out; char *cacert; char *cert; char *key; char *proxy; char *noproxy; } yubihsm_context; int actions_run(struct gengetopt_args_info *args_info); int do_put_key(uint8_t *enc_key, uint8_t *mac_key, uint16_t key_id, uint16_t domains, uint32_t capabilities, yh_session *ses); #ifdef _MSC_VER #pragma strict_gs_check(on) #endif #endif yubihsm-shell-2.7.3/src/README.adoc0000644000175000017500000000642415167357110015656 0ustar aveenaveen== YubiHSM Shell YubiHSM Shell is a tool to directly interface with a YubiHSM 2 device. For the most part it is a thin wrapper around `libyubihsm` exposing most of its functions directly to the user. YubiHSM Shell can be invoked in interactive mode and from the command line. Special (national) characters are supported on MacOS and Linux platforms. On Windows, they are supported in interactive mode and the same support can be activated through the OpenSSL environment variable `OPENSSL_WIN32_UTF8` for interactive password entry in non-interactive mode (i.e if password is not given on the command line). Such characters will be encoded according to current locale settings on MacOS/Linux (typically utf-8), and always as utf-8 on Windows. === Interactive Mode To invoke YubiHSM Shell in interactive mode simply run `yubihsm-shell` with no parameters. This mode supports tab-completion (not on Windows) and "classic" terminal shortcuts (`C-p`, `C-n`, `C-a`, `C-e`, etc.) In this mode, the default Connector URL is `http://127.0.01:12345`. If a different URL is needed, it can be specified with the `--connector` option. For example, to select direct USB run [source, bash] ---- yubihsm-shell --connector yhusb:// ---- Help can be obtained by running [source, bash] ---- yubihsm> help ---- to get a list of available commands and their syntax, or by running [source, bash] ---- yubihsm> help COMMAND ---- to get help on a specific command. Debug messages can be turned on by running [source, bash] ---- yubihsm> debug all ---- other levels of verbosity are available as well. Each command has its own default input and output format. Possible choices are `PEM`, `base64`, `binary`, `hex`, `password` and `default`. Those can be changed by running [source, bash] ---- yubihsm> set informat base64 ---- or [source, bash] ---- yubihsm> set outformat hex ---- Input and Output formats are a generic modifier and some values may not make sense in some cases. The default setting can be restored by using the `default` format. === Command-line Mode It is possible to run yubihsm-shell as a non-interactive command-line utility. To do so add the `--action` option with the desired command to execute. For example, to generate an RSA 2048 key with Label `Signature_Key`, Object ID `10` and Capabilities `sign-pss`, run [source, bash] ---- $ yubihsm-shell -p password -a generate-asymmetric -A rsa2048 -i 10 -c sign-pss -l Signature_Key ---- to sign a file called `message.dat` using the previously generated key, PSS with SHA256 as padding scheme and save the result to a file called `signature.dat` run [source, bash] ---- $ yubihsm-shell -p password -a sign-pss -i 10 -A rsa-pss-sha256 --in message.dat --out signature.dat --outformat binary ---- it is then possible to extract the public key by using [source, bash] ---- yubihsm-shell -p password -a get-public-key -i 10 --out key.pem --outformat PEM ---- and verify the signature with OpenSSL by running [source, bash] ---- $ openssl dgst -sha256 -binary message.dat > digest.dat $ openssl pkeyutl -verify -in digest.dat -sigfile signature.dat -pkeyopt rsa_padding_mode:pss -pubin -inkey key.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 ---- A detailed list of possible actions and parameters is available in the manpage or by running `yubihsm-shell --help`. yubihsm-shell-2.7.3/src/cmdline.c0000644000175000017500000023001615167357160015651 0ustar aveenaveen/* File autogenerated by gengetopt version 2.23 generated with the following command: gengetopt --conf-parser -i /home/runner/work/yubihsm-shell/yubihsm-shell/src/cmdline.ggo --output-dir /home/runner/work/yubihsm-shell/yubihsm-shell/src cmdline The developers of gengetopt consider the fixed text that goes in all gengetopt output files to be in the public domain: we make no copyright claims on it. */ /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifndef FIX_UNUSED #define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ #endif #include #include "cmdline.h" const char *gengetopt_args_info_purpose = ""; const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { " -h, --help Print help and exit", " -V, --version Print version and exit", " -a, --action=ENUM Action to perform (possible\n values=\"benchmark\", \"blink-device\",\n \"create-otp-aead\", \"decrypt-aesccm\",\n \"decrypt-aescbc\", \"decrypt-aesecb\",\n \"decrypt-oaep\", \"decrypt-otp\",\n \"decrypt-pkcs1v15\", \"delete-object\",\n \"derive-ecdh\", \"encrypt-aesccm\",\n \"encrypt-aescbc\", \"encrypt-aesecb\",\n \"generate-asymmetric-key\",\n \"generate-csr\", \"generate-hmac-key\",\n \"generate-otp-aead-key\",\n \"generate-wrap-key\",\n \"generate-symmetric-key\",\n \"get-device-info\", \"get-logs\",\n \"get-object-info\", \"get-opaque\",\n \"get-option\", \"get-pseudo-random\",\n \"get-public-key\", \"get-storage-info\",\n \"get-template\", \"get-wrapped\",\n \"get-rsa-wrapped\", \"get-rsa-wrapped-key\",\n \"get-device-pubkey\", \"list-objects\",\n \"put-asymmetric-key\",\n \"put-authentication-key\", \"put-hmac-key\",\n \"put-opaque\", \"put-option\",\n \"put-otp-aead-key\", \"put-symmetric-key\",\n \"put-template\", \"put-wrap-key\",\n \"put-rsa-wrapkey\", \"put-public-wrapkey\",\n \"put-wrapped\", \"put-rsa-wrapped\",\n \"put-rsa-wrapped-key\",\n \"randomize-otp-aead\", \"reset\",\n \"set-log-index\",\n \"sign-attestation-certificate\",\n \"sign-ecdsa\", \"sign-eddsa\",\n \"sign-hmac\", \"sign-pkcs1v15\",\n \"sign-pss\", \"sign-ssh-certificate\")", " -p, --password=STRING Authentication password", " --authkey=SHORT Authentication key (default=`1')", " -i, --object-id=SHORT Object ID (default=`0')", " -l, --label=STRING Object label (default=`')", " -d, --domains=STRING Object domains\n (default=`1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16')", " -c, --capabilities=STRING Capabilities for an object (default=`0')", " -t, --object-type=STRING Object type (default=`any')", " -y, --ykhsmauth-label=STRING Credential label on YubiKey (implicitly enables\n ykhsmauth)", " -r, --ykhsmauth-reader=STRING Only use a matching YubiKey reader name\n (default=`')", " --delegated=STRING Delegated capabilities (default=`0')", " --new-password=STRING New authentication password", " -A, --algorithm=STRING Operation algorithm (default=`any')", " --oaep=STRING OAEP algorithm. Used primarily with asymmetric\n wrap (default=`rsa-oaep-sha256')", " --mgf1=STRING MGF1 algorithm. Used primarily with asymmetric\n wrap (default=`mgf1-sha256')", " --nonce=INT OTP nonce", " --iv=STRING An initialization vector as a hexadecimal\n string", " --count=INT Number of bytes to request (default=`256')", " --duration=INT Blink duration in seconds (default=`10')", " --wrap-id=SHORT Wrap key ID", " --include-seed Include seed when exporting an ED25519 key\n under wrap (default=off)", " --template-id=SHORT Template ID", " --attestation-id=SHORT Attestation ID", " --log-index=INT Log index", " --opt-name=STRING Device option name", " --opt-value=STRING Device option value", " --with-compression Compress a X509Certificate before importing it\n into the device or detect compressed\n certificates when listing objects\n (default=off)", " -S, --subject=STRING The subject to use for certificate request. The\n subject must be written as:\n /CN=host.example.com/OU=test/O=example.com/", " --in=STRING Input data (filename) (default=`-')", " --out=STRING Output data (filename) (default=`-')", " --informat=ENUM Input format (possible values=\"default\",\n \"base64\", \"binary\", \"PEM\",\n \"password\", \"hex\", \"ASCII\"\n default=`default')", " --outformat=ENUM Input and output format (possible\n values=\"default\", \"base64\", \"binary\",\n \"PEM\", \"hex\", \"ASCII\"\n default=`default')", " -f, --config-file=STRING Configuration file to read (default=`')", " -C, --connector=STRING List of connectors to use", " --cacert=STRING HTTPS cacert for connector", " --cert=STRING HTTPS client certificate to authenticate with", " --key=STRING HTTPS client certificate key", " --proxy=STRING Proxy server to use for connector", " --noproxy=STRING Comma separated list of hosts ignore proxy for", " -v, --verbose=INT Print more information (default=`0')", " -P, --pre-connect Connect immediately in interactive mode\n (default=off)", " --device-pubkey=STRING List of device public keys allowed for\n asymmetric authentication", 0 }; typedef enum {ARG_NO , ARG_FLAG , ARG_STRING , ARG_INT , ARG_SHORT , ARG_ENUM } cmdline_parser_arg_type; static void clear_given (struct gengetopt_args_info *args_info); static void clear_args (struct gengetopt_args_info *args_info); static int cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error); static int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error); struct line_list { char * string_arg; struct line_list * next; }; static struct line_list *cmd_line_list = 0; static struct line_list *cmd_line_list_tmp = 0; static void free_cmd_list(void) { /* free the list of a previous call */ if (cmd_line_list) { while (cmd_line_list) { cmd_line_list_tmp = cmd_line_list; cmd_line_list = cmd_line_list->next; free (cmd_line_list_tmp->string_arg); free (cmd_line_list_tmp); } } } const char *cmdline_parser_action_values[] = {"benchmark", "blink-device", "create-otp-aead", "decrypt-aesccm", "decrypt-aescbc", "decrypt-aesecb", "decrypt-oaep", "decrypt-otp", "decrypt-pkcs1v15", "delete-object", "derive-ecdh", "encrypt-aesccm", "encrypt-aescbc", "encrypt-aesecb", "generate-asymmetric-key", "generate-csr", "generate-hmac-key", "generate-otp-aead-key", "generate-wrap-key", "generate-symmetric-key", "get-device-info", "get-logs", "get-object-info", "get-opaque", "get-option", "get-pseudo-random", "get-public-key", "get-storage-info", "get-template", "get-wrapped", "get-rsa-wrapped", "get-rsa-wrapped-key", "get-device-pubkey", "list-objects", "put-asymmetric-key", "put-authentication-key", "put-hmac-key", "put-opaque", "put-option", "put-otp-aead-key", "put-symmetric-key", "put-template", "put-wrap-key", "put-rsa-wrapkey", "put-public-wrapkey", "put-wrapped", "put-rsa-wrapped", "put-rsa-wrapped-key", "randomize-otp-aead", "reset", "set-log-index", "sign-attestation-certificate", "sign-ecdsa", "sign-eddsa", "sign-hmac", "sign-pkcs1v15", "sign-pss", "sign-ssh-certificate", 0}; /*< Possible values for action. */ const char *cmdline_parser_informat_values[] = {"default", "base64", "binary", "PEM", "password", "hex", "ASCII", 0}; /*< Possible values for informat. */ const char *cmdline_parser_outformat_values[] = {"default", "base64", "binary", "PEM", "hex", "ASCII", 0}; /*< Possible values for outformat. */ static char * gengetopt_strdup (const char *s); static void clear_given (struct gengetopt_args_info *args_info) { args_info->help_given = 0 ; args_info->version_given = 0 ; args_info->action_given = 0 ; args_info->password_given = 0 ; args_info->authkey_given = 0 ; args_info->object_id_given = 0 ; args_info->label_given = 0 ; args_info->domains_given = 0 ; args_info->capabilities_given = 0 ; args_info->object_type_given = 0 ; args_info->ykhsmauth_label_given = 0 ; args_info->ykhsmauth_reader_given = 0 ; args_info->delegated_given = 0 ; args_info->new_password_given = 0 ; args_info->algorithm_given = 0 ; args_info->oaep_given = 0 ; args_info->mgf1_given = 0 ; args_info->nonce_given = 0 ; args_info->iv_given = 0 ; args_info->count_given = 0 ; args_info->duration_given = 0 ; args_info->wrap_id_given = 0 ; args_info->include_seed_given = 0 ; args_info->template_id_given = 0 ; args_info->attestation_id_given = 0 ; args_info->log_index_given = 0 ; args_info->opt_name_given = 0 ; args_info->opt_value_given = 0 ; args_info->with_compression_given = 0 ; args_info->subject_given = 0 ; args_info->in_given = 0 ; args_info->out_given = 0 ; args_info->informat_given = 0 ; args_info->outformat_given = 0 ; args_info->config_file_given = 0 ; args_info->connector_given = 0 ; args_info->cacert_given = 0 ; args_info->cert_given = 0 ; args_info->key_given = 0 ; args_info->proxy_given = 0 ; args_info->noproxy_given = 0 ; args_info->verbose_given = 0 ; args_info->pre_connect_given = 0 ; args_info->device_pubkey_given = 0 ; } static void clear_args (struct gengetopt_args_info *args_info) { FIX_UNUSED (args_info); args_info->action_arg = NULL; args_info->action_orig = NULL; args_info->password_arg = NULL; args_info->password_orig = NULL; args_info->authkey_arg = 1; args_info->authkey_orig = NULL; args_info->object_id_arg = 0; args_info->object_id_orig = NULL; args_info->label_arg = gengetopt_strdup (""); args_info->label_orig = NULL; args_info->domains_arg = gengetopt_strdup ("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16"); args_info->domains_orig = NULL; args_info->capabilities_arg = gengetopt_strdup ("0"); args_info->capabilities_orig = NULL; args_info->object_type_arg = gengetopt_strdup ("any"); args_info->object_type_orig = NULL; args_info->ykhsmauth_label_arg = NULL; args_info->ykhsmauth_label_orig = NULL; args_info->ykhsmauth_reader_arg = gengetopt_strdup (""); args_info->ykhsmauth_reader_orig = NULL; args_info->delegated_arg = gengetopt_strdup ("0"); args_info->delegated_orig = NULL; args_info->new_password_arg = NULL; args_info->new_password_orig = NULL; args_info->algorithm_arg = gengetopt_strdup ("any"); args_info->algorithm_orig = NULL; args_info->oaep_arg = gengetopt_strdup ("rsa-oaep-sha256"); args_info->oaep_orig = NULL; args_info->mgf1_arg = gengetopt_strdup ("mgf1-sha256"); args_info->mgf1_orig = NULL; args_info->nonce_orig = NULL; args_info->iv_arg = NULL; args_info->iv_orig = NULL; args_info->count_arg = 256; args_info->count_orig = NULL; args_info->duration_arg = 10; args_info->duration_orig = NULL; args_info->wrap_id_orig = NULL; args_info->include_seed_flag = 0; args_info->template_id_orig = NULL; args_info->attestation_id_orig = NULL; args_info->log_index_orig = NULL; args_info->opt_name_arg = NULL; args_info->opt_name_orig = NULL; args_info->opt_value_arg = NULL; args_info->opt_value_orig = NULL; args_info->with_compression_flag = 0; args_info->subject_arg = NULL; args_info->subject_orig = NULL; args_info->in_arg = gengetopt_strdup ("-"); args_info->in_orig = NULL; args_info->out_arg = gengetopt_strdup ("-"); args_info->out_orig = NULL; args_info->informat_arg = informat_arg_default; args_info->informat_orig = NULL; args_info->outformat_arg = outformat_arg_default; args_info->outformat_orig = NULL; args_info->config_file_arg = gengetopt_strdup (""); args_info->config_file_orig = NULL; args_info->connector_arg = NULL; args_info->connector_orig = NULL; args_info->cacert_arg = NULL; args_info->cacert_orig = NULL; args_info->cert_arg = NULL; args_info->cert_orig = NULL; args_info->key_arg = NULL; args_info->key_orig = NULL; args_info->proxy_arg = NULL; args_info->proxy_orig = NULL; args_info->noproxy_arg = NULL; args_info->noproxy_orig = NULL; args_info->verbose_arg = 0; args_info->verbose_orig = NULL; args_info->pre_connect_flag = 0; args_info->device_pubkey_arg = NULL; args_info->device_pubkey_orig = NULL; } static void init_args_info(struct gengetopt_args_info *args_info) { args_info->help_help = gengetopt_args_info_help[0] ; args_info->version_help = gengetopt_args_info_help[1] ; args_info->action_help = gengetopt_args_info_help[2] ; args_info->action_min = 0; args_info->action_max = 0; args_info->password_help = gengetopt_args_info_help[3] ; args_info->authkey_help = gengetopt_args_info_help[4] ; args_info->object_id_help = gengetopt_args_info_help[5] ; args_info->label_help = gengetopt_args_info_help[6] ; args_info->domains_help = gengetopt_args_info_help[7] ; args_info->capabilities_help = gengetopt_args_info_help[8] ; args_info->object_type_help = gengetopt_args_info_help[9] ; args_info->ykhsmauth_label_help = gengetopt_args_info_help[10] ; args_info->ykhsmauth_reader_help = gengetopt_args_info_help[11] ; args_info->delegated_help = gengetopt_args_info_help[12] ; args_info->new_password_help = gengetopt_args_info_help[13] ; args_info->algorithm_help = gengetopt_args_info_help[14] ; args_info->oaep_help = gengetopt_args_info_help[15] ; args_info->mgf1_help = gengetopt_args_info_help[16] ; args_info->nonce_help = gengetopt_args_info_help[17] ; args_info->iv_help = gengetopt_args_info_help[18] ; args_info->count_help = gengetopt_args_info_help[19] ; args_info->duration_help = gengetopt_args_info_help[20] ; args_info->wrap_id_help = gengetopt_args_info_help[21] ; args_info->include_seed_help = gengetopt_args_info_help[22] ; args_info->template_id_help = gengetopt_args_info_help[23] ; args_info->attestation_id_help = gengetopt_args_info_help[24] ; args_info->log_index_help = gengetopt_args_info_help[25] ; args_info->opt_name_help = gengetopt_args_info_help[26] ; args_info->opt_value_help = gengetopt_args_info_help[27] ; args_info->with_compression_help = gengetopt_args_info_help[28] ; args_info->subject_help = gengetopt_args_info_help[29] ; args_info->in_help = gengetopt_args_info_help[30] ; args_info->out_help = gengetopt_args_info_help[31] ; args_info->informat_help = gengetopt_args_info_help[32] ; args_info->outformat_help = gengetopt_args_info_help[33] ; args_info->config_file_help = gengetopt_args_info_help[34] ; args_info->connector_help = gengetopt_args_info_help[35] ; args_info->connector_min = 0; args_info->connector_max = 0; args_info->cacert_help = gengetopt_args_info_help[36] ; args_info->cert_help = gengetopt_args_info_help[37] ; args_info->key_help = gengetopt_args_info_help[38] ; args_info->proxy_help = gengetopt_args_info_help[39] ; args_info->noproxy_help = gengetopt_args_info_help[40] ; args_info->verbose_help = gengetopt_args_info_help[41] ; args_info->pre_connect_help = gengetopt_args_info_help[42] ; args_info->device_pubkey_help = gengetopt_args_info_help[43] ; args_info->device_pubkey_min = 0; args_info->device_pubkey_max = 0; } void cmdline_parser_print_version (void) { printf ("%s %s\n", (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), CMDLINE_PARSER_VERSION); if (strlen(gengetopt_args_info_versiontext) > 0) printf("\n%s\n", gengetopt_args_info_versiontext); } static void print_help_common(void) { size_t len_purpose = strlen(gengetopt_args_info_purpose); size_t len_usage = strlen(gengetopt_args_info_usage); if (len_usage > 0) { printf("%s\n", gengetopt_args_info_usage); } if (len_purpose > 0) { printf("%s\n", gengetopt_args_info_purpose); } if (len_usage || len_purpose) { printf("\n"); } if (strlen(gengetopt_args_info_description) > 0) { printf("%s\n\n", gengetopt_args_info_description); } } void cmdline_parser_print_help (void) { int i = 0; print_help_common(); while (gengetopt_args_info_help[i]) printf("%s\n", gengetopt_args_info_help[i++]); } void cmdline_parser_init (struct gengetopt_args_info *args_info) { clear_given (args_info); clear_args (args_info); init_args_info (args_info); } void cmdline_parser_params_init(struct cmdline_parser_params *params) { if (params) { params->override = 0; params->initialize = 1; params->check_required = 1; params->check_ambiguity = 0; params->print_errors = 1; } } struct cmdline_parser_params * cmdline_parser_params_create(void) { struct cmdline_parser_params *params = (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); cmdline_parser_params_init(params); return params; } static void free_string_field (char **s) { if (*s) { free (*s); *s = 0; } } /** @brief generic value variable */ union generic_value { int int_arg; short short_arg; char *string_arg; const char *default_string_arg; }; /** @brief holds temporary values for multiple options */ struct generic_list { union generic_value arg; char *orig; struct generic_list *next; }; /** * @brief add a node at the head of the list */ static void add_node(struct generic_list **list) { struct generic_list *new_node = (struct generic_list *) malloc (sizeof (struct generic_list)); new_node->next = *list; *list = new_node; new_node->arg.string_arg = 0; new_node->orig = 0; } /** * The passed arg parameter is NOT set to 0 from this function */ static void free_multiple_field(unsigned int len, void *arg, char ***orig) { unsigned int i; if (arg) { for (i = 0; i < len; ++i) { free_string_field(&((*orig)[i])); } free (arg); free (*orig); *orig = 0; } } static void free_multiple_string_field(unsigned int len, char ***arg, char ***orig) { unsigned int i; if (*arg) { for (i = 0; i < len; ++i) { free_string_field(&((*arg)[i])); free_string_field(&((*orig)[i])); } free_string_field(&((*arg)[0])); /* free default string */ free (*arg); *arg = 0; free (*orig); *orig = 0; } } static void cmdline_parser_release (struct gengetopt_args_info *args_info) { free_multiple_field (args_info->action_given, (void *)(args_info->action_arg), &(args_info->action_orig)); args_info->action_arg = 0; free_string_field (&(args_info->password_arg)); free_string_field (&(args_info->password_orig)); free_string_field (&(args_info->authkey_orig)); free_string_field (&(args_info->object_id_orig)); free_string_field (&(args_info->label_arg)); free_string_field (&(args_info->label_orig)); free_string_field (&(args_info->domains_arg)); free_string_field (&(args_info->domains_orig)); free_string_field (&(args_info->capabilities_arg)); free_string_field (&(args_info->capabilities_orig)); free_string_field (&(args_info->object_type_arg)); free_string_field (&(args_info->object_type_orig)); free_string_field (&(args_info->ykhsmauth_label_arg)); free_string_field (&(args_info->ykhsmauth_label_orig)); free_string_field (&(args_info->ykhsmauth_reader_arg)); free_string_field (&(args_info->ykhsmauth_reader_orig)); free_string_field (&(args_info->delegated_arg)); free_string_field (&(args_info->delegated_orig)); free_string_field (&(args_info->new_password_arg)); free_string_field (&(args_info->new_password_orig)); free_string_field (&(args_info->algorithm_arg)); free_string_field (&(args_info->algorithm_orig)); free_string_field (&(args_info->oaep_arg)); free_string_field (&(args_info->oaep_orig)); free_string_field (&(args_info->mgf1_arg)); free_string_field (&(args_info->mgf1_orig)); free_string_field (&(args_info->nonce_orig)); free_string_field (&(args_info->iv_arg)); free_string_field (&(args_info->iv_orig)); free_string_field (&(args_info->count_orig)); free_string_field (&(args_info->duration_orig)); free_string_field (&(args_info->wrap_id_orig)); free_string_field (&(args_info->template_id_orig)); free_string_field (&(args_info->attestation_id_orig)); free_string_field (&(args_info->log_index_orig)); free_string_field (&(args_info->opt_name_arg)); free_string_field (&(args_info->opt_name_orig)); free_string_field (&(args_info->opt_value_arg)); free_string_field (&(args_info->opt_value_orig)); free_string_field (&(args_info->subject_arg)); free_string_field (&(args_info->subject_orig)); free_string_field (&(args_info->in_arg)); free_string_field (&(args_info->in_orig)); free_string_field (&(args_info->out_arg)); free_string_field (&(args_info->out_orig)); free_string_field (&(args_info->informat_orig)); free_string_field (&(args_info->outformat_orig)); free_string_field (&(args_info->config_file_arg)); free_string_field (&(args_info->config_file_orig)); free_multiple_string_field (args_info->connector_given, &(args_info->connector_arg), &(args_info->connector_orig)); free_string_field (&(args_info->cacert_arg)); free_string_field (&(args_info->cacert_orig)); free_string_field (&(args_info->cert_arg)); free_string_field (&(args_info->cert_orig)); free_string_field (&(args_info->key_arg)); free_string_field (&(args_info->key_orig)); free_string_field (&(args_info->proxy_arg)); free_string_field (&(args_info->proxy_orig)); free_string_field (&(args_info->noproxy_arg)); free_string_field (&(args_info->noproxy_orig)); free_string_field (&(args_info->verbose_orig)); free_multiple_string_field (args_info->device_pubkey_given, &(args_info->device_pubkey_arg), &(args_info->device_pubkey_orig)); clear_given (args_info); } /** * @param val the value to check * @param values the possible values * @return the index of the matched value: * -1 if no value matched, * -2 if more than one value has matched */ static int check_possible_values(const char *val, const char *values[]) { int i, found, last; size_t len; if (!val) /* otherwise strlen() crashes below */ return -1; /* -1 means no argument for the option */ found = last = 0; for (i = 0, len = strlen(val); values[i]; ++i) { if (strncmp(val, values[i], len) == 0) { ++found; last = i; if (strlen(values[i]) == len) return i; /* exact macth no need to check more */ } } if (found == 1) /* one match: OK */ return last; return (found ? -2 : -1); /* return many values or none matched */ } static void write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) { int found = -1; if (arg) { if (values) { found = check_possible_values(arg, values); } if (found >= 0) fprintf(outfile, "%s=\"%s\" # %s\n", opt, arg, values[found]); else fprintf(outfile, "%s=\"%s\"\n", opt, arg); } else { fprintf(outfile, "%s\n", opt); } } static void write_multiple_into_file(FILE *outfile, int len, const char *opt, char **arg, const char *values[]) { int i; for (i = 0; i < len; ++i) write_into_file(outfile, opt, (arg ? arg[i] : 0), values); } int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) { int i = 0; if (!outfile) { fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); return EXIT_FAILURE; } if (args_info->help_given) write_into_file(outfile, "help", 0, 0 ); if (args_info->version_given) write_into_file(outfile, "version", 0, 0 ); write_multiple_into_file(outfile, args_info->action_given, "action", args_info->action_orig, cmdline_parser_action_values); if (args_info->password_given) write_into_file(outfile, "password", args_info->password_orig, 0); if (args_info->authkey_given) write_into_file(outfile, "authkey", args_info->authkey_orig, 0); if (args_info->object_id_given) write_into_file(outfile, "object-id", args_info->object_id_orig, 0); if (args_info->label_given) write_into_file(outfile, "label", args_info->label_orig, 0); if (args_info->domains_given) write_into_file(outfile, "domains", args_info->domains_orig, 0); if (args_info->capabilities_given) write_into_file(outfile, "capabilities", args_info->capabilities_orig, 0); if (args_info->object_type_given) write_into_file(outfile, "object-type", args_info->object_type_orig, 0); if (args_info->ykhsmauth_label_given) write_into_file(outfile, "ykhsmauth-label", args_info->ykhsmauth_label_orig, 0); if (args_info->ykhsmauth_reader_given) write_into_file(outfile, "ykhsmauth-reader", args_info->ykhsmauth_reader_orig, 0); if (args_info->delegated_given) write_into_file(outfile, "delegated", args_info->delegated_orig, 0); if (args_info->new_password_given) write_into_file(outfile, "new-password", args_info->new_password_orig, 0); if (args_info->algorithm_given) write_into_file(outfile, "algorithm", args_info->algorithm_orig, 0); if (args_info->oaep_given) write_into_file(outfile, "oaep", args_info->oaep_orig, 0); if (args_info->mgf1_given) write_into_file(outfile, "mgf1", args_info->mgf1_orig, 0); if (args_info->nonce_given) write_into_file(outfile, "nonce", args_info->nonce_orig, 0); if (args_info->iv_given) write_into_file(outfile, "iv", args_info->iv_orig, 0); if (args_info->count_given) write_into_file(outfile, "count", args_info->count_orig, 0); if (args_info->duration_given) write_into_file(outfile, "duration", args_info->duration_orig, 0); if (args_info->wrap_id_given) write_into_file(outfile, "wrap-id", args_info->wrap_id_orig, 0); if (args_info->include_seed_given) write_into_file(outfile, "include-seed", 0, 0 ); if (args_info->template_id_given) write_into_file(outfile, "template-id", args_info->template_id_orig, 0); if (args_info->attestation_id_given) write_into_file(outfile, "attestation-id", args_info->attestation_id_orig, 0); if (args_info->log_index_given) write_into_file(outfile, "log-index", args_info->log_index_orig, 0); if (args_info->opt_name_given) write_into_file(outfile, "opt-name", args_info->opt_name_orig, 0); if (args_info->opt_value_given) write_into_file(outfile, "opt-value", args_info->opt_value_orig, 0); if (args_info->with_compression_given) write_into_file(outfile, "with-compression", 0, 0 ); if (args_info->subject_given) write_into_file(outfile, "subject", args_info->subject_orig, 0); if (args_info->in_given) write_into_file(outfile, "in", args_info->in_orig, 0); if (args_info->out_given) write_into_file(outfile, "out", args_info->out_orig, 0); if (args_info->informat_given) write_into_file(outfile, "informat", args_info->informat_orig, cmdline_parser_informat_values); if (args_info->outformat_given) write_into_file(outfile, "outformat", args_info->outformat_orig, cmdline_parser_outformat_values); if (args_info->config_file_given) write_into_file(outfile, "config-file", args_info->config_file_orig, 0); write_multiple_into_file(outfile, args_info->connector_given, "connector", args_info->connector_orig, 0); if (args_info->cacert_given) write_into_file(outfile, "cacert", args_info->cacert_orig, 0); if (args_info->cert_given) write_into_file(outfile, "cert", args_info->cert_orig, 0); if (args_info->key_given) write_into_file(outfile, "key", args_info->key_orig, 0); if (args_info->proxy_given) write_into_file(outfile, "proxy", args_info->proxy_orig, 0); if (args_info->noproxy_given) write_into_file(outfile, "noproxy", args_info->noproxy_orig, 0); if (args_info->verbose_given) write_into_file(outfile, "verbose", args_info->verbose_orig, 0); if (args_info->pre_connect_given) write_into_file(outfile, "pre-connect", 0, 0 ); write_multiple_into_file(outfile, args_info->device_pubkey_given, "device-pubkey", args_info->device_pubkey_orig, 0); i = EXIT_SUCCESS; return i; } int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) { FILE *outfile; int i = 0; outfile = fopen(filename, "w"); if (!outfile) { fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); return EXIT_FAILURE; } i = cmdline_parser_dump(outfile, args_info); fclose (outfile); return i; } void cmdline_parser_free (struct gengetopt_args_info *args_info) { cmdline_parser_release (args_info); } /** @brief replacement of strdup, which is not standard */ char * gengetopt_strdup (const char *s) { char *result = 0; if (!s) return result; result = (char*)malloc(strlen(s) + 1); if (result == (char*)0) return (char*)0; strcpy(result, s); return result; } static char * get_multiple_arg_token(const char *arg) { const char *tok; char *ret; size_t len, num_of_escape, i, j; if (!arg) return 0; tok = strchr (arg, ','); num_of_escape = 0; /* make sure it is not escaped */ while (tok) { if (*(tok-1) == '\\') { /* find the next one */ tok = strchr (tok+1, ','); ++num_of_escape; } else break; } if (tok) len = (size_t)(tok - arg + 1); else len = strlen (arg) + 1; len -= num_of_escape; ret = (char *) malloc (len); i = 0; j = 0; while (arg[i] && (j < len-1)) { if (arg[i] == '\\' && arg[ i + 1 ] && arg[ i + 1 ] == ',') ++i; ret[j++] = arg[i++]; } ret[len-1] = '\0'; return ret; } static const char * get_multiple_arg_token_next(const char *arg) { const char *tok; if (!arg) return 0; tok = strchr (arg, ','); /* make sure it is not escaped */ while (tok) { if (*(tok-1) == '\\') { /* find the next one */ tok = strchr (tok+1, ','); } else break; } if (! tok || strlen(tok) == 1) return 0; return tok+1; } static int check_multiple_option_occurrences(const char *prog_name, unsigned int option_given, unsigned int min, unsigned int max, const char *option_desc); int check_multiple_option_occurrences(const char *prog_name, unsigned int option_given, unsigned int min, unsigned int max, const char *option_desc) { int error_occurred = 0; if (option_given && (min > 0 || max > 0)) { if (min > 0 && max > 0) { if (min == max) { /* specific occurrences */ if (option_given != (unsigned int) min) { fprintf (stderr, "%s: %s option occurrences must be %d\n", prog_name, option_desc, min); error_occurred = 1; } } else if (option_given < (unsigned int) min || option_given > (unsigned int) max) { /* range occurrences */ fprintf (stderr, "%s: %s option occurrences must be between %d and %d\n", prog_name, option_desc, min, max); error_occurred = 1; } } else if (min > 0) { /* at least check */ if (option_given < min) { fprintf (stderr, "%s: %s option occurrences must be at least %d\n", prog_name, option_desc, min); error_occurred = 1; } } else if (max > 0) { /* at most check */ if (option_given > max) { fprintf (stderr, "%s: %s option occurrences must be at most %d\n", prog_name, option_desc, max); error_occurred = 1; } } } return error_occurred; } int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) { return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); } int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params) { int result; result = cmdline_parser_internal (argc, argv, args_info, params, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) { int result; struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) { int result = EXIT_SUCCESS; if (cmdline_parser_required2(args_info, prog_name, 0) > 0) result = EXIT_FAILURE; if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error) { int error_occurred = 0; FIX_UNUSED (additional_error); /* checks for required options */ if (check_multiple_option_occurrences(prog_name, args_info->action_given, args_info->action_min, args_info->action_max, "'--action' ('-a')")) error_occurred = 1; if (check_multiple_option_occurrences(prog_name, args_info->connector_given, args_info->connector_min, args_info->connector_max, "'--connector' ('-C')")) error_occurred = 1; if (check_multiple_option_occurrences(prog_name, args_info->device_pubkey_given, args_info->device_pubkey_min, args_info->device_pubkey_max, "'--device-pubkey'")) error_occurred = 1; /* checks for dependences among options */ return error_occurred; } static char *package_name = 0; /** * @brief updates an option * @param field the generic pointer to the field to update * @param orig_field the pointer to the orig field * @param field_given the pointer to the number of occurrence of this option * @param prev_given the pointer to the number of occurrence already seen * @param value the argument for this option (if null no arg was specified) * @param possible_values the possible values for this option (if specified) * @param default_value the default value (in case the option only accepts fixed values) * @param arg_type the type of this option * @param check_ambiguity @see cmdline_parser_params.check_ambiguity * @param override @see cmdline_parser_params.override * @param no_free whether to free a possible previous value * @param multiple_option whether this is a multiple option * @param long_opt the corresponding long option * @param short_opt the corresponding short option (or '-' if none) * @param additional_error possible further error specification */ static int update_arg(void *field, char **orig_field, unsigned int *field_given, unsigned int *prev_given, char *value, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, int check_ambiguity, int override, int no_free, int multiple_option, const char *long_opt, char short_opt, const char *additional_error) { char *stop_char = 0; const char *val = value; int found; char **string_field; FIX_UNUSED (field); stop_char = 0; found = 0; if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) { if (short_opt != '-') fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", package_name, long_opt, short_opt, (additional_error ? additional_error : "")); else fprintf (stderr, "%s: `--%s' option given more than once%s\n", package_name, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } if (possible_values && (found = check_possible_values((value ? value : default_value), possible_values)) < 0) { if (short_opt != '-') fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s' (`-%c')%s\n", package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt, short_opt, (additional_error ? additional_error : "")); else fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s'%s\n", package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } if (field_given && *field_given && ! override) return 0; if (prev_given) (*prev_given)++; if (field_given) (*field_given)++; if (possible_values) val = possible_values[found]; switch(arg_type) { case ARG_FLAG: *((int *)field) = !*((int *)field); break; case ARG_INT: if (val) *((int *)field) = strtol (val, &stop_char, 0); break; case ARG_SHORT: if (val) *((short *)field) = (short)strtol (val, &stop_char, 0); break; case ARG_ENUM: if (val) *((int *)field) = found; break; case ARG_STRING: if (val) { string_field = (char **)field; if (!no_free && *string_field) free (*string_field); /* free previous string */ *string_field = gengetopt_strdup (val); } break; default: break; }; /* check numeric conversion */ switch(arg_type) { case ARG_INT: case ARG_SHORT: if (val && !(stop_char && *stop_char == '\0')) { fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val); return 1; /* failure */ } break; default: ; }; /* store the original value */ switch(arg_type) { case ARG_NO: case ARG_FLAG: break; default: if (value && orig_field) { if (no_free) { *orig_field = value; } else { if (*orig_field) free (*orig_field); /* free previous string */ *orig_field = gengetopt_strdup (value); } } }; return 0; /* OK */ } /** * @brief store information about a multiple option in a temporary list * @param list where to (temporarily) store multiple options */ static int update_multiple_arg_temp(struct generic_list **list, unsigned int *prev_given, const char *val, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, const char *long_opt, char short_opt, const char *additional_error) { /* store single arguments */ char *multi_token; const char *multi_next; if (arg_type == ARG_NO) { (*prev_given)++; return 0; /* OK */ } multi_token = get_multiple_arg_token(val); multi_next = get_multiple_arg_token_next (val); while (1) { add_node (list); if (update_arg((void *)&((*list)->arg), &((*list)->orig), 0, prev_given, multi_token, possible_values, default_value, arg_type, 0, 1, 1, 1, long_opt, short_opt, additional_error)) { if (multi_token) free(multi_token); return 1; /* failure */ } if (multi_next) { multi_token = get_multiple_arg_token(multi_next); multi_next = get_multiple_arg_token_next (multi_next); } else break; } return 0; /* OK */ } /** * @brief free the passed list (including possible string argument) */ static void free_list(struct generic_list *list, short string_arg) { if (list) { struct generic_list *tmp; while (list) { tmp = list; if (string_arg && list->arg.string_arg) free (list->arg.string_arg); if (list->orig) free (list->orig); list = list->next; free (tmp); } } } /** * @brief updates a multiple option starting from the passed list */ static void update_multiple_arg(void *field, char ***orig_field, unsigned int field_given, unsigned int prev_given, union generic_value *default_value, cmdline_parser_arg_type arg_type, struct generic_list *list) { int i; struct generic_list *tmp; if (prev_given && list) { *orig_field = (char **) realloc (*orig_field, (field_given + prev_given) * sizeof (char *)); switch(arg_type) { case ARG_INT: case ARG_ENUM: *((int **)field) = (int *)realloc (*((int **)field), (field_given + prev_given) * sizeof (int)); break; case ARG_SHORT: *((short **)field) = (short *)realloc (*((short **)field), (field_given + prev_given) * sizeof (short)); break; case ARG_STRING: *((char ***)field) = (char **)realloc (*((char ***)field), (field_given + prev_given) * sizeof (char *)); break; default: break; }; for (i = (prev_given - 1); i >= 0; --i) { tmp = list; switch(arg_type) { case ARG_INT: (*((int **)field))[i + field_given] = tmp->arg.int_arg; break; case ARG_SHORT: (*((short **)field))[i + field_given] = tmp->arg.short_arg; break; case ARG_ENUM: (*((int **)field))[i + field_given] = tmp->arg.int_arg; break; case ARG_STRING: (*((char ***)field))[i + field_given] = tmp->arg.string_arg; break; default: break; } (*orig_field) [i + field_given] = list->orig; list = list->next; free (tmp); } } else { /* set the default value */ if (default_value && ! field_given) { switch(arg_type) { case ARG_INT: case ARG_ENUM: if (! *((int **)field)) { *((int **)field) = (int *)malloc (sizeof (int)); (*((int **)field))[0] = default_value->int_arg; } break; case ARG_SHORT: if (! *((short **)field)) { *((short **)field) = (short *)malloc (sizeof (short)); (*((short **)field))[0] = default_value->short_arg; } break; case ARG_STRING: if (! *((char ***)field)) { *((char ***)field) = (char **)malloc (sizeof (char *)); (*((char ***)field))[0] = gengetopt_strdup(default_value->string_arg); } break; default: break; } if (!(*orig_field)) { *orig_field = (char **) malloc (sizeof (char *)); (*orig_field)[0] = 0; } } } } int cmdline_parser_internal ( int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error) { int c; /* Character of the parsed option. */ struct generic_list * action_list = NULL; struct generic_list * connector_list = NULL; struct generic_list * device_pubkey_list = NULL; int error_occurred = 0; struct gengetopt_args_info local_args_info; int override; int initialize; int check_required; int check_ambiguity; package_name = argv[0]; /* TODO: Why is this here? It is not used anywhere. */ override = params->override; FIX_UNUSED(override); initialize = params->initialize; check_required = params->check_required; /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); cmdline_parser_init (&local_args_info); optarg = 0; optind = 0; opterr = params->print_errors; optopt = '?'; while (1) { int option_index = 0; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, { "action", 1, NULL, 'a' }, { "password", 1, NULL, 'p' }, { "authkey", 1, NULL, 0 }, { "object-id", 1, NULL, 'i' }, { "label", 1, NULL, 'l' }, { "domains", 1, NULL, 'd' }, { "capabilities", 1, NULL, 'c' }, { "object-type", 1, NULL, 't' }, { "ykhsmauth-label", 1, NULL, 'y' }, { "ykhsmauth-reader", 1, NULL, 'r' }, { "delegated", 1, NULL, 0 }, { "new-password", 1, NULL, 0 }, { "algorithm", 1, NULL, 'A' }, { "oaep", 1, NULL, 0 }, { "mgf1", 1, NULL, 0 }, { "nonce", 1, NULL, 0 }, { "iv", 1, NULL, 0 }, { "count", 1, NULL, 0 }, { "duration", 1, NULL, 0 }, { "wrap-id", 1, NULL, 0 }, { "include-seed", 0, NULL, 0 }, { "template-id", 1, NULL, 0 }, { "attestation-id", 1, NULL, 0 }, { "log-index", 1, NULL, 0 }, { "opt-name", 1, NULL, 0 }, { "opt-value", 1, NULL, 0 }, { "with-compression", 0, NULL, 0 }, { "subject", 1, NULL, 'S' }, { "in", 1, NULL, 0 }, { "out", 1, NULL, 0 }, { "informat", 1, NULL, 0 }, { "outformat", 1, NULL, 0 }, { "config-file", 1, NULL, 'f' }, { "connector", 1, NULL, 'C' }, { "cacert", 1, NULL, 0 }, { "cert", 1, NULL, 0 }, { "key", 1, NULL, 0 }, { "proxy", 1, NULL, 0 }, { "noproxy", 1, NULL, 0 }, { "verbose", 1, NULL, 'v' }, { "pre-connect", 0, NULL, 'P' }, { "device-pubkey", 1, NULL, 0 }, { 0, 0, 0, 0 } }; c = getopt_long (argc, argv, "hVa:p:i:l:d:c:t:y:r:A:S:f:C:v:P", long_options, &option_index); if (c == -1) break; /* Exit from `while (1)' loop. */ switch (c) { case 'h': /* Print help and exit. */ cmdline_parser_print_help (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'V': /* Print version and exit. */ cmdline_parser_print_version (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'a': /* Action to perform. */ if (update_multiple_arg_temp(&action_list, &(local_args_info.action_given), optarg, cmdline_parser_action_values, 0, ARG_ENUM, "action", 'a', additional_error)) goto failure; break; case 'p': /* Authentication password. */ if (update_arg( (void *)&(args_info->password_arg), &(args_info->password_orig), &(args_info->password_given), &(local_args_info.password_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "password", 'p', additional_error)) goto failure; break; case 'i': /* Object ID. */ if (update_arg( (void *)&(args_info->object_id_arg), &(args_info->object_id_orig), &(args_info->object_id_given), &(local_args_info.object_id_given), optarg, 0, "0", ARG_SHORT, check_ambiguity, override, 0, 0, "object-id", 'i', additional_error)) goto failure; break; case 'l': /* Object label. */ if (update_arg( (void *)&(args_info->label_arg), &(args_info->label_orig), &(args_info->label_given), &(local_args_info.label_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "label", 'l', additional_error)) goto failure; break; case 'd': /* Object domains. */ if (update_arg( (void *)&(args_info->domains_arg), &(args_info->domains_orig), &(args_info->domains_given), &(local_args_info.domains_given), optarg, 0, "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16", ARG_STRING, check_ambiguity, override, 0, 0, "domains", 'd', additional_error)) goto failure; break; case 'c': /* Capabilities for an object. */ if (update_arg( (void *)&(args_info->capabilities_arg), &(args_info->capabilities_orig), &(args_info->capabilities_given), &(local_args_info.capabilities_given), optarg, 0, "0", ARG_STRING, check_ambiguity, override, 0, 0, "capabilities", 'c', additional_error)) goto failure; break; case 't': /* Object type. */ if (update_arg( (void *)&(args_info->object_type_arg), &(args_info->object_type_orig), &(args_info->object_type_given), &(local_args_info.object_type_given), optarg, 0, "any", ARG_STRING, check_ambiguity, override, 0, 0, "object-type", 't', additional_error)) goto failure; break; case 'y': /* Credential label on YubiKey (implicitly enables ykhsmauth). */ if (update_arg( (void *)&(args_info->ykhsmauth_label_arg), &(args_info->ykhsmauth_label_orig), &(args_info->ykhsmauth_label_given), &(local_args_info.ykhsmauth_label_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "ykhsmauth-label", 'y', additional_error)) goto failure; break; case 'r': /* Only use a matching YubiKey reader name. */ if (update_arg( (void *)&(args_info->ykhsmauth_reader_arg), &(args_info->ykhsmauth_reader_orig), &(args_info->ykhsmauth_reader_given), &(local_args_info.ykhsmauth_reader_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "ykhsmauth-reader", 'r', additional_error)) goto failure; break; case 'A': /* Operation algorithm. */ if (update_arg( (void *)&(args_info->algorithm_arg), &(args_info->algorithm_orig), &(args_info->algorithm_given), &(local_args_info.algorithm_given), optarg, 0, "any", ARG_STRING, check_ambiguity, override, 0, 0, "algorithm", 'A', additional_error)) goto failure; break; case 'S': /* The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/. */ if (update_arg( (void *)&(args_info->subject_arg), &(args_info->subject_orig), &(args_info->subject_given), &(local_args_info.subject_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "subject", 'S', additional_error)) goto failure; break; case 'f': /* Configuration file to read. */ if (update_arg( (void *)&(args_info->config_file_arg), &(args_info->config_file_orig), &(args_info->config_file_given), &(local_args_info.config_file_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "config-file", 'f', additional_error)) goto failure; break; case 'C': /* List of connectors to use. */ if (update_multiple_arg_temp(&connector_list, &(local_args_info.connector_given), optarg, 0, 0, ARG_STRING, "connector", 'C', additional_error)) goto failure; break; case 'v': /* Print more information. */ if (update_arg( (void *)&(args_info->verbose_arg), &(args_info->verbose_orig), &(args_info->verbose_given), &(local_args_info.verbose_given), optarg, 0, "0", ARG_INT, check_ambiguity, override, 0, 0, "verbose", 'v', additional_error)) goto failure; break; case 'P': /* Connect immediately in interactive mode. */ if (update_arg((void *)&(args_info->pre_connect_flag), 0, &(args_info->pre_connect_given), &(local_args_info.pre_connect_given), optarg, 0, 0, ARG_FLAG, check_ambiguity, override, 1, 0, "pre-connect", 'P', additional_error)) goto failure; break; case 0: /* Long option with no short option */ /* Authentication key. */ if (strcmp (long_options[option_index].name, "authkey") == 0) { if (update_arg( (void *)&(args_info->authkey_arg), &(args_info->authkey_orig), &(args_info->authkey_given), &(local_args_info.authkey_given), optarg, 0, "1", ARG_SHORT, check_ambiguity, override, 0, 0, "authkey", '-', additional_error)) goto failure; } /* Delegated capabilities. */ else if (strcmp (long_options[option_index].name, "delegated") == 0) { if (update_arg( (void *)&(args_info->delegated_arg), &(args_info->delegated_orig), &(args_info->delegated_given), &(local_args_info.delegated_given), optarg, 0, "0", ARG_STRING, check_ambiguity, override, 0, 0, "delegated", '-', additional_error)) goto failure; } /* New authentication password. */ else if (strcmp (long_options[option_index].name, "new-password") == 0) { if (update_arg( (void *)&(args_info->new_password_arg), &(args_info->new_password_orig), &(args_info->new_password_given), &(local_args_info.new_password_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "new-password", '-', additional_error)) goto failure; } /* OAEP algorithm. Used primarily with asymmetric wrap. */ else if (strcmp (long_options[option_index].name, "oaep") == 0) { if (update_arg( (void *)&(args_info->oaep_arg), &(args_info->oaep_orig), &(args_info->oaep_given), &(local_args_info.oaep_given), optarg, 0, "rsa-oaep-sha256", ARG_STRING, check_ambiguity, override, 0, 0, "oaep", '-', additional_error)) goto failure; } /* MGF1 algorithm. Used primarily with asymmetric wrap. */ else if (strcmp (long_options[option_index].name, "mgf1") == 0) { if (update_arg( (void *)&(args_info->mgf1_arg), &(args_info->mgf1_orig), &(args_info->mgf1_given), &(local_args_info.mgf1_given), optarg, 0, "mgf1-sha256", ARG_STRING, check_ambiguity, override, 0, 0, "mgf1", '-', additional_error)) goto failure; } /* OTP nonce. */ else if (strcmp (long_options[option_index].name, "nonce") == 0) { if (update_arg( (void *)&(args_info->nonce_arg), &(args_info->nonce_orig), &(args_info->nonce_given), &(local_args_info.nonce_given), optarg, 0, 0, ARG_INT, check_ambiguity, override, 0, 0, "nonce", '-', additional_error)) goto failure; } /* An initialization vector as a hexadecimal string. */ else if (strcmp (long_options[option_index].name, "iv") == 0) { if (update_arg( (void *)&(args_info->iv_arg), &(args_info->iv_orig), &(args_info->iv_given), &(local_args_info.iv_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "iv", '-', additional_error)) goto failure; } /* Number of bytes to request. */ else if (strcmp (long_options[option_index].name, "count") == 0) { if (update_arg( (void *)&(args_info->count_arg), &(args_info->count_orig), &(args_info->count_given), &(local_args_info.count_given), optarg, 0, "256", ARG_INT, check_ambiguity, override, 0, 0, "count", '-', additional_error)) goto failure; } /* Blink duration in seconds. */ else if (strcmp (long_options[option_index].name, "duration") == 0) { if (update_arg( (void *)&(args_info->duration_arg), &(args_info->duration_orig), &(args_info->duration_given), &(local_args_info.duration_given), optarg, 0, "10", ARG_INT, check_ambiguity, override, 0, 0, "duration", '-', additional_error)) goto failure; } /* Wrap key ID. */ else if (strcmp (long_options[option_index].name, "wrap-id") == 0) { if (update_arg( (void *)&(args_info->wrap_id_arg), &(args_info->wrap_id_orig), &(args_info->wrap_id_given), &(local_args_info.wrap_id_given), optarg, 0, 0, ARG_SHORT, check_ambiguity, override, 0, 0, "wrap-id", '-', additional_error)) goto failure; } /* Include seed when exporting an ED25519 key under wrap. */ else if (strcmp (long_options[option_index].name, "include-seed") == 0) { if (update_arg((void *)&(args_info->include_seed_flag), 0, &(args_info->include_seed_given), &(local_args_info.include_seed_given), optarg, 0, 0, ARG_FLAG, check_ambiguity, override, 1, 0, "include-seed", '-', additional_error)) goto failure; } /* Template ID. */ else if (strcmp (long_options[option_index].name, "template-id") == 0) { if (update_arg( (void *)&(args_info->template_id_arg), &(args_info->template_id_orig), &(args_info->template_id_given), &(local_args_info.template_id_given), optarg, 0, 0, ARG_SHORT, check_ambiguity, override, 0, 0, "template-id", '-', additional_error)) goto failure; } /* Attestation ID. */ else if (strcmp (long_options[option_index].name, "attestation-id") == 0) { if (update_arg( (void *)&(args_info->attestation_id_arg), &(args_info->attestation_id_orig), &(args_info->attestation_id_given), &(local_args_info.attestation_id_given), optarg, 0, 0, ARG_SHORT, check_ambiguity, override, 0, 0, "attestation-id", '-', additional_error)) goto failure; } /* Log index. */ else if (strcmp (long_options[option_index].name, "log-index") == 0) { if (update_arg( (void *)&(args_info->log_index_arg), &(args_info->log_index_orig), &(args_info->log_index_given), &(local_args_info.log_index_given), optarg, 0, 0, ARG_INT, check_ambiguity, override, 0, 0, "log-index", '-', additional_error)) goto failure; } /* Device option name. */ else if (strcmp (long_options[option_index].name, "opt-name") == 0) { if (update_arg( (void *)&(args_info->opt_name_arg), &(args_info->opt_name_orig), &(args_info->opt_name_given), &(local_args_info.opt_name_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "opt-name", '-', additional_error)) goto failure; } /* Device option value. */ else if (strcmp (long_options[option_index].name, "opt-value") == 0) { if (update_arg( (void *)&(args_info->opt_value_arg), &(args_info->opt_value_orig), &(args_info->opt_value_given), &(local_args_info.opt_value_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "opt-value", '-', additional_error)) goto failure; } /* Compress a X509Certificate before importing it into the device or detect compressed certificates when listing objects. */ else if (strcmp (long_options[option_index].name, "with-compression") == 0) { if (update_arg((void *)&(args_info->with_compression_flag), 0, &(args_info->with_compression_given), &(local_args_info.with_compression_given), optarg, 0, 0, ARG_FLAG, check_ambiguity, override, 1, 0, "with-compression", '-', additional_error)) goto failure; } /* Input data (filename). */ else if (strcmp (long_options[option_index].name, "in") == 0) { if (update_arg( (void *)&(args_info->in_arg), &(args_info->in_orig), &(args_info->in_given), &(local_args_info.in_given), optarg, 0, "-", ARG_STRING, check_ambiguity, override, 0, 0, "in", '-', additional_error)) goto failure; } /* Output data (filename). */ else if (strcmp (long_options[option_index].name, "out") == 0) { if (update_arg( (void *)&(args_info->out_arg), &(args_info->out_orig), &(args_info->out_given), &(local_args_info.out_given), optarg, 0, "-", ARG_STRING, check_ambiguity, override, 0, 0, "out", '-', additional_error)) goto failure; } /* Input format. */ else if (strcmp (long_options[option_index].name, "informat") == 0) { if (update_arg( (void *)&(args_info->informat_arg), &(args_info->informat_orig), &(args_info->informat_given), &(local_args_info.informat_given), optarg, cmdline_parser_informat_values, "default", ARG_ENUM, check_ambiguity, override, 0, 0, "informat", '-', additional_error)) goto failure; } /* Input and output format. */ else if (strcmp (long_options[option_index].name, "outformat") == 0) { if (update_arg( (void *)&(args_info->outformat_arg), &(args_info->outformat_orig), &(args_info->outformat_given), &(local_args_info.outformat_given), optarg, cmdline_parser_outformat_values, "default", ARG_ENUM, check_ambiguity, override, 0, 0, "outformat", '-', additional_error)) goto failure; } /* HTTPS cacert for connector. */ else if (strcmp (long_options[option_index].name, "cacert") == 0) { if (update_arg( (void *)&(args_info->cacert_arg), &(args_info->cacert_orig), &(args_info->cacert_given), &(local_args_info.cacert_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "cacert", '-', additional_error)) goto failure; } /* HTTPS client certificate to authenticate with. */ else if (strcmp (long_options[option_index].name, "cert") == 0) { if (update_arg( (void *)&(args_info->cert_arg), &(args_info->cert_orig), &(args_info->cert_given), &(local_args_info.cert_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "cert", '-', additional_error)) goto failure; } /* HTTPS client certificate key. */ else if (strcmp (long_options[option_index].name, "key") == 0) { if (update_arg( (void *)&(args_info->key_arg), &(args_info->key_orig), &(args_info->key_given), &(local_args_info.key_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "key", '-', additional_error)) goto failure; } /* Proxy server to use for connector. */ else if (strcmp (long_options[option_index].name, "proxy") == 0) { if (update_arg( (void *)&(args_info->proxy_arg), &(args_info->proxy_orig), &(args_info->proxy_given), &(local_args_info.proxy_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "proxy", '-', additional_error)) goto failure; } /* Comma separated list of hosts ignore proxy for. */ else if (strcmp (long_options[option_index].name, "noproxy") == 0) { if (update_arg( (void *)&(args_info->noproxy_arg), &(args_info->noproxy_orig), &(args_info->noproxy_given), &(local_args_info.noproxy_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "noproxy", '-', additional_error)) goto failure; } /* List of device public keys allowed for asymmetric authentication. */ else if (strcmp (long_options[option_index].name, "device-pubkey") == 0) { if (update_multiple_arg_temp(&device_pubkey_list, &(local_args_info.device_pubkey_given), optarg, 0, 0, ARG_STRING, "device-pubkey", '-', additional_error)) goto failure; } break; case '?': /* Invalid option. */ /* `getopt_long' already printed an error message. */ goto failure; default: /* bug: option not considered. */ fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); abort (); } /* switch */ } /* while */ update_multiple_arg((void *)&(args_info->action_arg), &(args_info->action_orig), args_info->action_given, local_args_info.action_given, 0, ARG_ENUM, action_list); update_multiple_arg((void *)&(args_info->connector_arg), &(args_info->connector_orig), args_info->connector_given, local_args_info.connector_given, 0, ARG_STRING, connector_list); update_multiple_arg((void *)&(args_info->device_pubkey_arg), &(args_info->device_pubkey_orig), args_info->device_pubkey_given, local_args_info.device_pubkey_given, 0, ARG_STRING, device_pubkey_list); args_info->action_given += local_args_info.action_given; local_args_info.action_given = 0; args_info->connector_given += local_args_info.connector_given; local_args_info.connector_given = 0; args_info->device_pubkey_given += local_args_info.device_pubkey_given; local_args_info.device_pubkey_given = 0; if (check_required) { error_occurred += cmdline_parser_required2 (args_info, argv[0], additional_error); } cmdline_parser_release (&local_args_info); if ( error_occurred ) return (EXIT_FAILURE); return 0; failure: free_list (action_list, 0 ); free_list (connector_list, 1 ); free_list (device_pubkey_list, 1 ); cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } #ifndef CONFIG_FILE_LINE_SIZE #define CONFIG_FILE_LINE_SIZE 2048 #endif #define ADDITIONAL_ERROR " in configuration file " #define CONFIG_FILE_LINE_BUFFER_SIZE (CONFIG_FILE_LINE_SIZE+3) /* 3 is for "--" and "=" */ static int _cmdline_parser_configfile (const char *filename, int *my_argc) { FILE* file; char my_argv[CONFIG_FILE_LINE_BUFFER_SIZE+1]; char linebuf[CONFIG_FILE_LINE_SIZE]; int line_num = 0; int result = 0, equal; char *fopt, *farg; char *str_index; size_t len, next_token; char delimiter; if ((file = fopen(filename, "r")) == 0) { fprintf (stderr, "%s: Error opening configuration file '%s'\n", CMDLINE_PARSER_PACKAGE, filename); return EXIT_FAILURE; } while ((fgets(linebuf, CONFIG_FILE_LINE_SIZE, file)) != 0) { ++line_num; my_argv[0] = '\0'; len = strlen(linebuf); if (len > (CONFIG_FILE_LINE_BUFFER_SIZE-1)) { fprintf (stderr, "%s:%s:%d: Line too long in configuration file\n", CMDLINE_PARSER_PACKAGE, filename, line_num); result = EXIT_FAILURE; break; } /* find first non-whitespace character in the line */ next_token = strspn (linebuf, " \t\r\n"); str_index = linebuf + next_token; if ( str_index[0] == '\0' || str_index[0] == '#') continue; /* empty line or comment line is skipped */ fopt = str_index; /* truncate fopt at the end of the first non-valid character */ next_token = strcspn (fopt, " \t\r\n="); if (fopt[next_token] == '\0') /* the line is over */ { farg = 0; equal = 0; goto noarg; } /* remember if equal sign is present */ equal = (fopt[next_token] == '='); fopt[next_token++] = '\0'; /* advance pointers to the next token after the end of fopt */ next_token += strspn (fopt + next_token, " \t\r\n"); /* check for the presence of equal sign, and if so, skip it */ if ( !equal ) if ((equal = (fopt[next_token] == '='))) { next_token++; next_token += strspn (fopt + next_token, " \t\r\n"); } str_index += next_token; /* find argument */ farg = str_index; if ( farg[0] == '\"' || farg[0] == '\'' ) { /* quoted argument */ str_index = strchr (++farg, str_index[0] ); /* skip opening quote */ if (! str_index) { fprintf (stderr, "%s:%s:%d: unterminated string in configuration file\n", CMDLINE_PARSER_PACKAGE, filename, line_num); result = EXIT_FAILURE; break; } } else { /* read up the remaining part up to a delimiter */ next_token = strcspn (farg, " \t\r\n#\'\""); str_index += next_token; } /* truncate farg at the delimiter and store it for further check */ delimiter = *str_index, *str_index++ = '\0'; /* everything but comment is illegal at the end of line */ if (delimiter != '\0' && delimiter != '#') { str_index += strspn(str_index, " \t\r\n"); if (*str_index != '\0' && *str_index != '#') { fprintf (stderr, "%s:%s:%d: malformed string in configuration file\n", CMDLINE_PARSER_PACKAGE, filename, line_num); result = EXIT_FAILURE; break; } } noarg: if (!strcmp(fopt,"include")) { if (farg && *farg) { result = _cmdline_parser_configfile(farg, my_argc); } else { fprintf(stderr, "%s:%s:%d: include requires a filename argument.\n", CMDLINE_PARSER_PACKAGE, filename, line_num); } continue; } len = strlen(fopt); strcat (my_argv, len > 1 ? "--" : "-"); strcat (my_argv, fopt); if (len > 1 && ((farg && *farg) || equal)) strcat (my_argv, "="); if (farg && *farg) strcat (my_argv, farg); ++(*my_argc); cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); cmd_line_list_tmp->next = cmd_line_list; cmd_line_list = cmd_line_list_tmp; cmd_line_list->string_arg = gengetopt_strdup(my_argv); } /* while */ if (file) fclose(file); return result; } int cmdline_parser_configfile ( const char *filename, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) { struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; return cmdline_parser_config_file (filename, args_info, ¶ms); } int cmdline_parser_config_file (const char *filename, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params) { int i, result; int my_argc = 1; char **my_argv_arg; char *additional_error; /* store the program name */ cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); cmd_line_list_tmp->next = cmd_line_list; cmd_line_list = cmd_line_list_tmp; cmd_line_list->string_arg = gengetopt_strdup (CMDLINE_PARSER_PACKAGE); result = _cmdline_parser_configfile(filename, &my_argc); if (result != EXIT_FAILURE) { my_argv_arg = (char **) malloc((my_argc+1) * sizeof(char *)); cmd_line_list_tmp = cmd_line_list; for (i = my_argc - 1; i >= 0; --i) { my_argv_arg[i] = cmd_line_list_tmp->string_arg; cmd_line_list_tmp = cmd_line_list_tmp->next; } my_argv_arg[my_argc] = 0; additional_error = (char *)malloc(strlen(filename) + strlen(ADDITIONAL_ERROR) + 1); strcpy (additional_error, ADDITIONAL_ERROR); strcat (additional_error, filename); result = cmdline_parser_internal (my_argc, my_argv_arg, args_info, params, additional_error); free (additional_error); free (my_argv_arg); } free_cmd_list(); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } /* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ yubihsm-shell-2.7.3/src/cmd_util.c0000644000175000017500000001502215167357110016027 0ustar aveenaveen/* * Copyright 2025 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "yubihsm-shell.h" #include "cmd_util.h" static char *string_parser(char *str_orig, char delimiter, char *str_found) { char escape_char = '\\'; int f = 0; char *p = str_orig; while (*p == delimiter) { p++; } for (; *p; p++) { if (*p != delimiter) { str_found[f++] = *p; } else if (*p == delimiter) { if ((*(p - 1) == escape_char && *(p - 2) == escape_char)) { // The escape_char before the delimiter is escaped // => the delimiter is still in effect str_found[f - 1] = '\0'; return p + 1; } else if (*(p - 1) == escape_char && *(p - 2) != escape_char) { // the delimiter is escaped str_found[f - 1] = delimiter; } else { // nothing is escaped str_found[f] = '\0'; return p + 1; } } } str_found[f] = '\0'; return NULL; } X509_NAME *parse_subject_name(const char *orig_name) { char name[1025] = {0}; char part[1025] = {0}; X509_NAME *parsed = NULL; char *ptr = name; if (strlen(orig_name) > 1024) { fprintf(stderr, "Name is too long!\n"); return NULL; } strncpy(name, orig_name, sizeof(name)); name[sizeof(name) - 1] = 0; if (*name != '/' || name[strlen(name) - 1] != '/') { fprintf(stderr, "Name does not start or does not end with '/'!\n"); return NULL; } parsed = X509_NAME_new(); if (!parsed) { fprintf(stderr, "Failed to allocate memory\n"); return NULL; } while ((ptr = string_parser(ptr, '/', part))) { char *key; char *value; char *equals = strchr(part, '='); if (!equals) { fprintf(stderr, "The part '%s' doesn't seem to contain a =.\n", part); goto parse_err; } *equals++ = '\0'; value = equals; key = part; if (!key) { fprintf(stderr, "Malformed name (%s)\n", part); goto parse_err; } if (!value) { fprintf(stderr, "Malformed name (%s)\n", part); goto parse_err; } if (!X509_NAME_add_entry_by_txt(parsed, key, MBSTRING_UTF8, (unsigned char *) value, -1, -1, 0)) { fprintf(stderr, "Failed adding %s=%s to name.\n", key, value); goto parse_err; } } return parsed; parse_err: X509_NAME_free(parsed); return NULL; } static int ec_key_ex_data_idx = -1; struct internal_key { yh_session *session; uint16_t key_id; }; static int yk_rsa_meth_finish(RSA *rsa) { free(RSA_meth_get0_app_data(RSA_get_method(rsa))); return 1; } static int yk_rsa_meth_sign(int dtype, const unsigned char *m, unsigned int m_len, unsigned char *sig, unsigned int *sig_len, const RSA *rsa) { UNUSED(dtype); size_t yh_siglen = RSA_size(rsa); const RSA_METHOD *meth = RSA_get_method(rsa); const struct internal_key *key = RSA_meth_get0_app_data(meth); yh_rc yrc = yh_util_sign_pkcs1v1_5(key->session, key->key_id, true, m, m_len, sig, &yh_siglen); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with PKCS#1v1.5: %s\n", yh_strerror(yrc)); return 0; } *sig_len = (unsigned int) yh_siglen; return 1; } static void yk_ec_meth_finish(EC_KEY *ec) { free(EC_KEY_get_ex_data(ec, ec_key_ex_data_idx)); } static int yk_ec_meth_sign(int type, const unsigned char *m, int m_len, unsigned char *sig, unsigned int *sig_len, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec) { UNUSED(type); UNUSED(kinv); UNUSED(r); size_t yh_siglen = ECDSA_size(ec); const struct internal_key *key = EC_KEY_get_ex_data(ec, ec_key_ex_data_idx); yh_rc yrc = yh_util_sign_ecdsa(key->session, key->key_id, m, m_len, sig, &yh_siglen); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with ECDSA: %s\n", yh_strerror(yrc)); return 0; } *sig_len = (unsigned int) yh_siglen; return 1; } EVP_PKEY *wrap_public_key(yh_session *session, yh_algorithm algorithm, EVP_PKEY *public_key, uint16_t key_id) { struct internal_key *int_key = malloc(sizeof(struct internal_key)); int_key->session = session; int_key->key_id = key_id; EVP_PKEY *pkey = EVP_PKEY_new(); if (yh_is_rsa(algorithm)) { const RSA *pk = EVP_PKEY_get0_RSA(public_key); RSA_METHOD *meth = RSA_meth_dup(RSA_get_default_method()); if (RSA_meth_set0_app_data(meth, int_key) != 1) { fprintf(stderr, "Failed to set RSA data\n"); return NULL; } if (RSA_meth_set_finish(meth, yk_rsa_meth_finish) != 1) { fprintf(stderr, "Failed to set RSA finish method\n"); return NULL; } if (RSA_meth_set_sign(meth, yk_rsa_meth_sign) != 1) { fprintf(stderr, "Failed to set RSA sign method\n"); return NULL; } RSA *sk = RSA_new(); RSA_set0_key(sk, BN_dup(RSA_get0_n(pk)), BN_dup(RSA_get0_e(pk)), NULL); if (RSA_set_method(sk, meth) != 1) { fprintf(stderr, "Failed to set RSA key method\n"); return NULL; } EVP_PKEY_assign_RSA(pkey, sk); } else if (yh_is_ec(algorithm)) { const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(public_key); EC_KEY_METHOD *meth = EC_KEY_METHOD_new(EC_KEY_get_method(ec)); EC_KEY_METHOD_set_init(meth, NULL, yk_ec_meth_finish, NULL, NULL, NULL, NULL); EC_KEY_METHOD_set_sign(meth, yk_ec_meth_sign, NULL, NULL); EC_KEY *sk = EC_KEY_new(); EC_KEY_set_group(sk, EC_KEY_get0_group(ec)); EC_KEY_set_public_key(sk, EC_KEY_get0_public_key(ec)); if (ec_key_ex_data_idx == -1) ec_key_ex_data_idx = EC_KEY_get_ex_new_index(0, NULL, NULL, NULL, NULL); if (EC_KEY_set_ex_data(sk, ec_key_ex_data_idx, int_key) != 1) { fprintf(stderr, "Failed to set EC data\n"); return NULL; } if (EC_KEY_set_method(sk, meth) != 1) { fprintf(stderr, "Failed to wrap public EC key\n"); return NULL; } EVP_PKEY_assign_EC_KEY(pkey, sk); } return pkey; } yubihsm-shell-2.7.3/CHANGELOG0000644000175000017500000003146615167357110014520 0ustar aveenaveen=== Version 2.7.3 lib: Fix a bug in defining capabilities related to managing Public Wrap Key objects === Version 2.7.2 lib: Ensure that command audit for command 0x05 cannot be turned on pkcs11: Improve handling of public key component of RSA Wrap Key pkcs11: Fix a bug where generating an RSA key pair can potentially result in the wrong type of object being created build: Upgrade minimum CMake version requirement === Version 2.7.1 shell: Add support for decrypt-oaep command in non-interactive mode test: Improve testing processes === Version 2.7.0 lib: shell: pkcs11: Add support for compressing X509Certificate before import shell: Add subcommand to generate certificate signing request (CSR) test: Increase test coverage === Version 2.6.0 lib: shell: pkcs11: Add support for asymmetric wrap pkcs11: Add support for PKCS11 3.0 shell: Fix opening a session using credentials stored on a YubiKey build: Always compile with YubiHSM Auth enabled === Version 2.5.0 pkcs11: Add support for applying KDF after ECDH derivation pkcs11: Shell: Fix minor bugs test: Increase test coverage === Version 2.4.2 pkcs11: Add Symmetric key capabilities to searchable criteria pkcs11: Add support for CKA_KEY_TYPE when searching for objects pkcs11: Add support for CKA_MODIFIABLE and CKA_COPYABLE attributes for AES and Wrap keys test: Increase test coverage === Version 2.4.1 pkcs11: Security update for https://www.yubico.com/support/security-advisories/ysa-2023-01/[YSA-2023-01] pkcs11: Allow only a user with access to all the object's domains to edit its attributes pkcs11: Allow for the creation of an asymmetric key even if CKA_ID or CKA_LABEL attribute values for the private and public key are different. pkcs11: Improve backup capabilities of objects whose attributes have been changed pkcs11: Add support for CKA_ALLOWED_MECHANISMS pkcs11: Fix CKA_SENSITIVE and CKA_PRIVATE return value for opaque objects pkcs11: Add support for CKA_EXTRACTABLE for imported certificates pkcs11: Fix regression that only allowed encryption with private keys lib: pkcs11: Delay client side MAC check to avoid leaving unauthenticated sessions open shell: Fix handling of ED25519 keys build: Update release script for Centos7 build: Fix paths in pkg-config template build: Set linker flags by platform test: Improve test coverage === Version 2.4.0 lib: shell: pkcs11: Add support for symmetric encryption, AES-ECB and AES-CBC (Requires firmware version 2.3 and later) shell: Enable asymmetric authentication by default (Requires firmware version 2.3 and later) shell: Allow hex format when creating symmetric authentication key shell: Improve usage of the list command shell: Allow yubihsm-auth reader to be specified shell: Enable backend TLS support in the command line pkcs11: Add support for modifying CKA_ID and CKA_LABEL attribute values pkcs11: Improve handling of attributes pkcs11: Improve debug output pkcs11: Improve error handling pkcs11: Change in firmware/harware version representation. The version as reported by C_GetSlotInfo and C_GetTokenInfo will now show minor*10+patch, instead of minor*100+patch build: Dependecy updates === Version 2.3.2 shell: Remove limit on input file size shell: pkcs11: build: Minor improvements === Version 2.3.1 lib: Fix handling errors received from the YubiHSM shell: Enforce valid DER certificate when importing a certificate shell: Support PEM in-format when importing a certificate shell: pkcs11: Fix minor memory leaks pkcs11: Better handling of invalid input build: Better build experience on MacOS build: Better usage of security flags build: Improve scripts to build debian packages test: Improve testing === Version 2.3.0a build: Enable additional hardening flags when building with CMake < 3.14 === Version 2.3.0 lib: Security update for https://www.yubico.com/support/security-advisories/ysa-2021-04/[YSA-2021-04] lib: Improve backend loading on Windows lib: Add support for ecdh primitives using bcrypt on Windows lib: cli: Improve error handling lib: pkcs11: Add more connection option lib: pkcs11: cli: Fix minor bugs cli: Rename set-option to put-option and add support for get-option pkcs11: Add support for RSA encryption yubihsm-auth: No PSCS reader name filtering by default build: Add version details to yubihsm_pkcs11 module and libykhsmauth library files on Windows build: Make minimum CMake version required 3.5 test: Improved testing === Version 2.2.0 shell: Enable ykhsmauth to be used from commandline ykhsmauth: lib: Add support for YubiCrypt authentication yubihsm-auth: Add CLI for YubiCrypt authentication === Version 2.1.0 lib: Security update for https://www.yubico.com/support/security-advisories/ysa-2021-01/[YSA-2021-01] lib: Add FIPS-mode option lib: Add support for rsa-pkcs1-decrypt algorithm lib: shell: Add support for OTP AEAD rewrap shell: Add support writing attestation certificate to a file pkcs11: Add support for CKA_TRUSTED attribute all: Fix potential memory leaks all: Improve error handling doc: Clarify the minimum length of the password used with PKCS11 === Version 2.0.3 all: Move away from archaic offensive terms all: Update build scripts to account for changes in newer MACOS all: Build on Windows with Visual Studio 2019 pkcs11: Enable .Net to load yubihsm-pkcs11.dylib lib: Fix memory leaks lib: Security fixes lib: Add a session identifier for the backend lib: Make the backend more thread-safe on Windows shell: Honor the base64 format when returning a public key shell: Honor the PEM format when returning a certificate shell: Improve parsing of command line arguments when using OAEP decryption shell: Add support for special (national) characters test: Improve testing === Version 2.0.2 yhauth: Report touch policy as part of the "list" command ykyh: Allow reading the password from stdin yhwrap: Fix wrapping of ED25519 keys shell: Fix ED25519 public key PEM formatting shell: Replace unprintable characters in the object label with '.' ci: Fail early if DEFAULT_CONNECTOR_URL is not set ci: Update homebrew dependencies build: Add two bionic-based builds build: Fix 32-bit Windows builds with mingw32/gcc7 build: Ensure that PCSC is not automatically used on Windows tool: Stop the timer for keepalive functionality while reading the password string misc: Allow disabling link time optimization. misc: Fixes and improvements to build, work and test on FreeBSD. === Version 2.0.1 shell: Add "blink-device" command in CLI mode shell: Add "set-log-index" command to CLI mode shell: Add "exit" as an alias to the "quit" command. shell: Add an optional output file to "audit get" command shell: No openning a session for commands that do not need one shell/yhwrap/pkcs11: open all files in binary mode to keep Windows from changing line ends shell: Install the sigalarm handler in CLI mode build: Add support for installing to lib64 on Fedora build: Only use LTO on clang > 7 build: Add a library only build option examples: Improve code examples test: Tests are improved and are better adapted for MacOS pkcs11/tests: Only run ecdh engine tests on openssl 1.1+ lib: Improve handling of device memory lib: Allow both USB and HTTP support to be compiled in static library lib: Implement signing using sign-eddsa lib: Add the possibility to generate authkey specifying all the capabilities in their string form lib/curl: Include the curl strerror in debug when a connection fails doc: Improvement in documentation, README files and command help === Version 2.0.0 lib: Fix issue with session creation if the authentication key ID is too high lib: Fix a potential issue with memory operations lib: Fix a potential issue with data left after previous transactions or connections lib: Better documentation of arguments lib: Better handling of errors lib: Rename object types, algorithms, capabilities, commands, command options and errors lib: API improvements lib: Add a feature to derive an authentication key from a password lib: Add a feature to change an authentication key pkcs11: Added support for C_DeriveKey() shell: More efficient use of the keepalive function shell: More efficient handling of sessions when a connection is terminated shell: Change keepalive command to a toggle (on/off) tests: Make code examples compile tests: Add support for running tests using direct USB connection all: Drop unused files all: Re-organization of file structure doc: Drop documentation from the code base and moved the content to Yubico's developers website (https://developers.yubico.com/YubiHSM2/) === Version 1.0.4 pkcs11: Fix a potential issue with RSA bit calculation in C_GetMechanismInfo() pkcs11: Fix a case where we return the wrong error from C_GetMechanismList() pkcs11: Add a way for users to pass in options over the API to C_Initialize() connector: Fix a race condition when the usb state was re-created. connector: Better error reporting in some failure cases. connector: Fix issues where the connector could hang on Windows. connector: Fix an issue where the connector would not reconnect on Windows. shell: Fix an issue with importing HMAC keys. === Version 1.0.3 shell: Handle return values from reset correctly on windows. connector: Return HTTP errors when operations fail. lib: Handle HTTP errors correctly on windows. lib: Fix printing of time in debug on windows. pkcs11: Fix a problem in C_FindObjects() where not all items would be returned === Version 1.0.2 lib: Fix connect timeout on windows lib: Fix debugging to file lib/pkcs11/shell: Openssl 1.1 compatibility lib: Mark internal symbols as hidden correctly pkcs11: Fix an error case leaving the session in a broken state pkcs11: Start session IDs from 1, not 0 pkcs11: Add option to set connect timeout pkcs11: Accept C_SetAttributeValue() for CKA_ID and CKA_LABEL if unchanged setup: Fix broken debian package shell: Implement decrypt-ecdh in non-interactive mode connector: On Windows use internal USB libraries instead of libusb connector: Implement Host header allow listing (Use to prevent DNS rebinding attacks in applicable environments, e.g., if there is an absolute need to use a web browser on the host where the Yubihsm2 is installed to connect to untrusted web sites on the Internet. This is not a recommended practice.) === Version 1.0.1 shell: Fix hashing so signing from windows shell works shell: Sorted output pkcs11: Handle ecdsa with longer hash than key pkcs11: Correct error for trying to extract EC key pkcs11: Fix native locking on windows pkcs11: Correct linking on macos lib: Fix logic in session re-use lib: Mark all internal symbols as hidden ksp: Handle passwords longer than 8 characters all: Provide deb packages on debian/ubuntu === Version 0.2.1 doc: add Compatibility.adoc doc: fixup GET LOGS text doc: fixup GET LOGS stanza doc: fixup GET OBJECT INFO text doc: add text about pkcs11 configuration examples/attest: add reading out of cert after loading it examples/import_rsa: change import_rsa example to use pss signing examples: add wrap_data example examples: change all examples to use yh_parse_domains lib/tool/doc: add blink command log: add yh_set_connector_option for transport options lib: give create_session functions a reopen option lib: add OBJECT_EXISTS error lib: allow yh_util_get_object_info to not fill in an object lib: implement yh_util_reset lib: new function for setting debug output: yh_set_debug_output pkcs11: add CKA_ENCRYPT and CKA_VERIFY to public keys pkcs11: add an offset to the vendor defined values pkcs11: add checks for boolean attributes we just accept pkcs11: add configfile options for setting verbosity pkcs11: add debug output file to pkcs11 config pkcs11: don't set CKF_DECRYPT for pkcs+hash mechanisms pkcs11: fix verify for CKM_RSA_PKCS_PSS pkcs11: fixup for C_FindObjectsInit being called without logging in pkcs11: fixup session release in C_CloseSession pkcs11: ignore CKA_APPLICATION in object filtering pkcs11: ignore CKA_KEY_TYPE in C_FindObjectsInit pkcs11: in C_FindObjectsInit make more initial state earlier pkcs11: in C_FindObjectsInit set operation type as late as possible pkcs11: in C_GetSlotList detect overflow more reliably pkcs11: move CKA_ENCRYPT and CKA_VERIFY from hard true on pubkey pkcs11: move CKA_VERIFY and CKA_ENCRYPT from hard true for ec pubkey pkcs11: move wrap/unwrap on rsa generate to unchecked pkcs11: never try to delete a public key, lie and say it's fine instead pkcs11: print more debug info on OAEP mechanism error pkcs11: remove some skipped pkcs11test tests, we fail them correctly pkcs11: return CKR_ATTRIBUTE_SENSITIVE on CKA_PRIVATE_EXPONENT pkcs11: truncate CKA_ID to two bytes if it's longer pkcs11: when closing the debug output file, reset it to stderr tool: drop local connector spawn code tool: add decrypt ecdh command tool: add decrypt oaep command tool: add output for decrypt pkcs1v15 tool: cleanup created objects after benchmark tool: fixup otp decrypt that has to hex decode the otp tool: for ecdh benchmarks delete the temporary key tool: print a message when doing benchmark setup tool: make the reset command print nicer messages yhwrap: add hmac key pre-split yubihsm-shell-2.7.3/yubihsm-auth/0000755000175000017500000000000015167357157015726 5ustar aveenaveenyubihsm-shell-2.7.3/yubihsm-auth/cmdline.h0000644000175000017500000002727615167357157017530 0ustar aveenaveen/** @file cmdline.h * @brief The header file for the command line option parser * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten * @author GNU Gengetopt */ #ifndef CMDLINE_H #define CMDLINE_H /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* for FILE */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef CMDLINE_PARSER_PACKAGE /** @brief the program name (used for printing errors) */ #define CMDLINE_PARSER_PACKAGE PACKAGE #endif #ifndef CMDLINE_PARSER_PACKAGE_NAME /** @brief the complete program name (used for help and version) */ #ifdef PACKAGE_NAME #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE_NAME #else #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE #endif #endif #ifndef CMDLINE_PARSER_VERSION /** @brief the program version */ #define CMDLINE_PARSER_VERSION VERSION #endif enum enum_action { action__NULL = -1, action_arg_calculate = 0, action_arg_changeMINUS_mgmkey, action_arg_delete, action_arg_list, action_arg_put, action_arg_reset, action_arg_retries, action_arg_version, action_arg_getMINUS_challenge, action_arg_getMINUS_pubkey }; enum enum_touch { touch__NULL = -1, touch_arg_off = 0, touch_arg_on }; /** @brief Where the command line options are stored */ struct gengetopt_args_info { const char *help_help; /**< @brief Print help and exit help description. */ const char *version_help; /**< @brief Print version and exit help description. */ enum enum_action action_arg; /**< @brief Action to perform. */ char * action_orig; /**< @brief Action to perform original value given at command line. */ const char *action_help; /**< @brief Action to perform help description. */ char * mgmkey_arg; /**< @brief Management key is required to put and delete credentials. Sometimes, this key is also referenced as 'Admin Access Code' (default='00000000000000000000000000000000'). */ char * mgmkey_orig; /**< @brief Management key is required to put and delete credentials. Sometimes, this key is also referenced as 'Admin Access Code' original value given at command line. */ const char *mgmkey_help; /**< @brief Management key is required to put and delete credentials. Sometimes, this key is also referenced as 'Admin Access Code' help description. */ char * new_mgmkey_arg; /**< @brief New management key (default=''). */ char * new_mgmkey_orig; /**< @brief New management key original value given at command line. */ const char *new_mgmkey_help; /**< @brief New management key help description. */ char * credpwd_arg; /**< @brief Credential password is used to access the credential when logging into the YubiHSM2. Sometimes, this password is also referenced as 'User Access Code' (default=''). */ char * credpwd_orig; /**< @brief Credential password is used to access the credential when logging into the YubiHSM2. Sometimes, this password is also referenced as 'User Access Code' original value given at command line. */ const char *credpwd_help; /**< @brief Credential password is used to access the credential when logging into the YubiHSM2. Sometimes, this password is also referenced as 'User Access Code' help description. */ char * label_arg; /**< @brief Credential label (default=''). */ char * label_orig; /**< @brief Credential label original value given at command line. */ const char *label_help; /**< @brief Credential label help description. */ char * reader_arg; /**< @brief Only use a matching reader (default=''). */ char * reader_orig; /**< @brief Only use a matching reader original value given at command line. */ const char *reader_help; /**< @brief Only use a matching reader help description. */ enum enum_touch touch_arg; /**< @brief Touch required (default='off'). */ char * touch_orig; /**< @brief Touch required original value given at command line. */ const char *touch_help; /**< @brief Touch required help description. */ char * context_arg; /**< @brief Session keys calculation context (default=''). */ char * context_orig; /**< @brief Session keys calculation context original value given at command line. */ const char *context_help; /**< @brief Session keys calculation context help description. */ int verbose_arg; /**< @brief Print more information (default='0'). */ char * verbose_orig; /**< @brief Print more information original value given at command line. */ const char *verbose_help; /**< @brief Print more information help description. */ char * derivation_password_arg; /**< @brief Derivation password for encryption and MAC keys (default=''). */ char * derivation_password_orig; /**< @brief Derivation password for encryption and MAC keys original value given at command line. */ const char *derivation_password_help; /**< @brief Derivation password for encryption and MAC keys help description. */ char * enckey_arg; /**< @brief Encryption key (default=''). */ char * enckey_orig; /**< @brief Encryption key original value given at command line. */ const char *enckey_help; /**< @brief Encryption key help description. */ char * mackey_arg; /**< @brief MAC key (default=''). */ char * mackey_orig; /**< @brief MAC key original value given at command line. */ const char *mackey_help; /**< @brief MAC key help description. */ char * privkey_arg; /**< @brief Private key (default=''). */ char * privkey_orig; /**< @brief Private key original value given at command line. */ const char *privkey_help; /**< @brief Private key help description. */ unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ unsigned int action_given ; /**< @brief Whether action was given. */ unsigned int mgmkey_given ; /**< @brief Whether mgmkey was given. */ unsigned int new_mgmkey_given ; /**< @brief Whether new-mgmkey was given. */ unsigned int credpwd_given ; /**< @brief Whether credpwd was given. */ unsigned int label_given ; /**< @brief Whether label was given. */ unsigned int reader_given ; /**< @brief Whether reader was given. */ unsigned int touch_given ; /**< @brief Whether touch was given. */ unsigned int context_given ; /**< @brief Whether context was given. */ unsigned int verbose_given ; /**< @brief Whether verbose was given. */ unsigned int derivation_password_given ; /**< @brief Whether derivation-password was given. */ unsigned int enckey_given ; /**< @brief Whether enckey was given. */ unsigned int mackey_given ; /**< @brief Whether mackey was given. */ unsigned int privkey_given ; /**< @brief Whether privkey was given. */ int asymmetric_mode_counter; /**< @brief Counter for mode asymmetric */ int derivation_mode_counter; /**< @brief Counter for mode derivation */ int explicit_mode_counter; /**< @brief Counter for mode explicit */ } ; /** @brief The additional parameters to pass to parser functions */ struct cmdline_parser_params { int override; /**< @brief whether to override possibly already present options (default 0) */ int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ int check_required; /**< @brief whether to check that all required options were provided (default 1) */ int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ } ; /** @brief the purpose string of the program */ extern const char *gengetopt_args_info_purpose; /** @brief the usage string of the program */ extern const char *gengetopt_args_info_usage; /** @brief the description string of the program */ extern const char *gengetopt_args_info_description; /** @brief all the lines making the help output */ extern const char *gengetopt_args_info_help[]; /** * The command line parser * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info); /** * The command line parser (version with additional parameters - deprecated) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_ext() instead */ int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required); /** * The command line parser (version with additional parameters) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params); /** * Save the contents of the option struct into an already open FILE stream. * @param outfile the stream where to dump options * @param args_info the option struct to dump * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info); /** * Save the contents of the option struct into a (text) file. * This file can be read by the config file parser (if generated by gengetopt) * @param filename the file where to save * @param args_info the option struct to save * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info); /** * Print the help */ void cmdline_parser_print_help(void); /** * Print the version */ void cmdline_parser_print_version(void); /** * Initializes all the fields a cmdline_parser_params structure * to their default values * @param params the structure to initialize */ void cmdline_parser_params_init(struct cmdline_parser_params *params); /** * Allocates dynamically a cmdline_parser_params structure and initializes * all its fields to their default values * @return the created and initialized cmdline_parser_params structure */ struct cmdline_parser_params *cmdline_parser_params_create(void); /** * Initializes the passed gengetopt_args_info structure's fields * (also set default values for options that have a default) * @param args_info the structure to initialize */ void cmdline_parser_init (struct gengetopt_args_info *args_info); /** * Deallocates the string fields of the gengetopt_args_info structure * (but does not deallocate the structure itself) * @param args_info the structure to deallocate */ void cmdline_parser_free (struct gengetopt_args_info *args_info); /** * Checks that all the required options were specified * @param args_info the structure to check * @param prog_name the name of the program that will be used to print * possible errors * @return */ int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name); extern const char *cmdline_parser_action_values[]; /**< @brief Possible values for action. */ extern const char *cmdline_parser_touch_values[]; /**< @brief Possible values for touch. */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* CMDLINE_H */ yubihsm-shell-2.7.3/yubihsm-auth/main.c0000644000175000017500000004324415167357110017012 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "pkcs5.h" #include "parsing.h" #include "cmdline.h" uint8_t _yh_verbosity = 0xff; FILE *_yh_output; static bool parse_label(const char *prompt, char *label, char *parsed, size_t *parsed_len) { if (strlen(label) > *parsed_len) { fprintf(stdout, "Unable to read label, buffer too small\n"); return false; } if (strlen(label) == 0) { if (read_string(prompt, parsed, *parsed_len, false) == false) { return false; } } else { strcpy(parsed, label); } *parsed_len = strlen(parsed); return true; } static bool parse_pw(const char *prompt, char *pw, uint8_t *parsed, size_t *parsed_len) { if (strlen(pw) == 0) { if (read_string(prompt, (char *) parsed, *parsed_len, HIDDEN_CHECKED) == false) { return false; } } else { if(strcmp(pw, "-")) { if (strlen(pw) > *parsed_len) { fprintf(stderr, "Unable to read password, buffer too small\n"); return false; } strncpy((char *) parsed, pw, *parsed_len); } else { *parsed = 0; } } *parsed_len = strlen((char *) parsed); return true; } static bool parse_key(const char *prompt, char *key, uint8_t *parsed, size_t *parsed_len) { char buf[320] = {0}; size_t buf_size = sizeof(buf); size_t initial_len = *parsed_len; if (strlen(key) > buf_size) { fprintf(stdout, "Unable to read %s, buffer too small\n", prompt); return false; } if (strlen(key) == 0) { if (read_string(prompt, buf, buf_size, true) == false) { return false; } } else { strcpy(buf, key); } buf_size = strlen(buf); if (hex_decode(buf, parsed, parsed_len) == false) { fprintf(stdout, "Unable to parse %s, must be %d characters hexadecimal\n", prompt, YKHSMAUTH_YUBICO_AES128_KEY_LEN); return false; } if (*parsed_len != initial_len) { fprintf(stdout, "Unable to read %s, wrong length (must be %zu)\n", prompt, initial_len); return false; } return true; } static bool parse_context(const char *prompt, char *context, uint8_t *parsed, size_t *parsed_len) { char buf[320] = {0}; size_t buf_size = sizeof(buf); size_t initial_len = *parsed_len; if (strlen(context) > buf_size) { fprintf(stdout, "Unable to read context, buffer too small\n"); return false; } if (strlen(context) == 0) { if (read_string(prompt, buf, buf_size, false) == false) { return false; } buf_size = strlen(buf); } else { memcpy(buf, context, strlen(context)); buf_size = strlen(context); } if (hex_decode(buf, parsed, parsed_len) == false) { fprintf(stdout, "Unable to parse context, must be %d characters hexadecimal\n", YKHSMAUTH_CONTEXT_LEN * 2); return false; } if (*parsed_len != initial_len) { fprintf(stdout, "Unable to read context, wrong length (must be %d)\n", YKHSMAUTH_CONTEXT_LEN); return false; } return true; } static bool parse_touch_policy(enum enum_touch touch_policy, uint8_t *touch_policy_parsed) { switch (touch_policy) { case touch__NULL: case touch_arg_off: *touch_policy_parsed = 0; break; case touch_arg_on: *touch_policy_parsed = 1; break; } return true; } static bool delete_credential(ykhsmauth_state *state, char *mgmkey, char *label) { uint8_t mgmkey_parsed[YKHSMAUTH_PW_LEN] = {0}; size_t mgmkey_parsed_len = sizeof(mgmkey_parsed); char label_parsed[YKHSMAUTH_MAX_LABEL_LEN + 2] = {0}; size_t label_parsed_len = sizeof(label_parsed); uint8_t retries = 0; if (parse_key("Management key", mgmkey, mgmkey_parsed, &mgmkey_parsed_len) == false) { return false; } if (parse_label("Label", label, label_parsed, &label_parsed_len) == false) { return false; } ykhsmauth_rc ykhsmauthrc = ykhsmauth_delete(state, mgmkey_parsed, mgmkey_parsed_len, label_parsed, &retries); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to delete credential: %s, %d retries left\n", ykhsmauth_strerror(ykhsmauthrc), retries); return false; } fprintf(stdout, "Credential successfully deleted\n"); return true; } static bool list_credentials(ykhsmauth_state *state) { ykhsmauth_list_entry list[32] = {0}; size_t list_items = sizeof(list) / sizeof(list[0]); ykhsmauth_rc ykhsmauthrc = ykhsmauth_list_keys(state, list, &list_items); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to list credentials: %s\n", ykhsmauth_strerror(ykhsmauthrc)); return false; } if (list_items == 0) { fprintf(stdout, "No items found\n"); return true; } fprintf(stdout, "Found %zu item(s)\n", list_items); fprintf(stdout, "Algo\tTouch\tCounter\tLabel\n"); for (size_t i = 0; i < list_items; i++) { fprintf(stdout, "%d\t%d\t%d\t%s\n", list[i].algo, list[i].touch, list[i].ctr, list[i].label); } return true; } static bool put_credential(ykhsmauth_state *state, char *mgmkey, char *label, char *derivation_password, char *key_enc, char *key_mac, char *key_priv, char *credpassword, enum enum_touch touch_policy) { uint8_t mgmkey_parsed[YKHSMAUTH_PW_LEN] = {0}; size_t mgmkey_parsed_len = sizeof(mgmkey_parsed); char label_parsed[YKHSMAUTH_MAX_LABEL_LEN + 2] = {0}; size_t label_parsed_len = sizeof(label_parsed); uint8_t dpw_parsed[256] = {0}; size_t dpw_parsed_len = sizeof(dpw_parsed); uint8_t key_parsed[YKHSMAUTH_YUBICO_ECP256_PUBKEY_LEN] = {0}; size_t key_parsed_len = sizeof(key_parsed); uint8_t cpw_parsed[YKHSMAUTH_PW_LEN + 2] = {0}; size_t cpw_parsed_len = sizeof(cpw_parsed); uint8_t touch_policy_parsed = 0; uint8_t retries = 0; if (parse_key("Management key", mgmkey, mgmkey_parsed, &mgmkey_parsed_len) == false) { return false; } if (parse_label("Label", label, label_parsed, &label_parsed_len) == false) { return false; } if (strlen(key_mac) == 0 && strlen(key_enc) == 0 && strlen(key_priv) == 0) { if (parse_pw("Derivation password", derivation_password, dpw_parsed, &dpw_parsed_len) == false) { return false; } } else { dpw_parsed_len = 0; } if (dpw_parsed_len == 0) { if (strlen(key_priv)) { if (strcmp(key_priv, "-")) { key_parsed_len = YKHSMAUTH_YUBICO_ECP256_PRIVKEY_LEN; if (parse_key("Private key", key_priv, key_parsed, &key_parsed_len) == false) { return false; } } else { key_parsed_len = 0; } } else { size_t key_enc_parsed_len = YKHSMAUTH_YUBICO_AES128_KEY_LEN / 2; size_t key_mac_parsed_len = YKHSMAUTH_YUBICO_AES128_KEY_LEN / 2; if (parse_key("Encryption key", key_enc, key_parsed, &key_enc_parsed_len) == false) { return false; } if (parse_key("MAC key", key_mac, key_parsed + key_enc_parsed_len, &key_mac_parsed_len) == false) { return false; } key_parsed_len = key_enc_parsed_len + key_mac_parsed_len; } } else { if (pkcs5_pbkdf2_hmac((uint8_t *) dpw_parsed, dpw_parsed_len, (const uint8_t *) YKHSMAUTH_DEFAULT_SALT, strlen(YKHSMAUTH_DEFAULT_SALT), YKHSMAUTH_DEFAULT_ITERS, _SHA256, key_parsed, YKHSMAUTH_YUBICO_AES128_KEY_LEN) == false) { return false; } key_parsed_len = YKHSMAUTH_YUBICO_AES128_KEY_LEN; } if (parse_pw("Credential Password (max 16 characters)", credpassword, cpw_parsed, &cpw_parsed_len) == false) { return false; } if (cpw_parsed_len > YKHSMAUTH_PW_LEN) { fprintf(stderr, "Credential password can not be more than %d characters.\n", YKHSMAUTH_PW_LEN); return false; } if (parse_touch_policy(touch_policy, &touch_policy_parsed) == false) { return false; } ykhsmauth_rc ykhsmauthrc = ykhsmauth_put(state, mgmkey_parsed, mgmkey_parsed_len, label_parsed, strlen(key_priv) ? YKHSMAUTH_YUBICO_ECP256_ALGO : YKHSMAUTH_YUBICO_AES128_ALGO, key_parsed, key_parsed_len, cpw_parsed, cpw_parsed_len, touch_policy_parsed, &retries); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to store credential: %s, %d retries left\n", ykhsmauth_strerror(ykhsmauthrc), retries); return false; } fprintf(stdout, "Credential successfully stored\n"); return true; } static bool reset_device(ykhsmauth_state *state) { ykhsmauth_rc ykhsmauthrc = ykhsmauth_reset(state); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to reset device: %s\n", ykhsmauth_strerror(ykhsmauthrc)); return false; } fprintf(stdout, "Device successfully reset\n"); return true; } static bool get_mgmkey_retries(ykhsmauth_state *state) { uint8_t retries = 0; ykhsmauth_rc ykhsmauthrc = ykhsmauth_get_mgmkey_retries(state, &retries); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to get mgmkey retries: %s\n", ykhsmauth_strerror(ykhsmauthrc)); return false; } fprintf(stdout, "Retries left for Management Key: %d\n", retries); return true; } static void print_key(char *prompt, uint8_t *key, size_t len) { fprintf(stdout, "%s: ", prompt); for (size_t i = 0; i < len; i++) { fprintf(stdout, "%02x", key[i]); } fprintf(stdout, "\n"); } static bool get_challenge(ykhsmauth_state *state, char *label, char *credpassword) { char label_parsed[YKHSMAUTH_MAX_LABEL_LEN + 2] = {0}; size_t label_parsed_len = sizeof(label_parsed); uint8_t cpw_parsed[YKHSMAUTH_PW_LEN + 2] = {0}; size_t cpw_parsed_len = sizeof(cpw_parsed); uint8_t challenge[YKHSMAUTH_YUBICO_ECP256_PUBKEY_LEN] = {0}; size_t challenge_len = sizeof(challenge); if (parse_label("Label", label, label_parsed, &label_parsed_len) == false) { return false; } if (parse_pw("Credential Password (max 16 characters)", credpassword, cpw_parsed, &cpw_parsed_len) == false) { return false; } if (cpw_parsed_len > YKHSMAUTH_PW_LEN) { fprintf(stderr, "Credential password can not be more than %d characters.\n", YKHSMAUTH_PW_LEN); return false; } ykhsmauth_rc ykhsmauthrc = ykhsmauth_get_challenge_ex(state, label_parsed, cpw_parsed, cpw_parsed_len, challenge, &challenge_len); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to get challenge: %s\n", ykhsmauth_strerror(ykhsmauthrc)); return false; } print_key("Challenge", challenge, challenge_len); return true; } static bool get_pubkey(ykhsmauth_state *state, char *label) { char label_parsed[YKHSMAUTH_MAX_LABEL_LEN + 2] = {0}; size_t label_parsed_len = sizeof(label_parsed); uint8_t pubkey[YKHSMAUTH_YUBICO_ECP256_PUBKEY_LEN] = {0}; size_t pubkey_len = sizeof(pubkey); if (parse_label("Label", label, label_parsed, &label_parsed_len) == false) { return false; } ykhsmauth_rc ykhsmauthrc = ykhsmauth_get_pubkey(state, label_parsed, pubkey, &pubkey_len); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to get pubkey: %s\n", ykhsmauth_strerror(ykhsmauthrc)); return false; } print_key("Long-term public key", pubkey, pubkey_len); return true; } static bool get_version(ykhsmauth_state *state) { char version[64] = {0}; size_t version_len = sizeof(version); ykhsmauth_rc ykhsmauthrc = ykhsmauth_get_version(state, version, version_len); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to get version: %s\n", ykhsmauth_strerror(ykhsmauthrc)); return false; } fprintf(stdout, "Version %s\n", version); return true; } static bool calculate_session_keys(ykhsmauth_state *state, char *label, char *credpassword, char *context) { char label_parsed[YKHSMAUTH_MAX_LABEL_LEN + 2] = {0}; size_t label_parsed_len = sizeof(label_parsed); uint8_t context_parsed[YKHSMAUTH_CONTEXT_LEN] = {0}; size_t context_parsed_len = sizeof(context_parsed); uint8_t cpw_parsed[YKHSMAUTH_PW_LEN + 2] = {0}; size_t cpw_parsed_len = sizeof(cpw_parsed); uint8_t key_s_enc[YKHSMAUTH_SESSION_KEY_LEN] = {0}; uint8_t key_s_mac[YKHSMAUTH_SESSION_KEY_LEN] = {0}; uint8_t key_s_rmac[YKHSMAUTH_SESSION_KEY_LEN] = {0}; size_t key_s_enc_len = sizeof(key_s_enc); size_t key_s_mac_len = sizeof(key_s_mac); size_t key_s_rmac_len = sizeof(key_s_rmac); uint8_t retries = 0; if (parse_label("Label", label, label_parsed, &label_parsed_len) == false) { return false; } if (parse_context("Context", context, context_parsed, &context_parsed_len) == false) { return false; } if (parse_pw("Credential password", credpassword, cpw_parsed, &cpw_parsed_len) == false) { return false; } ykhsmauth_rc ykhsmauthrc = ykhsmauth_calculate(state, label_parsed, context_parsed, context_parsed_len, cpw_parsed, cpw_parsed_len, key_s_enc, key_s_enc_len, key_s_mac, key_s_mac_len, key_s_rmac, key_s_rmac_len, &retries); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to calculate session keys: %s\n", ykhsmauth_strerror(ykhsmauthrc)); if (ykhsmauthrc == YKHSMAUTHR_WRONG_PW) { fprintf(stderr, "%d attempts left\n", retries); } return false; } print_key("Session encryption key", key_s_enc, key_s_enc_len); print_key("Session MAC key", key_s_mac, key_s_mac_len); print_key("Session R-MAC key", key_s_rmac, key_s_rmac_len); return true; } static bool put_mgmkey(ykhsmauth_state *state, char *mgmkey, char *new_mgmkey) { uint8_t mgmkey_parsed[YKHSMAUTH_PW_LEN] = {0}; size_t mgmkey_parsed_len = sizeof(mgmkey_parsed); uint8_t new_mgmkey_parsed[YKHSMAUTH_PW_LEN] = {0}; size_t new_mgmkey_parsed_len = sizeof(mgmkey_parsed); uint8_t retries = 0; if (parse_key("Management key", mgmkey, mgmkey_parsed, &mgmkey_parsed_len) == false) { return false; } if (parse_key("New Management key", new_mgmkey, new_mgmkey_parsed, &new_mgmkey_parsed_len) == false) { return false; } ykhsmauth_rc ykhsmauthrc = ykhsmauth_put_mgmkey(state, mgmkey_parsed, mgmkey_parsed_len, new_mgmkey_parsed, new_mgmkey_parsed_len, &retries); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to change Management key: %s, %d retries left\n", ykhsmauth_strerror(ykhsmauthrc), retries); return false; } fprintf(stdout, "Management key successfully changed\n"); return true; } int main(int argc, char *argv[]) { struct gengetopt_args_info args_info = {0}; ykhsmauth_state *state = NULL; int rc = EXIT_FAILURE; if (cmdline_parser(argc, argv, &args_info) != 0) { goto main_exit; } ykhsmauth_rc ykhsmauthrc = ykhsmauth_init(&state, args_info.verbose_arg); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to initialize libykhsmauth\n"); goto main_exit; } ykhsmauthrc = ykhsmauth_connect(state, args_info.reader_arg); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Unable to connect: %s.\nMaybe yubihsm-auth is not supported or disabled on your YubiKey?\n", ykhsmauth_strerror(ykhsmauthrc)); goto main_exit; } bool result = false; switch (args_info.action_arg) { case action_arg_calculate: result = calculate_session_keys(state, args_info.label_arg, args_info.credpwd_arg, args_info.context_arg); break; case action_arg_changeMINUS_mgmkey: result = put_mgmkey(state, args_info.mgmkey_arg, args_info.new_mgmkey_arg); break; case action_arg_delete: result = delete_credential(state, args_info.mgmkey_arg, args_info.label_arg); break; case action_arg_list: result = list_credentials(state); break; case action_arg_put: result = put_credential(state, args_info.mgmkey_arg, args_info.label_arg, args_info.derivation_password_arg, args_info.enckey_arg, args_info.mackey_arg, args_info.privkey_arg, args_info.credpwd_arg, args_info.touch_arg); break; case action_arg_reset: result = reset_device(state); break; case action_arg_retries: result = get_mgmkey_retries(state); break; case action_arg_getMINUS_challenge: result = get_challenge(state, args_info.label_arg, args_info.credpwd_arg); break; case action_arg_getMINUS_pubkey: result = get_pubkey(state, args_info.label_arg); break; case action_arg_version: result = get_version(state); break; case action__NULL: fprintf(stderr, "No action given, nothing to do\n"); break; } if (result == true) { rc = EXIT_SUCCESS; } main_exit: ykhsmauth_done(state); return rc; } yubihsm-shell-2.7.3/yubihsm-auth/version.rc.in0000644000175000017500000000207715167357110020341 0ustar aveenaveen #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM Auth" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "yubihsm-auth.exe" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "yubihsm-auth.exe" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.7.3/yubihsm-auth/CMakeLists.txt0000644000175000017500000000523315167357110020456 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(${CMAKE_SOURCE_DIR}/cmake/openssl.cmake) find_libcrypto() set ( SOURCE main.c ../common/parsing.c ../common/pkcs5.c ../common/hash.c ) if(WIN32) set(SOURCE ${SOURCE} cmdline.c) include(${CMAKE_SOURCE_DIR}/cmake/getopt.cmake) find_getopt() else(WIN32) include(gengetopt) add_gengetopt_files (cmdline) set(SOURCE ${SOURCE} ${GGO_C}) message("${GGO_C}") endif(WIN32) include_directories ( ${LIBCRYPTO_INCLUDEDIR} ${CMAKE_CURRENT_SOURCE_DIR}/../ykhsmauth ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${CMAKE_CURRENT_SOURCE_DIR}/../common ) if(WIN32) list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) set (BCRYPT_LIBRARY bcrypt) endif(WIN32) # NOTE(adma): required by gengetopt add_definitions (-DPACKAGE="yubihsm-auth") add_definitions (-DVERSION="${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") list(APPEND LCOV_REMOVE_PATTERNS "'${PROJECT_SOURCE_DIR}/yubihsm-auth/cmdline.c'") if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") set_property(SOURCE ${GGO_C} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-but-set-variable ") endif() add_executable (yubihsm-auth ${SOURCE}) target_link_libraries ( yubihsm-auth ${LIBCRYPTO_LDFLAGS} ${GETOPT_LIBS} ykhsmauth ${BCRYPT_LIBRARY} ) # Set install RPATH (Darwin default from root CMakeLists.txt is correct for bin/ targets) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_target_properties(yubihsm-auth PROPERTIES INSTALL_RPATH "${YUBIHSM_INSTALL_LIB_DIR}") endif() install( TARGETS yubihsm-auth ARCHIVE DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" LIBRARY DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" RUNTIME DESTINATION "${YUBIHSM_INSTALL_BIN_DIR}") if (NOT WITHOUT_MANPAGES) include (help2man) add_help2man_manpage (yubihsm-auth.1 yubihsm-auth) add_custom_target (yubihsm-auth-man ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/yubihsm-auth.1 ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/yubihsm-auth.1" DESTINATION "${YUBIHSM_INSTALL_MAN_DIR}/man1") endif () yubihsm-shell-2.7.3/yubihsm-auth/cmdline.ggo0000644000175000017500000000417215167357110020030 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # option "action" a "Action to perform" values="calculate", "change-mgmkey", "delete", "list", "put", "reset", "retries", "version", "get-challenge", "get-pubkey" enum optional option "mgmkey" k "Management key is required to put and delete credentials. Sometimes, this key is also referenced as 'Admin Access Code'" string optional default="00000000000000000000000000000000" option "new-mgmkey" K "New management key" string optional default="" option "credpwd" p "Credential password is used to access the credential when logging into the YubiHSM2. Sometimes, this password is also referenced as 'User Access Code'" string optional default="" option "label" l "Credential label" string optional default="" option "reader" r "Only use a matching reader" string optional default="" option "touch" t "Touch required" values="off","on" enum optional default="off" option "context" c "Session keys calculation context" string optional default="" option "verbose" v "Print more information" int optional default="0" argoptional defmode "derivation" modedesc="Derive keys from a password using PBKDF2" modeoption "derivation-password" d "Derivation password for encryption and MAC keys" string mode="derivation" optional default="" defmode "explicit" modedesc="Explicit encryption and MAC keys" modeoption "enckey" e "Encryption key" string optional default="" mode="explicit" modeoption "mackey" m "MAC key" string optional default="" mode="explicit" defmode "asymmetric" modedesc="Explicit ec-p256 private key" modeoption "privkey" s "Private key" string optional default="" mode="asymmetric" yubihsm-shell-2.7.3/yubihsm-auth/README.adoc0000644000175000017500000000304515167357110017502 0ustar aveenaveen== YubiHSM Auth YubiHSM Auth is a command-line tool for the YubiKey HSM Auth application. This is used for storing the authentication keys of a YubiHSM in a YubiKey. === Examples This example shows how to store a new authentication key in the application, then using it with the YubiHSM. First we store the key in a YubiKey, if options are omitted they will be asked for: [source, bash] ---- $ yubihsm-auth -a put --label="default key" --derivation-password="password" --credpwd="my secret" Credential successfully stored ---- Then we authenticate with a YubiHSM (in interactive mode) using the YubiKey: [source, bash] ---- yubihsm> session ykopen 1 "default key" "my secret" trying to connect to reader 'Yubico Yubikey 4 OTP+U2F+CCID 00 00' Created session 0 ---- Alternatively using the command line: [source, bash] ---- $ yubihsm-shell -a get-pseudo-random --ykhsmauth-label="default key" --password="my secret" Session keepalive set up to run every 15 seconds trying to connect to reader 'Yubico Yubikey 4 OTP+U2F+CCID 00 00' Created session 0 06a4d93be9bbcf97891f09979d4297eee335c4ea9526bfb8565baa9239b6359d68d9c636364052bee91a5b1801d6844b88dd3aa1e47f34f2389d841a21398f60ba67507d7f282e8fdc3b7090a2465b3b0358df660f74dd8e9aa5af2c73aadd9d82101c762e558e129703fe44ecb8433537db4d04350141c73ba9d36143afe5264125ec2bfc202d18f73155c34f0e16d45a4ade4a92f17433a6426d4cda6d4b36e831c641be71c561cbeb537e412341b6318810b581b006c29acef3b5bdae157d536d05f4275b86510d6a22c37b352dc148a3400a513dad2a91162795964212b9f361328e5f98fb47ae7ad9e4c4d66ff912d90cb028e15f89d3b8e5d8c3664ed3 ---- yubihsm-shell-2.7.3/yubihsm-auth/cmdline.c0000644000175000017500000007215615167357157017520 0ustar aveenaveen/* File autogenerated by gengetopt version 2.23 generated with the following command: gengetopt -i /home/runner/work/yubihsm-shell/yubihsm-shell/yubihsm-auth/cmdline.ggo --output-dir /home/runner/work/yubihsm-shell/yubihsm-shell/yubihsm-auth cmdline The developers of gengetopt consider the fixed text that goes in all gengetopt output files to be in the public domain: we make no copyright claims on it. */ /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifndef FIX_UNUSED #define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ #endif #include #include "cmdline.h" const char *gengetopt_args_info_purpose = ""; const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { " -h, --help Print help and exit", " -V, --version Print version and exit", " -a, --action=ENUM Action to perform (possible\n values=\"calculate\", \"change-mgmkey\",\n \"delete\", \"list\", \"put\", \"reset\",\n \"retries\", \"version\", \"get-challenge\",\n \"get-pubkey\")", " -k, --mgmkey=STRING Management key is required to put and delete\n credentials. Sometimes, this key is also\n referenced as 'Admin Access Code'\n (default=`00000000000000000000000000000000')", " -K, --new-mgmkey=STRING New management key (default=`')", " -p, --credpwd=STRING Credential password is used to access the\n credential when logging into the YubiHSM2.\n Sometimes, this password is also referenced\n as 'User Access Code' (default=`')", " -l, --label=STRING Credential label (default=`')", " -r, --reader=STRING Only use a matching reader (default=`')", " -t, --touch=ENUM Touch required (possible values=\"off\",\n \"on\" default=`off')", " -c, --context=STRING Session keys calculation context (default=`')", " -v, --verbose[=INT] Print more information (default=`0')", "\n Mode: derivation\n Derive keys from a password using PBKDF2", " -d, --derivation-password=STRING\n Derivation password for encryption and MAC keys\n (default=`')", "\n Mode: explicit\n Explicit encryption and MAC keys", " -e, --enckey=STRING Encryption key (default=`')", " -m, --mackey=STRING MAC key (default=`')", "\n Mode: asymmetric\n Explicit ec-p256 private key", " -s, --privkey=STRING Private key (default=`')", 0 }; typedef enum {ARG_NO , ARG_STRING , ARG_INT , ARG_ENUM } cmdline_parser_arg_type; static void clear_given (struct gengetopt_args_info *args_info); static void clear_args (struct gengetopt_args_info *args_info); static int cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error); const char *cmdline_parser_action_values[] = {"calculate", "change-mgmkey", "delete", "list", "put", "reset", "retries", "version", "get-challenge", "get-pubkey", 0}; /*< Possible values for action. */ const char *cmdline_parser_touch_values[] = {"off", "on", 0}; /*< Possible values for touch. */ static char * gengetopt_strdup (const char *s); static void clear_given (struct gengetopt_args_info *args_info) { args_info->help_given = 0 ; args_info->version_given = 0 ; args_info->action_given = 0 ; args_info->mgmkey_given = 0 ; args_info->new_mgmkey_given = 0 ; args_info->credpwd_given = 0 ; args_info->label_given = 0 ; args_info->reader_given = 0 ; args_info->touch_given = 0 ; args_info->context_given = 0 ; args_info->verbose_given = 0 ; args_info->derivation_password_given = 0 ; args_info->enckey_given = 0 ; args_info->mackey_given = 0 ; args_info->privkey_given = 0 ; args_info->asymmetric_mode_counter = 0 ; args_info->derivation_mode_counter = 0 ; args_info->explicit_mode_counter = 0 ; } static void clear_args (struct gengetopt_args_info *args_info) { FIX_UNUSED (args_info); args_info->action_arg = action__NULL; args_info->action_orig = NULL; args_info->mgmkey_arg = gengetopt_strdup ("00000000000000000000000000000000"); args_info->mgmkey_orig = NULL; args_info->new_mgmkey_arg = gengetopt_strdup (""); args_info->new_mgmkey_orig = NULL; args_info->credpwd_arg = gengetopt_strdup (""); args_info->credpwd_orig = NULL; args_info->label_arg = gengetopt_strdup (""); args_info->label_orig = NULL; args_info->reader_arg = gengetopt_strdup (""); args_info->reader_orig = NULL; args_info->touch_arg = touch_arg_off; args_info->touch_orig = NULL; args_info->context_arg = gengetopt_strdup (""); args_info->context_orig = NULL; args_info->verbose_arg = 0; args_info->verbose_orig = NULL; args_info->derivation_password_arg = gengetopt_strdup (""); args_info->derivation_password_orig = NULL; args_info->enckey_arg = gengetopt_strdup (""); args_info->enckey_orig = NULL; args_info->mackey_arg = gengetopt_strdup (""); args_info->mackey_orig = NULL; args_info->privkey_arg = gengetopt_strdup (""); args_info->privkey_orig = NULL; } static void init_args_info(struct gengetopt_args_info *args_info) { args_info->help_help = gengetopt_args_info_help[0] ; args_info->version_help = gengetopt_args_info_help[1] ; args_info->action_help = gengetopt_args_info_help[2] ; args_info->mgmkey_help = gengetopt_args_info_help[3] ; args_info->new_mgmkey_help = gengetopt_args_info_help[4] ; args_info->credpwd_help = gengetopt_args_info_help[5] ; args_info->label_help = gengetopt_args_info_help[6] ; args_info->reader_help = gengetopt_args_info_help[7] ; args_info->touch_help = gengetopt_args_info_help[8] ; args_info->context_help = gengetopt_args_info_help[9] ; args_info->verbose_help = gengetopt_args_info_help[10] ; args_info->derivation_password_help = gengetopt_args_info_help[12] ; args_info->enckey_help = gengetopt_args_info_help[14] ; args_info->mackey_help = gengetopt_args_info_help[15] ; args_info->privkey_help = gengetopt_args_info_help[17] ; } void cmdline_parser_print_version (void) { printf ("%s %s\n", (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), CMDLINE_PARSER_VERSION); if (strlen(gengetopt_args_info_versiontext) > 0) printf("\n%s\n", gengetopt_args_info_versiontext); } static void print_help_common(void) { size_t len_purpose = strlen(gengetopt_args_info_purpose); size_t len_usage = strlen(gengetopt_args_info_usage); if (len_usage > 0) { printf("%s\n", gengetopt_args_info_usage); } if (len_purpose > 0) { printf("%s\n", gengetopt_args_info_purpose); } if (len_usage || len_purpose) { printf("\n"); } if (strlen(gengetopt_args_info_description) > 0) { printf("%s\n\n", gengetopt_args_info_description); } } void cmdline_parser_print_help (void) { int i = 0; print_help_common(); while (gengetopt_args_info_help[i]) printf("%s\n", gengetopt_args_info_help[i++]); } void cmdline_parser_init (struct gengetopt_args_info *args_info) { clear_given (args_info); clear_args (args_info); init_args_info (args_info); } void cmdline_parser_params_init(struct cmdline_parser_params *params) { if (params) { params->override = 0; params->initialize = 1; params->check_required = 1; params->check_ambiguity = 0; params->print_errors = 1; } } struct cmdline_parser_params * cmdline_parser_params_create(void) { struct cmdline_parser_params *params = (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); cmdline_parser_params_init(params); return params; } static void free_string_field (char **s) { if (*s) { free (*s); *s = 0; } } static void cmdline_parser_release (struct gengetopt_args_info *args_info) { free_string_field (&(args_info->action_orig)); free_string_field (&(args_info->mgmkey_arg)); free_string_field (&(args_info->mgmkey_orig)); free_string_field (&(args_info->new_mgmkey_arg)); free_string_field (&(args_info->new_mgmkey_orig)); free_string_field (&(args_info->credpwd_arg)); free_string_field (&(args_info->credpwd_orig)); free_string_field (&(args_info->label_arg)); free_string_field (&(args_info->label_orig)); free_string_field (&(args_info->reader_arg)); free_string_field (&(args_info->reader_orig)); free_string_field (&(args_info->touch_orig)); free_string_field (&(args_info->context_arg)); free_string_field (&(args_info->context_orig)); free_string_field (&(args_info->verbose_orig)); free_string_field (&(args_info->derivation_password_arg)); free_string_field (&(args_info->derivation_password_orig)); free_string_field (&(args_info->enckey_arg)); free_string_field (&(args_info->enckey_orig)); free_string_field (&(args_info->mackey_arg)); free_string_field (&(args_info->mackey_orig)); free_string_field (&(args_info->privkey_arg)); free_string_field (&(args_info->privkey_orig)); clear_given (args_info); } /** * @param val the value to check * @param values the possible values * @return the index of the matched value: * -1 if no value matched, * -2 if more than one value has matched */ static int check_possible_values(const char *val, const char *values[]) { int i, found, last; size_t len; if (!val) /* otherwise strlen() crashes below */ return -1; /* -1 means no argument for the option */ found = last = 0; for (i = 0, len = strlen(val); values[i]; ++i) { if (strncmp(val, values[i], len) == 0) { ++found; last = i; if (strlen(values[i]) == len) return i; /* exact macth no need to check more */ } } if (found == 1) /* one match: OK */ return last; return (found ? -2 : -1); /* return many values or none matched */ } static void write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) { int found = -1; if (arg) { if (values) { found = check_possible_values(arg, values); } if (found >= 0) fprintf(outfile, "%s=\"%s\" # %s\n", opt, arg, values[found]); else fprintf(outfile, "%s=\"%s\"\n", opt, arg); } else { fprintf(outfile, "%s\n", opt); } } int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) { int i = 0; if (!outfile) { fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); return EXIT_FAILURE; } if (args_info->help_given) write_into_file(outfile, "help", 0, 0 ); if (args_info->version_given) write_into_file(outfile, "version", 0, 0 ); if (args_info->action_given) write_into_file(outfile, "action", args_info->action_orig, cmdline_parser_action_values); if (args_info->mgmkey_given) write_into_file(outfile, "mgmkey", args_info->mgmkey_orig, 0); if (args_info->new_mgmkey_given) write_into_file(outfile, "new-mgmkey", args_info->new_mgmkey_orig, 0); if (args_info->credpwd_given) write_into_file(outfile, "credpwd", args_info->credpwd_orig, 0); if (args_info->label_given) write_into_file(outfile, "label", args_info->label_orig, 0); if (args_info->reader_given) write_into_file(outfile, "reader", args_info->reader_orig, 0); if (args_info->touch_given) write_into_file(outfile, "touch", args_info->touch_orig, cmdline_parser_touch_values); if (args_info->context_given) write_into_file(outfile, "context", args_info->context_orig, 0); if (args_info->verbose_given) write_into_file(outfile, "verbose", args_info->verbose_orig, 0); if (args_info->derivation_password_given) write_into_file(outfile, "derivation-password", args_info->derivation_password_orig, 0); if (args_info->enckey_given) write_into_file(outfile, "enckey", args_info->enckey_orig, 0); if (args_info->mackey_given) write_into_file(outfile, "mackey", args_info->mackey_orig, 0); if (args_info->privkey_given) write_into_file(outfile, "privkey", args_info->privkey_orig, 0); i = EXIT_SUCCESS; return i; } int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) { FILE *outfile; int i = 0; outfile = fopen(filename, "w"); if (!outfile) { fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); return EXIT_FAILURE; } i = cmdline_parser_dump(outfile, args_info); fclose (outfile); return i; } void cmdline_parser_free (struct gengetopt_args_info *args_info) { cmdline_parser_release (args_info); } /** @brief replacement of strdup, which is not standard */ char * gengetopt_strdup (const char *s) { char *result = 0; if (!s) return result; result = (char*)malloc(strlen(s) + 1); if (result == (char*)0) return (char*)0; strcpy(result, s); return result; } int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) { return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); } int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params) { int result; result = cmdline_parser_internal (argc, argv, args_info, params, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) { int result; struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) { FIX_UNUSED (args_info); FIX_UNUSED (prog_name); return EXIT_SUCCESS; } static char *package_name = 0; /** * @brief updates an option * @param field the generic pointer to the field to update * @param orig_field the pointer to the orig field * @param field_given the pointer to the number of occurrence of this option * @param prev_given the pointer to the number of occurrence already seen * @param value the argument for this option (if null no arg was specified) * @param possible_values the possible values for this option (if specified) * @param default_value the default value (in case the option only accepts fixed values) * @param arg_type the type of this option * @param check_ambiguity @see cmdline_parser_params.check_ambiguity * @param override @see cmdline_parser_params.override * @param no_free whether to free a possible previous value * @param multiple_option whether this is a multiple option * @param long_opt the corresponding long option * @param short_opt the corresponding short option (or '-' if none) * @param additional_error possible further error specification */ static int update_arg(void *field, char **orig_field, unsigned int *field_given, unsigned int *prev_given, char *value, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, int check_ambiguity, int override, int no_free, int multiple_option, const char *long_opt, char short_opt, const char *additional_error) { char *stop_char = 0; const char *val = value; int found; char **string_field; FIX_UNUSED (field); stop_char = 0; found = 0; if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) { if (short_opt != '-') fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", package_name, long_opt, short_opt, (additional_error ? additional_error : "")); else fprintf (stderr, "%s: `--%s' option given more than once%s\n", package_name, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } if (possible_values && (found = check_possible_values((value ? value : default_value), possible_values)) < 0) { if (short_opt != '-') fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s' (`-%c')%s\n", package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt, short_opt, (additional_error ? additional_error : "")); else fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s'%s\n", package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } if (field_given && *field_given && ! override) return 0; if (prev_given) (*prev_given)++; if (field_given) (*field_given)++; if (possible_values) val = possible_values[found]; switch(arg_type) { case ARG_INT: if (val) *((int *)field) = strtol (val, &stop_char, 0); break; case ARG_ENUM: if (val) *((int *)field) = found; break; case ARG_STRING: if (val) { string_field = (char **)field; if (!no_free && *string_field) free (*string_field); /* free previous string */ *string_field = gengetopt_strdup (val); } break; default: break; }; /* check numeric conversion */ switch(arg_type) { case ARG_INT: if (val && !(stop_char && *stop_char == '\0')) { fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val); return 1; /* failure */ } break; default: ; }; /* store the original value */ switch(arg_type) { case ARG_NO: break; default: if (value && orig_field) { if (no_free) { *orig_field = value; } else { if (*orig_field) free (*orig_field); /* free previous string */ *orig_field = gengetopt_strdup (value); } } }; return 0; /* OK */ } static int check_modes( int given1[], const char *options1[], int given2[], const char *options2[]) { int i = 0, j = 0, errors = 0; while (given1[i] >= 0) { if (given1[i]) { while (given2[j] >= 0) { if (given2[j]) { ++errors; fprintf(stderr, "%s: option %s conflicts with option %s\n", package_name, options1[i], options2[j]); } ++j; } } ++i; } return errors; } int cmdline_parser_internal ( int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error) { int c; /* Character of the parsed option. */ int error_occurred = 0; struct gengetopt_args_info local_args_info; int override; int initialize; int check_required; int check_ambiguity; package_name = argv[0]; /* TODO: Why is this here? It is not used anywhere. */ override = params->override; FIX_UNUSED(override); initialize = params->initialize; check_required = params->check_required; /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); cmdline_parser_init (&local_args_info); optarg = 0; optind = 0; opterr = params->print_errors; optopt = '?'; while (1) { int option_index = 0; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, { "action", 1, NULL, 'a' }, { "mgmkey", 1, NULL, 'k' }, { "new-mgmkey", 1, NULL, 'K' }, { "credpwd", 1, NULL, 'p' }, { "label", 1, NULL, 'l' }, { "reader", 1, NULL, 'r' }, { "touch", 1, NULL, 't' }, { "context", 1, NULL, 'c' }, { "verbose", 2, NULL, 'v' }, { "derivation-password", 1, NULL, 'd' }, { "enckey", 1, NULL, 'e' }, { "mackey", 1, NULL, 'm' }, { "privkey", 1, NULL, 's' }, { 0, 0, 0, 0 } }; c = getopt_long (argc, argv, "hVa:k:K:p:l:r:t:c:v::d:e:m:s:", long_options, &option_index); if (c == -1) break; /* Exit from `while (1)' loop. */ switch (c) { case 'h': /* Print help and exit. */ cmdline_parser_print_help (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'V': /* Print version and exit. */ cmdline_parser_print_version (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'a': /* Action to perform. */ if (update_arg( (void *)&(args_info->action_arg), &(args_info->action_orig), &(args_info->action_given), &(local_args_info.action_given), optarg, cmdline_parser_action_values, 0, ARG_ENUM, check_ambiguity, override, 0, 0, "action", 'a', additional_error)) goto failure; break; case 'k': /* Management key is required to put and delete credentials. Sometimes, this key is also referenced as 'Admin Access Code'. */ if (update_arg( (void *)&(args_info->mgmkey_arg), &(args_info->mgmkey_orig), &(args_info->mgmkey_given), &(local_args_info.mgmkey_given), optarg, 0, "00000000000000000000000000000000", ARG_STRING, check_ambiguity, override, 0, 0, "mgmkey", 'k', additional_error)) goto failure; break; case 'K': /* New management key. */ if (update_arg( (void *)&(args_info->new_mgmkey_arg), &(args_info->new_mgmkey_orig), &(args_info->new_mgmkey_given), &(local_args_info.new_mgmkey_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "new-mgmkey", 'K', additional_error)) goto failure; break; case 'p': /* Credential password is used to access the credential when logging into the YubiHSM2. Sometimes, this password is also referenced as 'User Access Code'. */ if (update_arg( (void *)&(args_info->credpwd_arg), &(args_info->credpwd_orig), &(args_info->credpwd_given), &(local_args_info.credpwd_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "credpwd", 'p', additional_error)) goto failure; break; case 'l': /* Credential label. */ if (update_arg( (void *)&(args_info->label_arg), &(args_info->label_orig), &(args_info->label_given), &(local_args_info.label_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "label", 'l', additional_error)) goto failure; break; case 'r': /* Only use a matching reader. */ if (update_arg( (void *)&(args_info->reader_arg), &(args_info->reader_orig), &(args_info->reader_given), &(local_args_info.reader_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "reader", 'r', additional_error)) goto failure; break; case 't': /* Touch required. */ if (update_arg( (void *)&(args_info->touch_arg), &(args_info->touch_orig), &(args_info->touch_given), &(local_args_info.touch_given), optarg, cmdline_parser_touch_values, "off", ARG_ENUM, check_ambiguity, override, 0, 0, "touch", 't', additional_error)) goto failure; break; case 'c': /* Session keys calculation context. */ if (update_arg( (void *)&(args_info->context_arg), &(args_info->context_orig), &(args_info->context_given), &(local_args_info.context_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "context", 'c', additional_error)) goto failure; break; case 'v': /* Print more information. */ if (update_arg( (void *)&(args_info->verbose_arg), &(args_info->verbose_orig), &(args_info->verbose_given), &(local_args_info.verbose_given), optarg, 0, "0", ARG_INT, check_ambiguity, override, 0, 0, "verbose", 'v', additional_error)) goto failure; break; case 'd': /* Derivation password for encryption and MAC keys. */ args_info->derivation_mode_counter += 1; if (update_arg( (void *)&(args_info->derivation_password_arg), &(args_info->derivation_password_orig), &(args_info->derivation_password_given), &(local_args_info.derivation_password_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "derivation-password", 'd', additional_error)) goto failure; break; case 'e': /* Encryption key. */ args_info->explicit_mode_counter += 1; if (update_arg( (void *)&(args_info->enckey_arg), &(args_info->enckey_orig), &(args_info->enckey_given), &(local_args_info.enckey_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "enckey", 'e', additional_error)) goto failure; break; case 'm': /* MAC key. */ args_info->explicit_mode_counter += 1; if (update_arg( (void *)&(args_info->mackey_arg), &(args_info->mackey_orig), &(args_info->mackey_given), &(local_args_info.mackey_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "mackey", 'm', additional_error)) goto failure; break; case 's': /* Private key. */ args_info->asymmetric_mode_counter += 1; if (update_arg( (void *)&(args_info->privkey_arg), &(args_info->privkey_orig), &(args_info->privkey_given), &(local_args_info.privkey_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "privkey", 's', additional_error)) goto failure; break; case 0: /* Long option with no short option */ case '?': /* Invalid option. */ /* `getopt_long' already printed an error message. */ goto failure; default: /* bug: option not considered. */ fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); abort (); } /* switch */ } /* while */ if (args_info->asymmetric_mode_counter && args_info->derivation_mode_counter) { int asymmetric_given[] = {args_info->privkey_given, -1}; const char *asymmetric_desc[] = {"--privkey", 0}; int derivation_given[] = {args_info->derivation_password_given, -1}; const char *derivation_desc[] = {"--derivation-password", 0}; error_occurred += check_modes(asymmetric_given, asymmetric_desc, derivation_given, derivation_desc); } if (args_info->asymmetric_mode_counter && args_info->explicit_mode_counter) { int asymmetric_given[] = {args_info->privkey_given, -1}; const char *asymmetric_desc[] = {"--privkey", 0}; int explicit_given[] = {args_info->enckey_given, args_info->mackey_given, -1}; const char *explicit_desc[] = {"--enckey", "--mackey", 0}; error_occurred += check_modes(asymmetric_given, asymmetric_desc, explicit_given, explicit_desc); } if (args_info->derivation_mode_counter && args_info->explicit_mode_counter) { int derivation_given[] = {args_info->derivation_password_given, -1}; const char *derivation_desc[] = {"--derivation-password", 0}; int explicit_given[] = {args_info->enckey_given, args_info->mackey_given, -1}; const char *explicit_desc[] = {"--enckey", "--mackey", 0}; error_occurred += check_modes(derivation_given, derivation_desc, explicit_given, explicit_desc); } FIX_UNUSED(check_required); cmdline_parser_release (&local_args_info); if ( error_occurred ) return (EXIT_FAILURE); return 0; failure: cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } /* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ yubihsm-shell-2.7.3/aes_cmac/0000755000175000017500000000000015167357110015027 5ustar aveenaveenyubihsm-shell-2.7.3/aes_cmac/aes.c0000644000175000017500000003144015167357110015745 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "aes.h" #include "debug_lib.h" #include "../common/insecure_memzero.h" #ifdef _WIN32_BCRYPT #include #endif #ifdef _WIN32_BCRYPT static NTSTATUS init_ctx(aes_context *ctx) { NTSTATUS status = STATUS_SUCCESS; BCRYPT_ALG_HANDLE hAlgCBC = 0; BCRYPT_ALG_HANDLE hAlgECB = 0; DWORD cbKeyObj = 0; DWORD cbData = 0; if (!ctx) { return STATUS_INVALID_PARAMETER; } if (ctx->hAlgCBC) { return STATUS_SUCCESS; } /* clear the context, to "reset" */ insecure_memzero(ctx, sizeof(aes_context)); if (!BCRYPT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAlgCBC, BCRYPT_AES_ALGORITHM, NULL, 0))) { goto cleanup; } if (!BCRYPT_SUCCESS(status = BCryptSetProperty(hAlgCBC, BCRYPT_CHAINING_MODE, (PBYTE) BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0))) { goto cleanup; } if (!BCRYPT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAlgECB, BCRYPT_AES_ALGORITHM, NULL, 0))) { goto cleanup; } if (!BCRYPT_SUCCESS(status = BCryptSetProperty(hAlgECB, BCRYPT_CHAINING_MODE, (PBYTE) BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0))) { goto cleanup; } if (!BCRYPT_SUCCESS(status = BCryptGetProperty(hAlgCBC, BCRYPT_OBJECT_LENGTH, (PBYTE) &cbKeyObj, sizeof(DWORD), &cbData, 0))) { goto cleanup; } ctx->hAlgCBC = hAlgCBC; hAlgCBC = 0; ctx->hAlgECB = hAlgECB; hAlgECB = 0; ctx->cbKeyObj = cbKeyObj; cleanup: if (hAlgCBC) { BCryptCloseAlgorithmProvider(hAlgCBC, 0); } if (hAlgECB) { BCryptCloseAlgorithmProvider(hAlgECB, 0); } return status; } static NTSTATUS import_key(BCRYPT_ALG_HANDLE hAlg, BCRYPT_KEY_HANDLE *phKey, PBYTE *ppbKeyObj, DWORD cbKeyObj, const uint8_t *key, size_t key_len) { NTSTATUS status = STATUS_SUCCESS; PBYTE pbKeyObj = NULL; BCRYPT_KEY_HANDLE hKey = 0; PBYTE pbKeyBlob = NULL; DWORD cbKeyBlob = 0; if (!phKey || !ppbKeyObj) { return STATUS_INVALID_PARAMETER; } /* close existing key first */ if (*phKey) { BCryptDestroyKey(*phKey); *phKey = 0; } /* free existing key object */ if (*ppbKeyObj) { free(*ppbKeyObj); *ppbKeyObj = NULL; } /* allocate new key object */ if (!(pbKeyObj = (PBYTE) malloc(cbKeyObj))) { status = STATUS_NO_MEMORY; goto cleanup; } cbKeyBlob = (DWORD) (sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key_len); if (!(pbKeyBlob = (PBYTE) malloc(cbKeyBlob))) { status = STATUS_NO_MEMORY; goto cleanup; } /* set up BCrypt Key Blob for import */ ((BCRYPT_KEY_DATA_BLOB_HEADER *) pbKeyBlob)->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; ((BCRYPT_KEY_DATA_BLOB_HEADER *) pbKeyBlob)->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; ((BCRYPT_KEY_DATA_BLOB_HEADER *) pbKeyBlob)->cbKeyData = (DWORD) key_len; memcpy(pbKeyBlob + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), key, key_len); if (!BCRYPT_SUCCESS(status = BCryptImportKey(hAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey, pbKeyObj, cbKeyObj, pbKeyBlob, cbKeyBlob, 0))) { goto cleanup; } /* set output params */ *phKey = hKey; hKey = 0; *ppbKeyObj = pbKeyObj; pbKeyObj = 0; cleanup: if (hKey) { BCryptDestroyKey(hKey); } if (pbKeyObj) { free(pbKeyObj); } if (pbKeyBlob) { free(pbKeyBlob); } return !BCRYPT_SUCCESS(status); } #else static const EVP_CIPHER *aes_ecb(uint16_t key_len) { switch (key_len) { case 16: return EVP_aes_128_ecb(); case 24: return EVP_aes_192_ecb(); case 32: return EVP_aes_256_ecb(); default: return NULL; } } static const EVP_CIPHER *aes_cbc(uint16_t key_len) { switch (key_len) { case 16: return EVP_aes_128_cbc(); case 24: return EVP_aes_192_cbc(); case 32: return EVP_aes_256_cbc(); default: return NULL; } } static int ossl_err_cb(const char *str, size_t len, void *u) { (void)len; (void)u; DBG_ERR("%s %s", (const char*)u, str); return 1; } static void DBG_OSSL(const char *str, int err) { DBG_ERR("%s: %d OSSL error stack begin", str, err); ERR_print_errors_cb(ossl_err_cb, (void*)str); DBG_ERR("%s: OSSL error stack end", str); } static int aes_encrypt_ex(const EVP_CIPHER *cipher, const uint8_t *in, uint8_t *out, uint16_t len, const uint8_t *iv, aes_context *ctx) { int err; if ((err = EVP_EncryptInit_ex(ctx->ctx, cipher, NULL, ctx->key, iv)) <= 0) { DBG_OSSL("aes_encrypt_ex EVP_EncryptInit_ex", err); return -1; } if ((err = EVP_CIPHER_CTX_set_padding(ctx->ctx, 0)) <= 0) { DBG_OSSL("aes_encrypt_ex EVP_CIPHER_CTX_set_padding", err); return -2; } int update_len = len; if ((err = EVP_EncryptUpdate(ctx->ctx, out, &update_len, in, len)) <= 0) { DBG_OSSL("aes_encrypt_ex EVP_EncryptUpdate", err); return -3; } int final_len = len - update_len; if ((err = EVP_EncryptFinal_ex(ctx->ctx, out + update_len, &final_len)) <= 0) { DBG_OSSL("aes_encrypt_ex EVP_EncryptFinal_ex", err); return -4; } if (update_len + final_len != len) { DBG_ERR("update_len + final_len != len"); return -5; } return 0; } static int aes_decrypt_ex(const EVP_CIPHER *cipher, const uint8_t *in, uint8_t *out, uint16_t len, const uint8_t *iv, aes_context *ctx) { int err; if ((err = EVP_DecryptInit_ex(ctx->ctx, cipher, NULL, ctx->key, iv)) != 1) { DBG_OSSL("aes_encrypt_ex EVP_DecryptInit_ex", err); return -1; } if ((err = EVP_CIPHER_CTX_set_padding(ctx->ctx, 0)) != 1) { DBG_OSSL("aes_decrypt_ex EVP_CIPHER_CTX_set_padding", err); return -2; } int update_len = len; if ((err = EVP_DecryptUpdate(ctx->ctx, out, &update_len, in, len)) != 1) { DBG_OSSL("aes_decrypt_ex EVP_DecryptUpdate", err); return -3; } int final_len = len - update_len; if ((err = EVP_DecryptFinal_ex(ctx->ctx, out + update_len, &final_len)) != 1) { DBG_OSSL("aes_decrypt_ex EVP_DecryptFinal_ex", err); return -4; } if (update_len + final_len != len) { DBG_ERR("update_len + final_len != len"); return -5; } return 0; } #endif int aes_set_key(const uint8_t *key, uint16_t key_len, aes_context *ctx) { #ifdef _WIN32_BCRYPT NTSTATUS status = STATUS_SUCCESS; if (!BCRYPT_SUCCESS(status = init_ctx(ctx))) { return -1; } if (!BCRYPT_SUCCESS(status = import_key(ctx->hAlgCBC, &(ctx->hKeyCBC), &(ctx->pbKeyCBCObj), ctx->cbKeyObj, key, key_len))) { return -2; } if (!BCRYPT_SUCCESS(status = import_key(ctx->hAlgECB, &(ctx->hKeyECB), &(ctx->pbKeyECBObj), ctx->cbKeyObj, key, key_len))) { return -3; } #else if (key == NULL || aes_ecb(key_len) == NULL) { return -1; } if (!ctx->ctx) { ctx->ctx = EVP_CIPHER_CTX_new(); if (!ctx->ctx) { DBG_OSSL("aes_set_key EVP_CIPHER_CTX_new", 0); return -2; } } ctx->key_len = key_len; memcpy(ctx->key, key, key_len); #endif return 0; } int aes_load_key(const char *key, aes_context *ctx) { #ifdef _WIN32_BCRYPT (void) key; (void) ctx; return -1; #else const uint8_t default_enc[] = {0x09, 0x0b, 0x47, 0xdb, 0xed, 0x59, 0x56, 0x54, 0x90, 0x1d, 0xee, 0x1c, 0xc6, 0x55, 0xe4, 0x20}; const uint8_t default_mac[] = {0x59, 0x2f, 0xd4, 0x83, 0xf7, 0x59, 0xe2, 0x99, 0x09, 0xa0, 0x4c, 0x45, 0x05, 0xd2, 0xce, 0x0a}; ctx->key_len = sizeof(default_enc); if (key == NULL || aes_ecb(ctx->key_len) == NULL) { return -1; } if (!ctx->ctx) { ctx->ctx = EVP_CIPHER_CTX_new(); if (!ctx->ctx) { DBG_OSSL("aes_load_key EVP_CIPHER_CTX_new", 0); return -2; } } if (!strcmp(key, "default_enc")) memcpy(ctx->key, default_enc, ctx->key_len); else if (!strcmp(key, "default_mac")) memcpy(ctx->key, default_mac, ctx->key_len); else memset(ctx->key, 0, ctx->key_len); return 0; #endif } int aes_encrypt(const uint8_t *in, uint8_t *out, aes_context *ctx) { #ifdef _WIN32_BCRYPT NTSTATUS status = STATUS_SUCCESS; ULONG cbResult = 0; if (!BCRYPT_SUCCESS(status = BCryptEncrypt(ctx->hKeyECB, (PUCHAR) in, AES_BLOCK_SIZE, NULL, NULL, 0, out, AES_BLOCK_SIZE, &cbResult, 0))) { return -1; } if (cbResult != AES_BLOCK_SIZE) { return -2; } return 0; #else return aes_encrypt_ex(aes_ecb(ctx->key_len), in, out, AES_BLOCK_SIZE, NULL, ctx); #endif } int aes_decrypt(const uint8_t *in, uint8_t *out, aes_context *ctx) { #ifdef _WIN32_BCRYPT NTSTATUS status = STATUS_SUCCESS; ULONG cbResult = 0; if (!BCRYPT_SUCCESS(status = BCryptDecrypt(ctx->hKeyECB, (PUCHAR) in, AES_BLOCK_SIZE, NULL, NULL, 0, out, AES_BLOCK_SIZE, &cbResult, 0))) { return -1; } if (cbResult != AES_BLOCK_SIZE) { return -2; } return 0; #else return aes_decrypt_ex(aes_ecb(ctx->key_len), in, out, AES_BLOCK_SIZE, NULL, ctx); #endif } int aes_cbc_encrypt(const uint8_t *in, uint8_t *out, uint16_t len, const uint8_t *iv, aes_context *ctx) { #ifdef _WIN32_BCRYPT NTSTATUS status = STATUS_SUCCESS; ULONG cbResult = 0; UCHAR _iv[AES_BLOCK_SIZE]; memcpy(_iv, iv, AES_BLOCK_SIZE); if (!BCRYPT_SUCCESS(status = BCryptEncrypt(ctx->hKeyCBC, (PUCHAR) in, len, NULL, _iv, AES_BLOCK_SIZE, out, len, &cbResult, 0))) { return -1; } if (cbResult != len) { return -2; } return 0; #else return aes_encrypt_ex(aes_cbc(ctx->key_len), in, out, len, iv, ctx); #endif } int aes_cbc_decrypt(const uint8_t *in, uint8_t *out, uint16_t len, const uint8_t *iv, aes_context *ctx) { #ifdef _WIN32_BCRYPT NTSTATUS status = STATUS_SUCCESS; ULONG cbResult = 0; UCHAR _iv[AES_BLOCK_SIZE]; memcpy(_iv, iv, AES_BLOCK_SIZE); if (!BCRYPT_SUCCESS(status = BCryptDecrypt(ctx->hKeyCBC, (PUCHAR) in, len, NULL, _iv, AES_BLOCK_SIZE, out, len, &cbResult, 0))) { return -1; } if (cbResult != len) { return -2; } return 0; #else return aes_decrypt_ex(aes_cbc(ctx->key_len), in, out, len, iv, ctx); #endif } int aes_add_padding(uint8_t *in, uint16_t max_len, uint16_t *len) { uint16_t new_len = *len; if (in) { if (new_len >= max_len) { return -1; } in[new_len] = 0x80; } new_len++; while (new_len % AES_BLOCK_SIZE != 0) { if (in) { if (new_len >= max_len) { return -2; } in[new_len] = 0x00; } new_len++; } *len = new_len; return 0; } void aes_remove_padding(uint8_t *in, uint16_t *len) { while ((*len) > 1 && in[(*len) - 1] == 0) { (*len)--; } if (*len > 0) (*len)--; } void aes_destroy(aes_context *ctx) { if (!ctx) { return; } #ifdef _WIN32_BCRYPT if (ctx->hKeyCBC) { BCryptDestroyKey(ctx->hKeyCBC); } if (ctx->pbKeyCBCObj) { free(ctx->pbKeyCBCObj); } if (ctx->hKeyECB) { BCryptDestroyKey(ctx->hKeyECB); } if (ctx->pbKeyECBObj) { free(ctx->pbKeyECBObj); } if (ctx->hAlgCBC) { BCryptCloseAlgorithmProvider(ctx->hAlgCBC, 0); } if (ctx->hAlgECB) { BCryptCloseAlgorithmProvider(ctx->hAlgECB, 0); } #else EVP_CIPHER_CTX_free(ctx->ctx); #endif insecure_memzero(ctx, sizeof(aes_context)); } yubihsm-shell-2.7.3/aes_cmac/aes.h0000644000175000017500000000444415167357110015756 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* aes.h ** ** Defines the AES crypto module for CMAC */ #ifndef _AESCMAC_AES_H_ #define _AESCMAC_AES_H_ #include #include "../common/platform-config.h" #ifdef _WIN32_BCRYPT #include #include #include #else #include #include #endif #ifndef AES_BLOCK_SIZE // Defined in openssl/aes.h #define AES_BLOCK_SIZE 16 #endif #ifdef __cplusplus extern "C" { #endif typedef struct { #ifdef _WIN32_BCRYPT BCRYPT_ALG_HANDLE hAlgCBC; BCRYPT_ALG_HANDLE hAlgECB; BCRYPT_KEY_HANDLE hKeyCBC; BCRYPT_KEY_HANDLE hKeyECB; PBYTE pbKeyCBCObj; PBYTE pbKeyECBObj; size_t cbKeyObj; #else EVP_CIPHER_CTX *ctx; uint16_t key_len; uint8_t key[32]; #endif } aes_context; #ifndef __WIN32 #define YH_INTERNAL __attribute__((visibility("hidden"))) #else #define YH_INTERNAL #endif int YH_INTERNAL aes_load_key(const char *key, aes_context *ctx); int YH_INTERNAL aes_set_key(const uint8_t *key, uint16_t key_len, aes_context *ctx); int YH_INTERNAL aes_encrypt(const uint8_t *in, uint8_t *out, aes_context *ctx); int YH_INTERNAL aes_decrypt(const uint8_t *in, uint8_t *out, aes_context *ctx); int YH_INTERNAL aes_cbc_encrypt(const uint8_t *in, uint8_t *out, uint16_t len, const uint8_t *iv, aes_context *ctx); int YH_INTERNAL aes_cbc_decrypt(const uint8_t *in, uint8_t *out, uint16_t len, const uint8_t *iv, aes_context *ctx); int YH_INTERNAL aes_add_padding(uint8_t *in, uint16_t max_len, uint16_t *len); void YH_INTERNAL aes_remove_padding(uint8_t *in, uint16_t *len); void YH_INTERNAL aes_destroy(aes_context *ctx); #ifdef __cplusplus } #endif #endif /* _AESCMAC_AES_H_ */ yubihsm-shell-2.7.3/aes_cmac/aes_cmac.c0000644000175000017500000000603315167357110016730 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // AES-CMAC implementation as defined in SP-800-38B // AES key length can be one of 128, 192, 256 // Output length is one full block (16 bytes) #include #include #include #include "aes_cmac.h" #include "../common/insecure_memzero.h" static const uint8_t zero[AES_BLOCK_SIZE] = {0}; static void do_pad(uint8_t *data, uint8_t len) { for (uint8_t i = len; i < AES_BLOCK_SIZE; i++) if (i == len) data[i] = 0x80; else data[i] = 0x00; } static void do_xor(const uint8_t *a, uint8_t *b) { for (uint8_t i = 0; i < AES_BLOCK_SIZE; i++) { b[i] ^= a[i]; } } static void do_shift_one_bit_left(const uint8_t *a, uint8_t *b, uint8_t *carry) { for (int8_t i = AES_BLOCK_SIZE - 1; i >= 0; i--) { b[i] = (a[i] << 1) | *carry; *carry = a[i] >> 7; } } static void cmac_generate_subkey(const uint8_t *key, uint8_t *subkey) { uint8_t carry = 0; do_shift_one_bit_left(key, subkey, &carry); subkey[AES_BLOCK_SIZE - 1] ^= 0x87 >> (8 - (carry * 8)); } int aes_cmac_encrypt(aes_cmac_context_t *ctx, const uint8_t *message, const uint16_t message_len, uint8_t *mac) { uint8_t M[AES_BLOCK_SIZE] = {0}; const uint8_t *ptr = message; memcpy(mac, zero, AES_BLOCK_SIZE); uint8_t n_blocks; if (message_len == 0) n_blocks = 0; else n_blocks = (message_len + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE - 1; for (uint8_t i = 0; i < n_blocks; i++) { int rc = aes_cbc_encrypt(ptr, mac, AES_BLOCK_SIZE, mac, ctx->aes_ctx); if (rc) { return rc; } ptr += AES_BLOCK_SIZE; } uint8_t remaining_bytes = (message_len % AES_BLOCK_SIZE); if (remaining_bytes == 0) { if (message != NULL && message_len != 0) { memcpy(M, ptr, AES_BLOCK_SIZE); do_xor(ctx->k1, M); } else { do_pad(M, 0); do_xor(ctx->k2, M); } } else { memcpy(M, ptr, remaining_bytes); do_pad(M, remaining_bytes); do_xor(ctx->k2, M); } return aes_cbc_encrypt(M, mac, AES_BLOCK_SIZE, mac, ctx->aes_ctx); } int aes_cmac_init(aes_context *aes_ctx, aes_cmac_context_t *ctx) { uint8_t L[AES_BLOCK_SIZE] = {0}; ctx->aes_ctx = aes_ctx; int rc = aes_encrypt(zero, L, ctx->aes_ctx); if (rc) { return rc; } cmac_generate_subkey(L, ctx->k1); cmac_generate_subkey(ctx->k1, ctx->k2); return 0; } void aes_cmac_destroy(aes_cmac_context_t *ctx) { if (ctx) { insecure_memzero(ctx, sizeof(aes_cmac_context_t)); } } yubihsm-shell-2.7.3/aes_cmac/tests/0000755000175000017500000000000015167357110016171 5ustar aveenaveenyubihsm-shell-2.7.3/aes_cmac/tests/aes_cmac_tests.c0000644000175000017500000002161215167357110021314 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "../aes_cmac.h" #define asrt(c, e, m) _asrt(__LINE__, c, e, m); static void _asrt(int line, int check, int expected, unsigned char *msg) { if (check == expected) return; fprintf(stderr, "<%s>:%d check failed with value %d (0x%x), expected %d (0x%x)\n", msg, line, check, check, expected, expected); exit(EXIT_FAILURE); } int main() { aes_context aes = {0}; aes_cmac_context_t ctx = {0}; uint8_t mac[AES_BLOCK_SIZE]; uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}; uint8_t k_128[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; uint8_t k_192[] = {0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b}; uint8_t k_256[] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; uint8_t mac1[] = {0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46}; uint8_t mac2[] = {0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c}; uint8_t mac3[] = {0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27}; uint8_t mac4[] = {0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe}; uint8_t mac5[] = {0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67}; uint8_t mac6[] = {0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84}; uint8_t mac7[] = {0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e}; uint8_t mac8[] = {0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11}; uint8_t mac9[] = {0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83}; uint8_t mac10[] = {0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c}; uint8_t mac11[] = {0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6}; uint8_t mac12[] = {0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10}; aes_set_key(k_128, sizeof(k_128), &aes); aes_cmac_init(&aes, &ctx); aes_cmac_encrypt(&ctx, m, 0, mac); asrt(memcmp(mac, mac1, 16), 0, (unsigned char *) "MAC1"); aes_cmac_encrypt(&ctx, m, 16, mac); asrt(memcmp(mac, mac2, 16), 0, (unsigned char *) "MAC2"); aes_cmac_encrypt(&ctx, m, 40, mac); asrt(memcmp(mac, mac3, 16), 0, (unsigned char *) "MAC3"); aes_cmac_encrypt(&ctx, m, 64, mac); asrt(memcmp(mac, mac4, 16), 0, (unsigned char *) "MAC4"); aes_cmac_destroy(&ctx); aes_destroy(&aes); aes_set_key(k_192, sizeof(k_192), &aes); aes_cmac_init(&aes, &ctx); aes_cmac_encrypt(&ctx, m, 0, mac); asrt(memcmp(mac, mac5, 16), 0, (unsigned char *) "MAC5"); aes_cmac_encrypt(&ctx, m, 16, mac); asrt(memcmp(mac, mac6, 16), 0, (unsigned char *) "MAC6"); aes_cmac_encrypt(&ctx, m, 40, mac); asrt(memcmp(mac, mac7, 16), 0, (unsigned char *) "MAC7"); aes_cmac_encrypt(&ctx, m, 64, mac); asrt(memcmp(mac, mac8, 16), 0, (unsigned char *) "MAC8"); aes_cmac_destroy(&ctx); aes_destroy(&aes); aes_set_key(k_256, sizeof(k_256), &aes); aes_cmac_init(&aes, &ctx); aes_cmac_encrypt(&ctx, m, 0, mac); asrt(memcmp(mac, mac9, 16), 0, (unsigned char *) "MAC9"); aes_cmac_encrypt(&ctx, m, 16, mac); asrt(memcmp(mac, mac10, 16), 0, (unsigned char *) "MAC10"); aes_cmac_encrypt(&ctx, m, 40, mac); asrt(memcmp(mac, mac11, 16), 0, (unsigned char *) "MAC11"); aes_cmac_encrypt(&ctx, m, 64, mac); asrt(memcmp(mac, mac12, 16), 0, (unsigned char *) "MAC12"); aes_cmac_destroy(&ctx); aes_destroy(&aes); // Padding tests uint8_t a[48]; uint16_t l; l = 3; memset(a, 0xab, 48); aes_add_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00", 16), 0, (unsigned char *) "PADDING 1a"); asrt(l, 16, (unsigned char *) "PADDING 1b"); aes_remove_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab", 3), 0, (unsigned char *) "PADDING 1c"); asrt(l, 3, (unsigned char *) "PADDING 1d"); fprintf(stderr, "\n"); l = 15; memset(a, 0xab, 48); aes_add_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\x80", 16), 0, (unsigned char *) "PADDING 2a"); asrt(l, 16, (unsigned char *) "PADDING 2b"); aes_remove_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\xab", 15), 0, (unsigned char *) "PADDING 2c"); asrt(l, 15, (unsigned char *) "PADDING 2d"); fprintf(stderr, "\n"); l = 16; memset(a, 0xab, 48); aes_add_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\xab\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00", 32), 0, (unsigned char *) "PADDING 3a"); asrt(l, 32, (unsigned char *) "PADDING 3b"); aes_remove_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\xab", 16), 0, (unsigned char *) "PADDING 3c"); asrt(l, 16, (unsigned char *) "PADDING 3d"); fprintf(stderr, "\n"); l = 19; memset(a, 0xab, 48); aes_add_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\xab\xab\xab\xab\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00", 32), 0, (unsigned char *) "PADDING 4a"); asrt(l, 32, (unsigned char *) "PADDING 4b"); aes_remove_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\xab\xab\xab\xab", 19), 0, (unsigned char *) "PADDING 4c"); asrt(l, 19, (unsigned char *) "PADDING 4d"); fprintf(stderr, "\n"); l = 32; memset(a, 0xab, 48); aes_add_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\xab\xab\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00", 48), 0, (unsigned char *) "PADDING 5a"); asrt(l, 48, (unsigned char *) "PADDING 5b"); aes_remove_padding(a, &l); asrt(memcmp(a, "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab\xab" "\xab\xab", 32), 0, (unsigned char *) "PADDING 5c"); asrt(l, 32, (unsigned char *) "PADDING 5d"); fprintf(stderr, "\n"); l = 0; memset(a, 0xab, 48); aes_add_padding(a, &l); asrt(memcmp(a, "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00", 16), 0, (unsigned char *) "PADDING 6a"); asrt(l, 16, (unsigned char *) "PADDING 6b"); aes_remove_padding(a, &l); asrt(memcmp(a, "", 0), 0, (unsigned char *) "PADDING 6c"); asrt(l, 0, (unsigned char *) "PADDING 6d"); fprintf(stderr, "\n"); return EXIT_SUCCESS; } yubihsm-shell-2.7.3/aes_cmac/aes_cmac.h0000644000175000017500000000222615167357110016735 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "aes.h" typedef struct { aes_context *aes_ctx; uint8_t k1[AES_BLOCK_SIZE]; uint8_t k2[AES_BLOCK_SIZE]; } aes_cmac_context_t; #ifndef __WIN32 #define YH_INTERNAL __attribute__((visibility("hidden"))) #else #define YH_INTERNAL #endif int YH_INTERNAL aes_cmac_init(aes_context *aes_ctx, aes_cmac_context_t *ctx); int YH_INTERNAL aes_cmac_encrypt(aes_cmac_context_t *ctx, const uint8_t *message, const uint16_t message_len, uint8_t *mac); void YH_INTERNAL aes_cmac_destroy(aes_cmac_context_t *ctx); yubihsm-shell-2.7.3/yhwrap/0000755000175000017500000000000015167357170014614 5ustar aveenaveenyubihsm-shell-2.7.3/yhwrap/cmdline.h0000644000175000017500000002143015167357170016400 0ustar aveenaveen/** @file cmdline.h * @brief The header file for the command line option parser * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten * @author GNU Gengetopt */ #ifndef CMDLINE_H #define CMDLINE_H /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* for FILE */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef CMDLINE_PARSER_PACKAGE /** @brief the program name (used for printing errors) */ #define CMDLINE_PARSER_PACKAGE PACKAGE #endif #ifndef CMDLINE_PARSER_PACKAGE_NAME /** @brief the complete program name (used for help and version) */ #ifdef PACKAGE_NAME #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE_NAME #else #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE #endif #endif #ifndef CMDLINE_PARSER_VERSION /** @brief the program version */ #define CMDLINE_PARSER_VERSION VERSION #endif /** @brief Where the command line options are stored */ struct gengetopt_args_info { const char *help_help; /**< @brief Print help and exit help description. */ const char *version_help; /**< @brief Print version and exit help description. */ char * algorithm_arg; /**< @brief Object algorithm. */ char * algorithm_orig; /**< @brief Object algorithm original value given at command line. */ const char *algorithm_help; /**< @brief Object algorithm help description. */ char * capabilities_arg; /**< @brief Object capabilities. */ char * capabilities_orig; /**< @brief Object capabilities original value given at command line. */ const char *capabilities_help; /**< @brief Object capabilities help description. */ char * delegated_arg; /**< @brief Object delegates capabilities. */ char * delegated_orig; /**< @brief Object delegates capabilities original value given at command line. */ const char *delegated_help; /**< @brief Object delegates capabilities help description. */ char * domains_arg; /**< @brief Object domains. */ char * domains_orig; /**< @brief Object domains original value given at command line. */ const char *domains_help; /**< @brief Object domains help description. */ short id_arg; /**< @brief Object ID (default='0'). */ char * id_orig; /**< @brief Object ID original value given at command line. */ const char *id_help; /**< @brief Object ID help description. */ char * in_arg; /**< @brief Input data (filename). */ char * in_orig; /**< @brief Input data (filename) original value given at command line. */ const char *in_help; /**< @brief Input data (filename) help description. */ char * out_arg; /**< @brief Output data (filename). */ char * out_orig; /**< @brief Output data (filename) original value given at command line. */ const char *out_help; /**< @brief Output data (filename) help description. */ char * label_arg; /**< @brief Object label. */ char * label_orig; /**< @brief Object label original value given at command line. */ const char *label_help; /**< @brief Object label help description. */ char * wrapkey_arg; /**< @brief Key to wrap data with (filename). */ char * wrapkey_orig; /**< @brief Key to wrap data with (filename) original value given at command line. */ const char *wrapkey_help; /**< @brief Key to wrap data with (filename) help description. */ unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ unsigned int algorithm_given ; /**< @brief Whether algorithm was given. */ unsigned int capabilities_given ; /**< @brief Whether capabilities was given. */ unsigned int delegated_given ; /**< @brief Whether delegated was given. */ unsigned int domains_given ; /**< @brief Whether domains was given. */ unsigned int id_given ; /**< @brief Whether id was given. */ unsigned int in_given ; /**< @brief Whether in was given. */ unsigned int out_given ; /**< @brief Whether out was given. */ unsigned int label_given ; /**< @brief Whether label was given. */ unsigned int wrapkey_given ; /**< @brief Whether wrapkey was given. */ } ; /** @brief The additional parameters to pass to parser functions */ struct cmdline_parser_params { int override; /**< @brief whether to override possibly already present options (default 0) */ int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ int check_required; /**< @brief whether to check that all required options were provided (default 1) */ int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ } ; /** @brief the purpose string of the program */ extern const char *gengetopt_args_info_purpose; /** @brief the usage string of the program */ extern const char *gengetopt_args_info_usage; /** @brief the description string of the program */ extern const char *gengetopt_args_info_description; /** @brief all the lines making the help output */ extern const char *gengetopt_args_info_help[]; /** * The command line parser * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info); /** * The command line parser (version with additional parameters - deprecated) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_ext() instead */ int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required); /** * The command line parser (version with additional parameters) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params); /** * Save the contents of the option struct into an already open FILE stream. * @param outfile the stream where to dump options * @param args_info the option struct to dump * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info); /** * Save the contents of the option struct into a (text) file. * This file can be read by the config file parser (if generated by gengetopt) * @param filename the file where to save * @param args_info the option struct to save * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info); /** * Print the help */ void cmdline_parser_print_help(void); /** * Print the version */ void cmdline_parser_print_version(void); /** * Initializes all the fields a cmdline_parser_params structure * to their default values * @param params the structure to initialize */ void cmdline_parser_params_init(struct cmdline_parser_params *params); /** * Allocates dynamically a cmdline_parser_params structure and initializes * all its fields to their default values * @return the created and initialized cmdline_parser_params structure */ struct cmdline_parser_params *cmdline_parser_params_create(void); /** * Initializes the passed gengetopt_args_info structure's fields * (also set default values for options that have a default) * @param args_info the structure to initialize */ void cmdline_parser_init (struct gengetopt_args_info *args_info); /** * Deallocates the string fields of the gengetopt_args_info structure * (but does not deallocate the structure itself) * @param args_info the structure to deallocate */ void cmdline_parser_free (struct gengetopt_args_info *args_info); /** * Checks that all the required options were specified * @param args_info the structure to check * @param prog_name the name of the program that will be used to print * possible errors * @return */ int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* CMDLINE_H */ yubihsm-shell-2.7.3/yhwrap/main.c0000644000175000017500000003006115167357110015676 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "../common/platform-config.h" #ifdef __WIN32 #include #else #include #endif #include #include #include "cmdline.h" #include "parsing.h" #include "pkcs5.h" #include "util.h" #include uint8_t _yh_verbosity = YH_VERB_ALL; FILE *_yh_output; #define INPUT_BUFSIZE 4096 #define WRAPKEY_BUFSIZE 32 #define OBJECT_HEADER_SIZE 59 static bool wrap_data(uint8_t *key, size_t key_len, uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { EVP_CIPHER_CTX *ctx = NULL; const EVP_CIPHER *cipher_type; uint8_t nonce[13]; int nonce_len = 13; int tag_len = 16; int len; ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { return false; } switch (key_len) { case 16: cipher_type = EVP_aes_128_ccm(); break; case 24: cipher_type = EVP_aes_192_ccm(); break; case 32: cipher_type = EVP_aes_256_ccm(); break; default: return false; } if (RAND_bytes(nonce, nonce_len) != 1) { return false; } memcpy(out, nonce, nonce_len); // Select cipher if (EVP_EncryptInit_ex(ctx, cipher_type, NULL, NULL, NULL) != 1) { return false; } // Set nonce length if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, nonce_len, NULL) != 1) { return false; } // Set tag length if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL) != 1) { return false; } // Initialize key and IV if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce) != 1) { return false; } // Provide the total plaintext length if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, in_len) != 1) { return false; } // Provide the message to be encrypted, and obtain the encrypted output if (EVP_EncryptUpdate(ctx, out + nonce_len, &len, in, in_len) != 1) { return false; } *out_len = len; // Finalize the encryption if (EVP_EncryptFinal_ex(ctx, out + nonce_len + *out_len, &len) != 1) { return false; } *out_len += len; // Get the tag if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, tag_len, out + nonce_len + *out_len) != 1) { return false; } *out_len += tag_len; *out_len += nonce_len; // Clean up EVP_CIPHER_CTX_free(ctx); return true; } static void format_header(yh_algorithm wrapkey_algorithm, yh_capabilities capabilities, uint16_t id, uint16_t data_len, uint16_t domains, yh_object_type type, yh_algorithm algorithm, uint8_t *label, uint8_t *header) { *header = (uint8_t) wrapkey_algorithm; header++; memcpy(header, capabilities.capabilities, YH_CAPABILITIES_LEN); header += YH_CAPABILITIES_LEN; *((uint16_t *) header) = htons(id); header += sizeof(uint16_t); *((uint16_t *) header) = htons(data_len); header += sizeof(uint16_t); *((uint16_t *) header) = htons(domains); header += sizeof(uint16_t); *header = (uint8_t) type; header++; *header = (uint8_t) algorithm; header++; *header = 0x00; // Sequence header++; *header = 0x02; // Origin header++; memcpy(header, label, YH_OBJ_LABEL_LEN); header += YH_OBJ_LABEL_LEN; } static FILE *open_file(const char *name, bool input) { if (input) { if (strcmp(name, "-") == 0) { return stdin; } else { return fopen(name, "rb"); } } else { if (strcmp(name, "-") == 0) { return stdout; } else { return fopen(name, "wb"); } } } static void dump_hex(const unsigned char *buf, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) { if (i && !(i % 32)) fprintf(stderr, "\n"); else if (i && !(i % 8)) fprintf(stderr, " "); fprintf(stderr, "%02x", buf[i]); } fprintf(stderr, "\n"); } int main(int argc, char *argv[]) { struct gengetopt_args_info args_info; int rc = EXIT_FAILURE; yh_rc yhrc; FILE *input_file = NULL; FILE *output_file = NULL; FILE *wrapkey_file = NULL; #pragma pack(push, 1) union { struct { uint8_t header[OBJECT_HEADER_SIZE]; uint8_t body[INPUT_BUFSIZE]; }; uint8_t buf[1]; } wrap_object = {{{0}, {0}}}; #pragma pack(pop) size_t wrap_object_len = sizeof(wrap_object.body); if (cmdline_parser(argc, argv, &args_info) != 0) { goto main_exit; } yh_algorithm algorithm; yhrc = yh_string_to_algo(args_info.algorithm_arg, &algorithm); if (yhrc != YHR_SUCCESS) { fprintf(stderr, "Unable to parse algorithm: %s\n", yh_strerror(yhrc)); goto main_exit; } yh_capabilities capabilities = {{0}}; yhrc = yh_string_to_capabilities(args_info.capabilities_arg, &capabilities); if (yhrc != YHR_SUCCESS) { fprintf(stderr, "Unable to parse capabilities: %s\n", yh_strerror(yhrc)); goto main_exit; } uint16_t domains; yhrc = yh_string_to_domains(args_info.domains_arg, &domains); if (yhrc != YHR_SUCCESS) { fprintf(stderr, "Unable to parse domains: %s\n", yh_strerror(yhrc)); goto main_exit; } uint16_t id = args_info.id_arg; uint8_t label[YH_OBJ_LABEL_LEN] = {0}; size_t label_len = strlen(args_info.label_arg); if (label_len > YH_OBJ_LABEL_LEN) { fprintf(stderr, "Unable to parse label: label too long, maximum length is %d\n", YH_OBJ_LABEL_LEN); goto main_exit; } memcpy(label, args_info.label_arg, label_len); yh_object_type type; if (algo2type(algorithm, &type) == false) { fprintf(stderr, "Invalid algorithm\n"); goto main_exit; } yh_capabilities delegated = {{0}}; bool has_delegated = ((type == YH_AUTHENTICATION_KEY || type == YH_WRAP_KEY) ? true : false); if (has_delegated == true) { if (!args_info.delegated_given) { fprintf(stderr, "Missing delegated capabilities argument\n"); goto main_exit; } yhrc = yh_string_to_capabilities(args_info.delegated_arg, &delegated); if (yhrc != YHR_SUCCESS) { fprintf(stderr, "Unable to parse delegated capabilities: %s\n", yh_strerror(yhrc)); goto main_exit; } } input_file = open_file(args_info.in_arg, true); if (input_file == NULL) { perror("Unable to open input file"); goto main_exit; } switch (type) { case YH_AUTHENTICATION_KEY: { char password[256] = {0}; size_t password_len = sizeof(password); if (input_file == stdin) { const char *prompt = "Derivation Password: "; if (EVP_read_pw_string(password, password_len - 1, prompt, 1)) { fprintf(stderr, "Unable to read password prompt\n"); goto main_exit; } password_len = strlen(password); } else { if (read_file(input_file, (uint8_t *) password, &password_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } if (password[password_len - 1] == '\n') { password_len--; } if (password[password_len - 1] == '\r') { password_len--; } password[password_len] = '\0'; } uint8_t key[YH_KEY_LEN * 2]; bool ret = pkcs5_pbkdf2_hmac((const uint8_t *) password, password_len, (const uint8_t *) YH_DEFAULT_SALT, strlen(YH_DEFAULT_SALT), YH_DEFAULT_ITERS, _SHA256, key, sizeof(key)); if (ret == false) { fprintf(stderr, "Unable to derive keys\n"); goto main_exit; } memcpy(wrap_object.body, delegated.capabilities, YH_CAPABILITIES_LEN); wrap_object_len -= YH_CAPABILITIES_LEN; memcpy(wrap_object.body + YH_CAPABILITIES_LEN, key, YH_KEY_LEN); memcpy(wrap_object.body + YH_CAPABILITIES_LEN + YH_KEY_LEN, key + YH_KEY_LEN, YH_KEY_LEN); wrap_object_len = YH_CAPABILITIES_LEN + YH_KEY_LEN * 2; } break; case YH_WRAP_KEY: { memcpy(wrap_object.body, delegated.capabilities, YH_CAPABILITIES_LEN); wrap_object_len -= YH_CAPABILITIES_LEN; if (read_file(input_file, wrap_object.body + YH_CAPABILITIES_LEN, &wrap_object_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } wrap_object_len += YH_CAPABILITIES_LEN; } break; case YH_ASYMMETRIC_KEY: { yh_algorithm parsed_algorithm; if (read_file(input_file, wrap_object.body, &wrap_object_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } if (read_private_key(wrap_object.body, wrap_object_len, &parsed_algorithm, wrap_object.body, &wrap_object_len, true) != true) { fprintf(stderr, "Unable to read asymmetric private key\n"); goto main_exit; } if (parsed_algorithm != algorithm) { fprintf(stderr, "Mismatched algorithm\n"); goto main_exit; } } break; case YH_HMAC_KEY: { if (read_file(input_file, wrap_object.body, &wrap_object_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } if (split_hmac_key(algorithm, wrap_object.body, wrap_object_len, wrap_object.body, &wrap_object_len) != true) { fprintf(stderr, "Unable to format hmac key\n"); goto main_exit; } } break; default: if (read_file(input_file, wrap_object.body, &wrap_object_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } } wrapkey_file = open_file(args_info.wrapkey_arg, true); if (wrapkey_file == NULL) { perror("Unable to open wrapkey file"); goto main_exit; } uint8_t wrapkey_buf[WRAPKEY_BUFSIZE]; size_t wrapkey_buf_len = sizeof(wrapkey_buf); if (read_file(wrapkey_file, wrapkey_buf, &wrapkey_buf_len) == false) { fprintf(stderr, "Unable to read wrapkey file\n"); } yh_algorithm wrapkey_algorithm; switch (wrapkey_buf_len) { case 16: wrapkey_algorithm = YH_ALGO_AES128_CCM_WRAP; break; case 24: wrapkey_algorithm = YH_ALGO_AES192_CCM_WRAP; break; case 32: wrapkey_algorithm = YH_ALGO_AES256_CCM_WRAP; break; default: fprintf(stderr, "Unable to parse wrapkey: invalid length\n"); goto main_exit; } output_file = open_file(args_info.out_arg, false); if (output_file == NULL) { perror("Unable to open output file"); goto main_exit; } format_header(wrapkey_algorithm, capabilities, id, wrap_object_len, domains, type, algorithm, label, wrap_object.header); uint8_t wrapped[2048] = {0}; size_t wrapped_len = sizeof(wrapped); if (wrap_data(wrapkey_buf, wrapkey_buf_len, wrap_object.buf, OBJECT_HEADER_SIZE + wrap_object_len, wrapped, &wrapped_len) == false) { fprintf(stderr, "Unable to wrap data\n"); goto main_exit; } if (getenv("DEBUG") != NULL) { dump_hex(wrap_object.buf, OBJECT_HEADER_SIZE + wrap_object_len); } if (write_file(wrapped, wrapped_len, output_file, _base64) == false || write_file((uint8_t *) "\n", 1, output_file, _binary) == false) { fprintf(stderr, "Unable to write output file\n"); goto main_exit; } rc = EXIT_SUCCESS; main_exit: cmdline_parser_free(&args_info); if (input_file != NULL) { fclose(input_file); input_file = NULL; } if (output_file != NULL) { fclose(output_file); output_file = NULL; } if (wrapkey_file != NULL) { fclose(wrapkey_file); wrapkey_file = NULL; } return rc; } yubihsm-shell-2.7.3/yhwrap/version.rc.in0000644000175000017500000000214515167357110017230 0ustar aveenaveen #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM Wrap" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "yubihsm-wrap.exe" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "yubihsm-wrap.exe" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.7.3/yhwrap/CMakeLists.txt0000644000175000017500000000520715167357110017352 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(${CMAKE_SOURCE_DIR}/cmake/openssl.cmake) find_libcrypto() set ( SOURCE ../common/hash.c ../common/parsing.c ../common/pkcs5.c ../common/util.c ../common/openssl-compat.c main.c ) if(WIN32) set(SOURCE ${SOURCE} cmdline.c) include(${CMAKE_SOURCE_DIR}/cmake/getopt.cmake) find_getopt() else(WIN32) include(gengetopt) add_gengetopt_files (cmdline) set(SOURCE ${SOURCE} ${GGO_C}) message("${GGO_C}") endif(WIN32) include_directories ( ${LIBCRYPTO_INCLUDEDIR} ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${CMAKE_CURRENT_SOURCE_DIR}/../common ) if(${WIN32}) list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) endif(${WIN32}) # NOTE(adma): required by gengetopt add_definitions (-DPACKAGE="yubihsm-wrap") add_definitions (-DVERSION="${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") list(APPEND LCOV_REMOVE_PATTERNS "'${PROJECT_SOURCE_DIR}/yhwrap/cmdline.c'") if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") set_property(SOURCE ${GGO_C} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-but-set-variable ") endif() add_executable (yubihsm-wrap ${SOURCE}) target_link_libraries ( yubihsm-wrap ${LIBCRYPTO_LDFLAGS} ${GETOPT_LIBS} yubihsm ) # Set install RPATH (Darwin default from root CMakeLists.txt is correct for bin/ targets) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_target_properties(yubihsm-wrap PROPERTIES INSTALL_RPATH "${YUBIHSM_INSTALL_LIB_DIR}") endif() add_coverage(yubihsm-wrap) install( TARGETS yubihsm-wrap ARCHIVE DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" LIBRARY DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" RUNTIME DESTINATION "${YUBIHSM_INSTALL_BIN_DIR}") if (NOT WITHOUT_MANPAGES) include (help2man) add_help2man_manpage (yubihsm-wrap.1 yubihsm-wrap) add_custom_target (yubihsm-wrap-man ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/yubihsm-wrap.1 ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/yubihsm-wrap.1" DESTINATION "${YUBIHSM_INSTALL_MAN_DIR}/man1") endif () yubihsm-shell-2.7.3/yhwrap/cmdline.ggo0000644000175000017500000000201415167357110016714 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # option "algorithm" a "Object algorithm" string option "capabilities" c "Object capabilities" string option "delegated" e "Object delegates capabilities" string optional option "domains" d "Object domains" string option "id" i "Object ID" short optional default="0" option "in" - "Input data (filename)" string option "out" - "Output data (filename)" string option "label" l "Object label" string option "wrapkey" k "Key to wrap data with (filename)" string yubihsm-shell-2.7.3/yhwrap/README.adoc0000644000175000017500000000472415167357110016402 0ustar aveenaveen== YubiHSM Wrap YubiHSM Wrap is a command-line tool to create "offline wraps" for a YubiHSM 2 device. One of the functionalities supported by the YubiHSM is to import objects under wrap. The typical use is to generate an object on one device, export it under wrap using a Wrap Key and import it to a different device which has the same Wrap Key. At times it is also useful to be able to create those wrapped objects from a computer, so that they can be encrypted at rest and also easily sent to devices for use. === Example This example shows how to generate a private key using OpenSSL, wrap it to a pre-shared Wrap Key and import it on a device. The first thing we need is a Wrap Key that we will use to wrap the object. For this example we are going to use `00112233445566778899aabbccddeeff` We first save it to a file called `wrap.key` by running [source, bash] ---- $ echo -en '\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff' >wrap.key ---- The Wrap Key has to also exist on the YubiHSM. We can import it in the device and give it Object ID `20` by running [source, bash] ---- $ yubihsm-shell -p password -a put-wrap-key -i 20 -c all --delegated all --informat bin --in wrap.key ---- At this point we can use OpenSSL to generate the RSA key that we would like to wrap and import [source, bash] ---- $ openssl genrsa -out private.pem ---- We can now use `yubihsm-wrap` to produce the wrapped version of the private key. Specifically, we will be asking for the key to have, once imported, Object ID `30`, label `RSA_Key` and belong to Domains `1`, `2` and `5`. [source, bash] ---- $ yubihsm-wrap -a rsa2048 -c sign-pkcs -d 1,2,5 --id 30 --label RSA_Key --in private.pem --wrapkey wrap.key --out private.yhw ---- The output file `private.yhw` is the wrapped version of the key and it is ready to be imported in the device using the Wrap Key that we stored before. The command to do that is [source, bash] ---- $ yubihsm-shell -p password -a put-wrapped --wrap-id 20 --in private.yhw ---- We should now be able to retrieve information about the Asymmetric Key with Object ID `30` by running [source, bash] ---- $ yubihsm-shell -p password -a get-object-info -i 30 -t asymmetric-key Using default connector URL: http://localhost:12345 Session keepalive set up to run every 15 seconds Created session 0 id: 0x001e, type: asymmetric-key, algorithm: rsa2048, label: "RSA_Key", length: 896, domains: 1:2:5, sequence: 0, origin: imported:imported_wrapped, capabilities: sign-pkcs ---- yubihsm-shell-2.7.3/yhwrap/cmdline.c0000644000175000017500000005351315167357170016402 0ustar aveenaveen/* File autogenerated by gengetopt version 2.23 generated with the following command: gengetopt -i /home/runner/work/yubihsm-shell/yubihsm-shell/yhwrap/cmdline.ggo --output-dir /home/runner/work/yubihsm-shell/yubihsm-shell/yhwrap cmdline The developers of gengetopt consider the fixed text that goes in all gengetopt output files to be in the public domain: we make no copyright claims on it. */ /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifndef FIX_UNUSED #define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ #endif #include #include "cmdline.h" const char *gengetopt_args_info_purpose = ""; const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { " -h, --help Print help and exit", " -V, --version Print version and exit", " -a, --algorithm=STRING Object algorithm", " -c, --capabilities=STRING Object capabilities", " -e, --delegated=STRING Object delegates capabilities", " -d, --domains=STRING Object domains", " -i, --id=SHORT Object ID (default=`0')", " --in=STRING Input data (filename)", " --out=STRING Output data (filename)", " -l, --label=STRING Object label", " -k, --wrapkey=STRING Key to wrap data with (filename)", 0 }; typedef enum {ARG_NO , ARG_STRING , ARG_SHORT } cmdline_parser_arg_type; static void clear_given (struct gengetopt_args_info *args_info); static void clear_args (struct gengetopt_args_info *args_info); static int cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error); static int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error); static char * gengetopt_strdup (const char *s); static void clear_given (struct gengetopt_args_info *args_info) { args_info->help_given = 0 ; args_info->version_given = 0 ; args_info->algorithm_given = 0 ; args_info->capabilities_given = 0 ; args_info->delegated_given = 0 ; args_info->domains_given = 0 ; args_info->id_given = 0 ; args_info->in_given = 0 ; args_info->out_given = 0 ; args_info->label_given = 0 ; args_info->wrapkey_given = 0 ; } static void clear_args (struct gengetopt_args_info *args_info) { FIX_UNUSED (args_info); args_info->algorithm_arg = NULL; args_info->algorithm_orig = NULL; args_info->capabilities_arg = NULL; args_info->capabilities_orig = NULL; args_info->delegated_arg = NULL; args_info->delegated_orig = NULL; args_info->domains_arg = NULL; args_info->domains_orig = NULL; args_info->id_arg = 0; args_info->id_orig = NULL; args_info->in_arg = NULL; args_info->in_orig = NULL; args_info->out_arg = NULL; args_info->out_orig = NULL; args_info->label_arg = NULL; args_info->label_orig = NULL; args_info->wrapkey_arg = NULL; args_info->wrapkey_orig = NULL; } static void init_args_info(struct gengetopt_args_info *args_info) { args_info->help_help = gengetopt_args_info_help[0] ; args_info->version_help = gengetopt_args_info_help[1] ; args_info->algorithm_help = gengetopt_args_info_help[2] ; args_info->capabilities_help = gengetopt_args_info_help[3] ; args_info->delegated_help = gengetopt_args_info_help[4] ; args_info->domains_help = gengetopt_args_info_help[5] ; args_info->id_help = gengetopt_args_info_help[6] ; args_info->in_help = gengetopt_args_info_help[7] ; args_info->out_help = gengetopt_args_info_help[8] ; args_info->label_help = gengetopt_args_info_help[9] ; args_info->wrapkey_help = gengetopt_args_info_help[10] ; } void cmdline_parser_print_version (void) { printf ("%s %s\n", (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), CMDLINE_PARSER_VERSION); if (strlen(gengetopt_args_info_versiontext) > 0) printf("\n%s\n", gengetopt_args_info_versiontext); } static void print_help_common(void) { size_t len_purpose = strlen(gengetopt_args_info_purpose); size_t len_usage = strlen(gengetopt_args_info_usage); if (len_usage > 0) { printf("%s\n", gengetopt_args_info_usage); } if (len_purpose > 0) { printf("%s\n", gengetopt_args_info_purpose); } if (len_usage || len_purpose) { printf("\n"); } if (strlen(gengetopt_args_info_description) > 0) { printf("%s\n\n", gengetopt_args_info_description); } } void cmdline_parser_print_help (void) { int i = 0; print_help_common(); while (gengetopt_args_info_help[i]) printf("%s\n", gengetopt_args_info_help[i++]); } void cmdline_parser_init (struct gengetopt_args_info *args_info) { clear_given (args_info); clear_args (args_info); init_args_info (args_info); } void cmdline_parser_params_init(struct cmdline_parser_params *params) { if (params) { params->override = 0; params->initialize = 1; params->check_required = 1; params->check_ambiguity = 0; params->print_errors = 1; } } struct cmdline_parser_params * cmdline_parser_params_create(void) { struct cmdline_parser_params *params = (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); cmdline_parser_params_init(params); return params; } static void free_string_field (char **s) { if (*s) { free (*s); *s = 0; } } static void cmdline_parser_release (struct gengetopt_args_info *args_info) { free_string_field (&(args_info->algorithm_arg)); free_string_field (&(args_info->algorithm_orig)); free_string_field (&(args_info->capabilities_arg)); free_string_field (&(args_info->capabilities_orig)); free_string_field (&(args_info->delegated_arg)); free_string_field (&(args_info->delegated_orig)); free_string_field (&(args_info->domains_arg)); free_string_field (&(args_info->domains_orig)); free_string_field (&(args_info->id_orig)); free_string_field (&(args_info->in_arg)); free_string_field (&(args_info->in_orig)); free_string_field (&(args_info->out_arg)); free_string_field (&(args_info->out_orig)); free_string_field (&(args_info->label_arg)); free_string_field (&(args_info->label_orig)); free_string_field (&(args_info->wrapkey_arg)); free_string_field (&(args_info->wrapkey_orig)); clear_given (args_info); } static void write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) { FIX_UNUSED (values); if (arg) { fprintf(outfile, "%s=\"%s\"\n", opt, arg); } else { fprintf(outfile, "%s\n", opt); } } int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) { int i = 0; if (!outfile) { fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); return EXIT_FAILURE; } if (args_info->help_given) write_into_file(outfile, "help", 0, 0 ); if (args_info->version_given) write_into_file(outfile, "version", 0, 0 ); if (args_info->algorithm_given) write_into_file(outfile, "algorithm", args_info->algorithm_orig, 0); if (args_info->capabilities_given) write_into_file(outfile, "capabilities", args_info->capabilities_orig, 0); if (args_info->delegated_given) write_into_file(outfile, "delegated", args_info->delegated_orig, 0); if (args_info->domains_given) write_into_file(outfile, "domains", args_info->domains_orig, 0); if (args_info->id_given) write_into_file(outfile, "id", args_info->id_orig, 0); if (args_info->in_given) write_into_file(outfile, "in", args_info->in_orig, 0); if (args_info->out_given) write_into_file(outfile, "out", args_info->out_orig, 0); if (args_info->label_given) write_into_file(outfile, "label", args_info->label_orig, 0); if (args_info->wrapkey_given) write_into_file(outfile, "wrapkey", args_info->wrapkey_orig, 0); i = EXIT_SUCCESS; return i; } int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) { FILE *outfile; int i = 0; outfile = fopen(filename, "w"); if (!outfile) { fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); return EXIT_FAILURE; } i = cmdline_parser_dump(outfile, args_info); fclose (outfile); return i; } void cmdline_parser_free (struct gengetopt_args_info *args_info) { cmdline_parser_release (args_info); } /** @brief replacement of strdup, which is not standard */ char * gengetopt_strdup (const char *s) { char *result = 0; if (!s) return result; result = (char*)malloc(strlen(s) + 1); if (result == (char*)0) return (char*)0; strcpy(result, s); return result; } int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) { return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); } int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params) { int result; result = cmdline_parser_internal (argc, argv, args_info, params, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) { int result; struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) { int result = EXIT_SUCCESS; if (cmdline_parser_required2(args_info, prog_name, 0) > 0) result = EXIT_FAILURE; if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error) { int error_occurred = 0; FIX_UNUSED (additional_error); /* checks for required options */ if (! args_info->algorithm_given) { fprintf (stderr, "%s: '--algorithm' ('-a') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->capabilities_given) { fprintf (stderr, "%s: '--capabilities' ('-c') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->domains_given) { fprintf (stderr, "%s: '--domains' ('-d') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->in_given) { fprintf (stderr, "%s: '--in' option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->out_given) { fprintf (stderr, "%s: '--out' option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->label_given) { fprintf (stderr, "%s: '--label' ('-l') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->wrapkey_given) { fprintf (stderr, "%s: '--wrapkey' ('-k') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } /* checks for dependences among options */ return error_occurred; } static char *package_name = 0; /** * @brief updates an option * @param field the generic pointer to the field to update * @param orig_field the pointer to the orig field * @param field_given the pointer to the number of occurrence of this option * @param prev_given the pointer to the number of occurrence already seen * @param value the argument for this option (if null no arg was specified) * @param possible_values the possible values for this option (if specified) * @param default_value the default value (in case the option only accepts fixed values) * @param arg_type the type of this option * @param check_ambiguity @see cmdline_parser_params.check_ambiguity * @param override @see cmdline_parser_params.override * @param no_free whether to free a possible previous value * @param multiple_option whether this is a multiple option * @param long_opt the corresponding long option * @param short_opt the corresponding short option (or '-' if none) * @param additional_error possible further error specification */ static int update_arg(void *field, char **orig_field, unsigned int *field_given, unsigned int *prev_given, char *value, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, int check_ambiguity, int override, int no_free, int multiple_option, const char *long_opt, char short_opt, const char *additional_error) { char *stop_char = 0; const char *val = value; int found; char **string_field; FIX_UNUSED (field); stop_char = 0; found = 0; if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) { if (short_opt != '-') fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", package_name, long_opt, short_opt, (additional_error ? additional_error : "")); else fprintf (stderr, "%s: `--%s' option given more than once%s\n", package_name, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } FIX_UNUSED (default_value); if (field_given && *field_given && ! override) return 0; if (prev_given) (*prev_given)++; if (field_given) (*field_given)++; if (possible_values) val = possible_values[found]; switch(arg_type) { case ARG_SHORT: if (val) *((short *)field) = (short)strtol (val, &stop_char, 0); break; case ARG_STRING: if (val) { string_field = (char **)field; if (!no_free && *string_field) free (*string_field); /* free previous string */ *string_field = gengetopt_strdup (val); } break; default: break; }; /* check numeric conversion */ switch(arg_type) { case ARG_SHORT: if (val && !(stop_char && *stop_char == '\0')) { fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val); return 1; /* failure */ } break; default: ; }; /* store the original value */ switch(arg_type) { case ARG_NO: break; default: if (value && orig_field) { if (no_free) { *orig_field = value; } else { if (*orig_field) free (*orig_field); /* free previous string */ *orig_field = gengetopt_strdup (value); } } }; return 0; /* OK */ } int cmdline_parser_internal ( int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error) { int c; /* Character of the parsed option. */ int error_occurred = 0; struct gengetopt_args_info local_args_info; int override; int initialize; int check_required; int check_ambiguity; package_name = argv[0]; /* TODO: Why is this here? It is not used anywhere. */ override = params->override; FIX_UNUSED(override); initialize = params->initialize; check_required = params->check_required; /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); cmdline_parser_init (&local_args_info); optarg = 0; optind = 0; opterr = params->print_errors; optopt = '?'; while (1) { int option_index = 0; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, { "algorithm", 1, NULL, 'a' }, { "capabilities", 1, NULL, 'c' }, { "delegated", 1, NULL, 'e' }, { "domains", 1, NULL, 'd' }, { "id", 1, NULL, 'i' }, { "in", 1, NULL, 0 }, { "out", 1, NULL, 0 }, { "label", 1, NULL, 'l' }, { "wrapkey", 1, NULL, 'k' }, { 0, 0, 0, 0 } }; c = getopt_long (argc, argv, "hVa:c:e:d:i:l:k:", long_options, &option_index); if (c == -1) break; /* Exit from `while (1)' loop. */ switch (c) { case 'h': /* Print help and exit. */ cmdline_parser_print_help (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'V': /* Print version and exit. */ cmdline_parser_print_version (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'a': /* Object algorithm. */ if (update_arg( (void *)&(args_info->algorithm_arg), &(args_info->algorithm_orig), &(args_info->algorithm_given), &(local_args_info.algorithm_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "algorithm", 'a', additional_error)) goto failure; break; case 'c': /* Object capabilities. */ if (update_arg( (void *)&(args_info->capabilities_arg), &(args_info->capabilities_orig), &(args_info->capabilities_given), &(local_args_info.capabilities_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "capabilities", 'c', additional_error)) goto failure; break; case 'e': /* Object delegates capabilities. */ if (update_arg( (void *)&(args_info->delegated_arg), &(args_info->delegated_orig), &(args_info->delegated_given), &(local_args_info.delegated_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "delegated", 'e', additional_error)) goto failure; break; case 'd': /* Object domains. */ if (update_arg( (void *)&(args_info->domains_arg), &(args_info->domains_orig), &(args_info->domains_given), &(local_args_info.domains_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "domains", 'd', additional_error)) goto failure; break; case 'i': /* Object ID. */ if (update_arg( (void *)&(args_info->id_arg), &(args_info->id_orig), &(args_info->id_given), &(local_args_info.id_given), optarg, 0, "0", ARG_SHORT, check_ambiguity, override, 0, 0, "id", 'i', additional_error)) goto failure; break; case 'l': /* Object label. */ if (update_arg( (void *)&(args_info->label_arg), &(args_info->label_orig), &(args_info->label_given), &(local_args_info.label_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "label", 'l', additional_error)) goto failure; break; case 'k': /* Key to wrap data with (filename). */ if (update_arg( (void *)&(args_info->wrapkey_arg), &(args_info->wrapkey_orig), &(args_info->wrapkey_given), &(local_args_info.wrapkey_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "wrapkey", 'k', additional_error)) goto failure; break; case 0: /* Long option with no short option */ /* Input data (filename). */ if (strcmp (long_options[option_index].name, "in") == 0) { if (update_arg( (void *)&(args_info->in_arg), &(args_info->in_orig), &(args_info->in_given), &(local_args_info.in_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "in", '-', additional_error)) goto failure; } /* Output data (filename). */ else if (strcmp (long_options[option_index].name, "out") == 0) { if (update_arg( (void *)&(args_info->out_arg), &(args_info->out_orig), &(args_info->out_given), &(local_args_info.out_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "out", '-', additional_error)) goto failure; } break; case '?': /* Invalid option. */ /* `getopt_long' already printed an error message. */ goto failure; default: /* bug: option not considered. */ fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); abort (); } /* switch */ } /* while */ if (check_required) { error_occurred += cmdline_parser_required2 (args_info, argv[0], additional_error); } cmdline_parser_release (&local_args_info); if ( error_occurred ) return (EXIT_FAILURE); return 0; failure: cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } /* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ yubihsm-shell-2.7.3/CMakeLists.txt0000644000175000017500000002523615167357110016044 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # cmake_minimum_required (VERSION 3.15) # policy CMP0025 is to get AppleClang identifier rather than Clang for both # this matters since the apple compiler accepts different flags. cmake_policy(SET CMP0025 NEW) cmake_policy(SET CMP0042 NEW) cmake_policy(SET CMP0054 NEW) cmake_policy(SET CMP0091 NEW) project (yubihsm-shell) option(BUILD_ONLY_LIB "Library only build" OFF) option(SUPRESS_MSVC_WARNINGS "Suppresses a lot of the warnings when compiling with MSVC" ON) option(ENABLE_STATIC "Compiles libyubihsm as a static library (in addtion to the dynamic library)" OFF) option(ENABLE_CERT_COMPRESS "Enable/disable certificate compression" ON) if(ENABLE_CERT_COMPRESS) message(STATUS "Certificate compression is enabled.") add_definitions(-DENABLE_CERT_COMPRESS) else () message(STATUS "Certificate compression is disabled.") endif() include(${CMAKE_SOURCE_DIR}/cmake/Fuzzing.cmake) include(${CMAKE_SOURCE_DIR}/cmake/SecurityFlags.cmake) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") # Set various install paths if (NOT DEFINED YUBIHSM_INSTALL_LIB_DIR) set(YUBIHSM_INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Installation directory for libraries") endif () if (NOT DEFINED YUBIHSM_INSTALL_INC_DIR) set(YUBIHSM_INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers") endif () if (NOT DEFINED YUBIHSM_INSTALL_BIN_DIR) set(YUBIHSM_INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") endif () if (NOT DEFINED YUBIHSM_INSTALL_MAN_DIR) set(YUBIHSM_INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages") endif () if (NOT DEFINED YUBIHSM_INSTALL_PKGCONFIG_DIR) if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") set(YUBIHSM_INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/libdata/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") else () set(YUBIHSM_INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") endif () endif () # --------------------------------------------------------------------------- # macOS: Configure relocatable @rpath-based install names # --------------------------------------------------------------------------- if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # Use @rpath in install names for all shared libraries set(CMAKE_MACOSX_RPATH ON) # Don't embed the build tree rpath into installed binaries set(CMAKE_SKIP_BUILD_RPATH FALSE) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) # Strip build-tree rpaths when installing set(CMAKE_INSTALL_RPATH_USE_LINK_DEPENDS FALSE) # Executables in bin/ need to find libs in ../lib relative to themselves # Libraries in lib/ don't need an rpath (they live alongside their siblings) # The PKCS#11 module in lib/pkcs11/ needs to find libs in .. relative to itself # We set a default here; individual targets override as needed in their CMakeLists.txt set(CMAKE_INSTALL_RPATH "@loader_path/../lib") endif() if (NOT CMAKE_BUILD_TYPE) if (${RELEASE_BUILD} MATCHES 1) set (CMAKE_BUILD_TYPE Release) else () set (CMAKE_BUILD_TYPE Debug) endif () endif () if(MSVC) set(DISABLE_LTO 1) endif() if (NOT DISABLE_LTO) if (CMAKE_C_COMPILER_ID STREQUAL GNU) if (CMAKE_C_COMPILER_VERSION VERSION_GREATER 6.0) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto") endif () else () if (CMAKE_C_COMPILER_VERSION VERSION_GREATER 7.0) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto") endif () endif () endif () if (CMAKE_C_COMPILER_ID STREQUAL AppleClang) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-nullability-completeness -Wno-nullability-extension -Wno-expansion-to-defined -Wno-undef-prefix -Wno-extra-semi") elseif (NOT MSVC) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-braces -Wno-missing-field-initializers") # -Wl,--strip-all is dependent on linker not compiler... set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -Wl,--strip-all") endif () if (CMAKE_MAJOR_VERSION LESS 3) if (CMAKE_C_COMPILER_ID STREQUAL GNU) # The C_STANDARD property was introduced in cmake 3.1 # https://cmake.org/cmake/help/latest/prop_tgt/C_STANDARD.html set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11") endif () else () set (CMAKE_C_STANDARD 11) endif () set (yubihsm_shell_VERSION_MAJOR 2) set (yubihsm_shell_VERSION_MINOR 7) set (yubihsm_shell_VERSION_PATCH 3) set (VERSION "${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") set(ENV{PKG_CONFIG_PATH} "/usr/libdata/pkgconfig:$ENV{PKG_CONFIG_PATH}") endif () if (NOT DEFINED DEFAULT_CONNECTOR_URL) set (DEFAULT_CONNECTOR_URL "http://localhost:12345") endif() add_definitions(-DDEFAULT_CONNECTOR_URL="${DEFAULT_CONNECTOR_URL}") enable_testing() find_package(codecov) add_definitions(-DOPENSSL_API_COMPAT=0x10000000L) if(WIN32) add_definitions(-DWIN32_LEAN_AND_MEAN=1) set(_WIN32 1) set(__WIN32 1) set(_WIN32_BCRYPT 1) endif() if(MSVC) message("win32") set(_MSVC 1) if(SUPRESS_MSVC_WARNINGS) set(MSVC_DISABLED_WARNINGS_LIST "C4706" # assignment within conditional expression; "C4996" # The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name "C4005" # redefinition of micros. Status codes are defined in winnt.h and then redefined in ntstatus.h with the same values "C4244" # conversion of size_t to other types. Since we don't have sizes that occupy more than 2 bytes, this should be safe to ignore "C4267" # conversion of size_t to other types. Since we don't have sizes that occupy more than 2 bytes, this should be safe to ignore "C4100" # unreferenced formal parameter "C4201" # nonstandard extension used: nameless struct/union "C4295" # array is too small to include a terminating null character. They arrays it's complaining about aren't meant to include terminating null character (triggered in tests and examples only) "C4127" # conditional expression is constant "C5105" # macro expansion producing 'defined' has undefined behavior "C4018" # signed/unsigned mismatch ) # The construction in the following 3 lines was taken from LibreSSL's # CMakeLists.txt. string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR ${MSVC_DISABLED_WARNINGS_LIST}) string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 ${MSVC_DISABLED_WARNINGS_STR}") endif(SUPRESS_MSVC_WARNINGS) set (WITHOUT_MANPAGES 1) if (NOT WITHOUT_WIN32_BCRYPT) set (WIN32_BCRYPT 1) endif() else() message(STATUS "not win32") include(CheckFunctionExists) check_function_exists(memset_s HAVE_MEMSET_S) if (HAVE_MEMSET_S) add_definitions (-DHAVE_MEMSET_S) endif() check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO) if (HAVE_EXPLICIT_BZERO) add_definitions (-DHAVE_EXPLICIT_BZERO) endif () find_package (PkgConfig REQUIRED) if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") if (NOT LIBCRYPTO_LDFLAGS) set (LIBCRYPTO_LDFLAGS "-lcrypto") endif() if (NOT LIBCRYPTO_VERSION) set (LIBCRYPTO_VERSION "1.1.1") endif() else() include(${CMAKE_SOURCE_DIR}/cmake/openssl.cmake) find_libcrypto() endif() if(NOT BUILD_ONLY_LIB) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set (LIBEDIT_LDFLAGS "-ledit") else() pkg_search_module (LIBEDIT REQUIRED libedit) endif() endif() pkg_search_module (LIBCURL REQUIRED libcurl) pkg_search_module (LIBUSB REQUIRED libusb-1.0) endif() message("LIBCRYPTO_VERSION: ${LIBCRYPTO_VERSION}") add_subdirectory (lib) if(NOT BUILD_ONLY_LIB) add_subdirectory (pkcs11) set(LIBPCSC_REQ "Linux" "FreeBSD") if(${CMAKE_SYSTEM_NAME} IN_LIST LIBPCSC_REQ) pkg_search_module (LIBPCSC REQUIRED libpcsclite) elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows") set (LIBPCSC_LDFLAGS "winscard.lib") elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(LIBPCSC_LDFLAGS "-Wl,-framework -Wl,PCSC") endif() add_subdirectory (ykhsmauth) add_subdirectory (yubihsm-auth) add_subdirectory (src) add_subdirectory (examples) add_subdirectory(yhwrap) endif() add_custom_target ( cppcheck COMMENT "Running cppcheck" COMMAND cppcheck --enable=warning,style,unusedFunction,missingInclude --template="[{severity}][{id}] {message} {callstack} \(On {file}:{line}\)" -i ${CMAKE_SOURCE_DIR}/src/cmdline.c -i ${CMAKE_SOURCE_DIR}/pkcs11/cmdline.c --verbose --quiet ${CMAKE_SOURCE_DIR}/lib ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/pkcs11 ) set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}) add_custom_target ( dist COMMAND git archive --prefix=${ARCHIVE_NAME}/ HEAD | gzip > ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.gz WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) coverage_evaluate() message("Build summary:") message("") message(" Project name: ${CMAKE_PROJECT_NAME}") message(" Version: ${VERSION}") message(" Host type: ${CMAKE_SYSTEM_NAME}") message(" Path prefix: ${CMAKE_PREFIX_PATH}") message(" Compiler: ${CMAKE_C_COMPILER}") message(" Compiler ID: ${CMAKE_C_COMPILER_ID}") message(" Compiler version: ${CMAKE_C_COMPILER_VERSION}") message(" CMake version: ${CMAKE_VERSION}") message(" CFLAGS: ${CMAKE_C_FLAGS}") message(" CPPFLAGS: ${CMAKE_CXX_FLAGS}") message(" Warnings: ${WARN_FLAGS}") message(" Build type: ${CMAKE_BUILD_TYPE}") message("") message(" Install prefix: ${CMAKE_INSTALL_PREFIX}") message(" Install targets") message(" Libraries ${YUBIHSM_INSTALL_LIB_DIR}") message(" Includes ${YUBIHSM_INSTALL_INC_DIR}") message(" Binaries ${YUBIHSM_INSTALL_BIN_DIR}") message(" Manuals ${YUBIHSM_INSTALL_MAN_DIR}") message(" Pkg-config ${YUBIHSM_INSTALL_PKGCONFIG_DIR}") yubihsm-shell-2.7.3/LICENSE0000644000175000017500000002205615167357110014306 0ustar aveenaveenApache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS yubihsm-shell-2.7.3/examples/0000755000175000017500000000000015167357110015112 5ustar aveenaveenyubihsm-shell-2.7.3/examples/wrap.c0000644000175000017500000004753115167357110016241 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "openssl-compat.h" const char *key_label = "label"; const uint8_t password[] = "password"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("export-wrapped:import-wrapped", &capabilities); assert(yrc == YHR_SUCCESS); yh_capabilities delegated_capabilities = {{0}}; yrc = yh_string_to_capabilities("sign-ecdsa:sign-eddsa:sign-pkcs:sign-pss:exportable-under-wrap", &delegated_capabilities); // delegated // capabilities has // to match the // capabilities of // the object we // want to export assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); const char data[] = "This is the data to sign"; uint8_t hashed_data[32]; unsigned int hashed_data_len = sizeof(hashed_data); EVP_MD_CTX *mdctx = EVP_MD_CTX_create(); assert(mdctx != NULL); EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL); EVP_DigestUpdate(mdctx, data, sizeof(data) - 1); EVP_DigestFinal_ex(mdctx, hashed_data, &hashed_data_len); EVP_MD_CTX_destroy(mdctx); uint16_t wrapping_key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_generate_wrap_key(session, &wrapping_key_id, key_label, domain_five, &capabilities, YH_ALGO_AES256_CCM_WRAP, &delegated_capabilities); assert(yrc == YHR_SUCCESS); printf("Generated wrapping key with ID %04x\n", wrapping_key_id); memset(capabilities.capabilities, 0, YH_CAPABILITIES_LEN); yrc = yh_string_to_capabilities("sign-ecdsa:sign-eddsa:sign-pkcs:sign-pss:exportable-under-wrap", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t key_id_before = 0; // ID 0 lets the device generate an ID yrc = yh_util_generate_ec_key(session, &key_id_before, key_label, domain_five, &capabilities, YH_ALGO_EC_P256); assert(yrc == YHR_SUCCESS); printf("Generated ec key with ID %04x\n", key_id_before); uint8_t public_key_before[1024]; size_t public_key_before_len = sizeof(public_key_before); yrc = yh_util_get_public_key(session, key_id_before, public_key_before, &public_key_before_len, NULL); assert(yrc == YHR_SUCCESS); memmove(public_key_before + 1, public_key_before, public_key_before_len); public_key_before[0] = 0x04; // hack to make it a valid ec pubkey.. public_key_before_len++; printf("Public ec key before (%zu bytes) is:", public_key_before_len); for (unsigned int i = 0; i < public_key_before_len; i++) { printf(" %02x", public_key_before[i]); } printf("\n"); uint8_t signature_before[512]; size_t signature_before_len = sizeof(signature_before); yrc = yh_util_sign_ecdsa(session, key_id_before, hashed_data, hashed_data_len, signature_before, &signature_before_len); assert(yrc == YHR_SUCCESS); printf("ECDSA signature before (%zu bytes) is:", signature_before_len); for (unsigned int i = 0; i < signature_before_len; i++) { printf(" %02x", signature_before[i]); } printf("\n"); int nid = algo2nid(YH_ALGO_EC_P256); EC_GROUP *group = EC_GROUP_new_by_curve_name(nid); assert(group != NULL); EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); EC_POINT *point = EC_POINT_new(group); EC_POINT_oct2point(group, point, public_key_before, public_key_before_len, NULL); EC_KEY *eckey = EC_KEY_new(); EC_KEY_set_group(eckey, group); EC_KEY_set_public_key(eckey, point); assert(ECDSA_verify(0, hashed_data, hashed_data_len, signature_before, signature_before_len, eckey) == 1); printf("ECDSA Signature before successfully verified\n"); EC_POINT_free(point); EC_KEY_free(eckey); uint8_t wrapped_object[2048]; size_t wrapped_object_len = sizeof(wrapped_object); yh_object_type object_type_after; yrc = yh_util_export_wrapped(session, wrapping_key_id, YH_ASYMMETRIC_KEY, key_id_before, wrapped_object, &wrapped_object_len); assert(yrc == YHR_SUCCESS); printf("Wrapped object (%zu bytes) is:", wrapped_object_len); for (unsigned int i = 0; i < wrapped_object_len; i++) { printf(" %02x", wrapped_object[i]); } printf("\n"); yrc = yh_util_delete_object(session, key_id_before, YH_ASYMMETRIC_KEY); assert(yrc == YHR_SUCCESS); printf("Successfully deleted ec key with ID %04x\n", key_id_before); uint8_t public_key_after[1024]; size_t public_key_after_len = sizeof(public_key_after); yrc = yh_util_get_public_key(session, key_id_before, public_key_after, &public_key_after_len, NULL); assert(yrc == YHR_DEVICE_OBJECT_NOT_FOUND); printf("Unable to get public key for ec key with ID %04x\n", key_id_before); uint16_t key_id_after; yrc = yh_util_import_wrapped(session, wrapping_key_id, wrapped_object, wrapped_object_len, &object_type_after, &key_id_after); assert(yrc == YHR_SUCCESS); printf("Successfully imported wrapped object with ID %04x\n", key_id_after); if (object_type_after != YH_ASYMMETRIC_KEY) { printf("Unexpected odbject type\n"); exit(EXIT_FAILURE); } if (key_id_before != key_id_after) { printf("ID %04x and %04x do not match\n", key_id_before, key_id_after); exit(EXIT_FAILURE); } else { printf("ID %04x and %04x match\n", key_id_before, key_id_after); } yrc = yh_util_get_public_key(session, key_id_after, public_key_after, &public_key_after_len, NULL); assert(yrc == YHR_SUCCESS); memmove(public_key_after + 1, public_key_after, public_key_after_len); public_key_after[0] = 0x04; // hack to make it a valid ec pubkey.. public_key_after_len++; printf("Public ec key after (%zu bytes) is:", public_key_after_len); for (unsigned int i = 0; i < public_key_after_len; i++) { printf(" %02x", public_key_after[i]); } printf("\n"); if (public_key_before_len != public_key_after_len || memcmp(public_key_before, public_key_after, public_key_before_len) != 0) { printf("Public key before and after do not match\n"); exit(EXIT_FAILURE); } else { printf("Public key before and after match\n"); } uint8_t signature_after[512]; size_t signature_after_len = sizeof(signature_after); yrc = yh_util_sign_ecdsa(session, key_id_after, hashed_data, hashed_data_len, signature_after, &signature_after_len); assert(yrc == YHR_SUCCESS); printf("\nECDSA signature after (%zu bytes) is:", signature_after_len); for (unsigned int i = 0; i < signature_after_len; i++) { printf(" %02x", signature_after[i]); } printf("\n"); point = EC_POINT_new(group); EC_POINT_oct2point(group, point, public_key_after, public_key_after_len, NULL); eckey = EC_KEY_new(); EC_KEY_set_group(eckey, group); EC_KEY_set_public_key(eckey, point); assert(ECDSA_verify(0, hashed_data, hashed_data_len, signature_after, signature_after_len, eckey) == 1); printf("ECDSA Signature after successfully verified\n"); EC_POINT_free(point); EC_KEY_free(eckey); EC_GROUP_free(group); yh_object_descriptor object; yrc = yh_util_get_object_info(session, key_id_after, YH_ASYMMETRIC_KEY, &object); assert(yrc == YHR_SUCCESS); yrc = yh_util_delete_object(session, key_id_after, YH_ASYMMETRIC_KEY); assert(yrc == YHR_SUCCESS); printf("Successfully deleted ec key with ID %04x\n", key_id_after); key_id_before = 0; yrc = yh_util_generate_ed_key(session, &key_id_before, key_label, domain_five, &capabilities, YH_ALGO_EC_ED25519); assert(yrc == YHR_SUCCESS); printf("Generated ed25519 key with ID %04x\n", key_id_before); public_key_before_len = sizeof(public_key_before); yrc = yh_util_get_public_key(session, key_id_before, public_key_before, &public_key_before_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public ed25519 key before (%zu bytes) is:", public_key_before_len); for (unsigned int i = 0; i < public_key_before_len; i++) { printf(" %02x", public_key_before[i]); } printf("\n"); signature_before_len = sizeof(signature_before); yrc = yh_util_sign_eddsa(session, key_id_before, hashed_data, hashed_data_len, signature_before, &signature_before_len); assert(yrc == YHR_SUCCESS); printf("Signature (%zu bytes) is:", signature_before_len); for (unsigned int i = 0; i < signature_before_len; i++) { printf(" %02x", signature_before[i]); } printf("\n"); assert(signature_before_len == 64); #if (OPENSSL_VERSION_NUMBER < 0x10101000L) || defined(LIBRESSL_VERSION_NUMBER) printf("Signature check skipped for ed25519 key\n"); #else EVP_PKEY *edkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, 0, public_key_before, public_key_before_len); assert(edkey != NULL); EVP_MD_CTX *edmdctx = EVP_MD_CTX_new(); assert(edmdctx != NULL); assert(EVP_DigestVerifyInit(edmdctx, NULL, NULL, NULL, edkey) > 0); assert(EVP_DigestVerify(edmdctx, signature_before, signature_before_len, hashed_data, hashed_data_len) > 0); EVP_MD_CTX_free(edmdctx); EVP_PKEY_free(edkey); #endif wrapped_object_len = sizeof(wrapped_object); yrc = yh_util_export_wrapped(session, wrapping_key_id, YH_ASYMMETRIC_KEY, key_id_before, wrapped_object, &wrapped_object_len); assert(yrc == YHR_SUCCESS); printf("Wrapped object (%zu bytes) is:", wrapped_object_len); for (unsigned int i = 0; i < wrapped_object_len; i++) { printf(" %02x", wrapped_object[i]); } printf("\n"); yrc = yh_util_delete_object(session, key_id_before, YH_ASYMMETRIC_KEY); assert(yrc == YHR_SUCCESS); printf("Successfully deleted ed25519 key with ID %04x\n", key_id_before); public_key_after_len = sizeof(public_key_after); yrc = yh_util_get_public_key(session, key_id_before, public_key_after, &public_key_after_len, NULL); assert(yrc == YHR_DEVICE_OBJECT_NOT_FOUND); printf("Unable to get public key for ed25519 key with ID %04x\n", key_id_before); yrc = yh_util_import_wrapped(session, wrapping_key_id, wrapped_object, wrapped_object_len, &object_type_after, &key_id_after); assert(yrc == YHR_SUCCESS); printf("Successfully imported wrapped object with ID %04x\n", key_id_after); if (object_type_after != YH_ASYMMETRIC_KEY) { printf("Unexpected odbject type\n"); exit(EXIT_FAILURE); } if (key_id_before != key_id_after) { printf("ID %04x and %04x do not match\n", key_id_before, key_id_after); exit(EXIT_FAILURE); } else { printf("ID %04x and %04x match\n", key_id_before, key_id_after); } yrc = yh_util_get_public_key(session, key_id_after, public_key_after, &public_key_after_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public ed25519 key after (%zu bytes) is:", public_key_after_len); for (unsigned int i = 0; i < public_key_after_len; i++) { printf(" %02x", public_key_after[i]); } printf("\n"); if (public_key_before_len != public_key_after_len || memcmp(public_key_before, public_key_after, public_key_before_len) != 0) { printf("Public key before and after do not match\n"); exit(EXIT_FAILURE); } else { printf("Public key before and after match\n"); } signature_after_len = sizeof(signature_after); yrc = yh_util_sign_eddsa(session, key_id_after, hashed_data, hashed_data_len, signature_after, &signature_after_len); assert(yrc == YHR_SUCCESS); printf("Signature (%zu bytes) is:", signature_after_len); for (unsigned int i = 0; i < signature_after_len; i++) { printf(" %02x", signature_after[i]); } printf("\n"); assert(signature_after_len == 64); #if (OPENSSL_VERSION_NUMBER < 0x10101000L) || defined(LIBRESSL_VERSION_NUMBER) printf("Signature check skipped for ed25519 key\n"); #else edkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, 0, public_key_after, public_key_after_len); assert(edkey != NULL); edmdctx = EVP_MD_CTX_new(); assert(edmdctx != NULL); assert(EVP_DigestVerifyInit(edmdctx, NULL, NULL, NULL, edkey) > 0); assert(EVP_DigestVerify(edmdctx, signature_after, signature_after_len, hashed_data, hashed_data_len) > 0); EVP_MD_CTX_free(edmdctx); EVP_PKEY_free(edkey); #endif if (signature_before_len != signature_after_len || memcmp(signature_before, signature_after, signature_before_len) != 0) { printf("Signature before and after do not match\n"); exit(EXIT_FAILURE); } else { printf("Signature before and after match\n"); } yrc = yh_util_get_object_info(session, key_id_after, YH_ASYMMETRIC_KEY, &object); assert(yrc == YHR_SUCCESS); yrc = yh_util_delete_object(session, key_id_after, YH_ASYMMETRIC_KEY); assert(yrc == YHR_SUCCESS); printf("Successfully deleted ed25519 key with ID %04x\n", key_id_after); key_id_before = 0; yrc = yh_util_generate_rsa_key(session, &key_id_before, key_label, domain_five, &capabilities, YH_ALGO_RSA_2048); assert(yrc == YHR_SUCCESS); printf("Generated 2048 bit RSA key with ID %04x\n", key_id_before); public_key_before_len = sizeof(public_key_before); yrc = yh_util_get_public_key(session, key_id_before, public_key_before, &public_key_before_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public RSA key before (%zu bytes) is:", public_key_before_len); for (unsigned int i = 0; i < public_key_before_len; i++) { printf(" %02x", public_key_before[i]); } printf("\n"); signature_before_len = sizeof(signature_before); yrc = yh_util_sign_pkcs1v1_5(session, key_id_before, true, hashed_data, hashed_data_len, signature_before, &signature_before_len); assert(yrc == YHR_SUCCESS); printf("Signature (%zu bytes) is:", signature_before_len); for (unsigned int i = 0; i < signature_before_len; i++) { printf(" %02x", signature_before[i]); } printf("\n"); BIGNUM *n = BN_bin2bn(public_key_before, public_key_before_len, NULL); assert(n != NULL); BIGNUM *e = BN_bin2bn((const unsigned char *) "\x01\x00\x01", 3, NULL); assert(e != NULL); RSA *rsa = RSA_new(); assert(RSA_set0_key(rsa, n, e, NULL) != 0); assert(RSA_verify(EVP_MD_type(EVP_sha256()), hashed_data, hashed_data_len, signature_before, signature_before_len, rsa) == 1); printf("RSA signature before successfully verified\n"); RSA_free(rsa); wrapped_object_len = sizeof(wrapped_object); yrc = yh_util_export_wrapped(session, wrapping_key_id, YH_ASYMMETRIC_KEY, key_id_before, wrapped_object, &wrapped_object_len); assert(yrc == YHR_SUCCESS); printf("Wrapped object (%zu bytes) is:", wrapped_object_len); for (unsigned int i = 0; i < wrapped_object_len; i++) { printf(" %02x", wrapped_object[i]); } printf("\n"); yrc = yh_util_delete_object(session, key_id_before, YH_ASYMMETRIC_KEY); assert(yrc == YHR_SUCCESS); printf("Successfully deleted RSA key with ID %04x\n", key_id_before); public_key_after_len = sizeof(public_key_after); yrc = yh_util_get_public_key(session, key_id_before, public_key_after, &public_key_after_len, NULL); assert(yrc == YHR_DEVICE_OBJECT_NOT_FOUND); printf("Unable to get public key for RSA key with ID %04x\n", key_id_before); yrc = yh_util_import_wrapped(session, wrapping_key_id, wrapped_object, wrapped_object_len, &object_type_after, &key_id_after); assert(yrc == YHR_SUCCESS); printf("Successfully imported wrapped object with ID %04x\n", key_id_after); if (object_type_after != YH_ASYMMETRIC_KEY) { printf("Unexpected odbject type\n"); exit(EXIT_FAILURE); } if (key_id_before != key_id_after) { printf("ID %04x and %04x do not match\n", key_id_before, key_id_after); exit(EXIT_FAILURE); } else { printf("ID %04x and %04x match\n", key_id_before, key_id_after); } yrc = yh_util_get_public_key(session, key_id_after, public_key_after, &public_key_after_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public RSA key after (%zu bytes) is:", public_key_after_len); for (unsigned int i = 0; i < public_key_after_len; i++) { printf(" %02x", public_key_after[i]); } printf("\n"); if (public_key_before_len != public_key_after_len || memcmp(public_key_before, public_key_after, public_key_before_len) != 0) { printf("Public key before and after do not match\n"); exit(EXIT_FAILURE); } else { printf("Public key before and after match\n"); } signature_after_len = sizeof(signature_after); yrc = yh_util_sign_pkcs1v1_5(session, key_id_before, true, hashed_data, hashed_data_len, signature_after, &signature_after_len); assert(yrc == YHR_SUCCESS); printf("Signature (%zu bytes) is:", signature_after_len); for (unsigned int i = 0; i < signature_after_len; i++) { printf(" %02x", signature_after[i]); } printf("\n"); n = BN_bin2bn(public_key_after, public_key_after_len, NULL); assert(n != NULL); e = BN_bin2bn((const unsigned char *) "\x01\x00\x01", 3, NULL); assert(e != NULL); rsa = RSA_new(); assert(RSA_set0_key(rsa, n, e, NULL) != 0); assert(RSA_verify(EVP_MD_type(EVP_sha256()), hashed_data, hashed_data_len, signature_after, signature_after_len, rsa) == 1); printf("RSA signature after successfully verified\n"); RSA_free(rsa); yrc = yh_util_get_object_info(session, key_id_after, YH_ASYMMETRIC_KEY, &object); assert(yrc == YHR_SUCCESS); yrc = yh_util_delete_object(session, key_id_after, YH_ASYMMETRIC_KEY); assert(yrc == YHR_SUCCESS); printf("Successfully deleted RSA key with ID %04x\n", key_id_after); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/wrap_data.c0000644000175000017500000000635215167357110017226 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t clear[] = "test data"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("wrap-data:unwrap-data", &capabilities); assert(yrc == YHR_SUCCESS); yh_capabilities delegated_capabilities = {{0}}; uint16_t domain_five = 0; uint16_t wrapping_key_id = 0; // ID 0 lets the device generate an ID yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); yrc = yh_util_generate_wrap_key(session, &wrapping_key_id, key_label, domain_five, &capabilities, YH_ALGO_AES256_CCM_WRAP, &delegated_capabilities); assert(yrc == YHR_SUCCESS); printf("Generated wrapping key with ID %04x\n", wrapping_key_id); uint8_t data[1024]; size_t data_len = sizeof(data); yrc = yh_util_wrap_data(session, wrapping_key_id, clear, sizeof(clear), data, &data_len); assert(yrc == YHR_SUCCESS); printf("Data wrapped to length %zu\n", data_len); assert(data_len == sizeof(clear) + YH_CCM_WRAP_OVERHEAD); assert(memcmp(data, clear, sizeof(clear)) != 0); yrc = yh_util_unwrap_data(session, wrapping_key_id, data, data_len, data, &data_len); assert(yrc == YHR_SUCCESS); assert(data_len == sizeof(clear)); assert(memcmp(data, clear, sizeof(clear)) == 0); printf("Data unwrapped successfully\n"); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/change_authkey.c0000644000175000017500000001157615167357110020247 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include const char *key_label = "label"; const uint8_t password1[] = "password"; const uint8_t password2[] = "letmein!"; const uint8_t password3[] = "PASSWORD"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password1, sizeof(password1) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d using Authentication Key " "%04x\n", session_id, authkey); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("change-authentication-key", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_import_authentication_key_derived(session, &key_id, key_label, domain_five, &capabilities, &capabilities, password2, sizeof(password2)); assert(yrc == YHR_SUCCESS); printf("Imported Authentication Key with ID %04x and password \"%s\"\n", key_id, password2); yrc = yh_util_change_authentication_key_derived(session, &key_id, password3, sizeof(password3)); assert(yrc == YHR_DEVICE_INVALID_ID); printf("Unable to change Authentication Key with ID %04x from this session\n", key_id); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); printf("Closed session %02d\n", session_id); yrc = yh_create_session_derived(connector, key_id, password2, sizeof(password2) - 1, false, &session); assert(yrc == YHR_SUCCESS); yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d using Authentication Key " "%04x\n", session_id, key_id); yrc = yh_util_change_authentication_key_derived(session, &key_id, password3, sizeof(password3)); assert(yrc == YHR_SUCCESS); printf("Successfully changed Authentication Key with ID %04x to password " "\"%s\"\n", key_id, password3); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); printf("Closed session %02d\n", session_id); yrc = yh_create_session_derived(connector, key_id, password2, sizeof(password2) - 1, false, &session); assert(yrc == YHR_DEVICE_AUTHENTICATION_FAILED); printf("Unable to open session with Authentication Key %04x and password " "\"%s\"\n", key_id, password2); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, key_id, password3, sizeof(password3) - 1, false, &session); assert(yrc == YHR_SUCCESS); yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d using Authentcation Key %04x " "and password \"%s\"\n", session_id, key_id, password3); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/p256_pvtkey.pem0000644000175000017500000000045615167357110017720 0ustar aveenaveen-----BEGIN EC PARAMETERS----- BggqhkjOPQMBBw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIHj8HDHmb3sE2LbjB4iOkfh2wngiUJX340mzn9viEm/ZoAoGCCqGSM49 AwEHoUQDQgAESfiuLv9xV/VNf2wLgrMba2jLcjY/DmstGEs2sC9nbR+OhUUia3n1 f/TdJE466eFZ9MIaZNmRsrkwxWbZ1w7yWQ== -----END EC PRIVATE KEY----- yubihsm-shell-2.7.3/examples/import_authkey.c0000644000175000017500000000766015167357110020333 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include const char *key_label = "label"; const uint8_t password1[] = "password"; const uint8_t password2[] = "letmein!"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password1, sizeof(password1) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d using Authentication Keys " "%04x\n", session_id, authkey); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("get-log-entries", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_import_authentication_key_derived(session, &key_id, key_label, domain_five, &capabilities, &capabilities, password2, sizeof(password2)); assert(yrc == YHR_SUCCESS); printf("Imported Authentication Key with ID %04x\n", key_id); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); printf("Closed session %02d\n", session_id); yrc = yh_create_session_derived(connector, key_id, password2, sizeof(password2) - 1, false, &session); assert(yrc == YHR_SUCCESS); yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d using Authentication Key " "%04x\n", session_id, key_id); printf("Trying to get log entries\n"); uint16_t unlogged_boot, unlogged_auth; yh_log_entry logs[YH_MAX_LOG_ENTRIES]; size_t n_items = sizeof(logs) / sizeof(yh_log_entry); yrc = yh_util_get_log_entries(session, &unlogged_boot, &unlogged_auth, logs, &n_items); assert(yrc == YHR_SUCCESS); printf("Got %zu log entries: %s\n", n_items, yh_strerror(yrc)); printf("Trying to get 16 bytes of random data\n"); uint8_t data[16]; size_t data_len = sizeof(data); yrc = yh_util_get_pseudo_random(session, 16, data, &data_len); assert(yrc == YHR_DEVICE_INSUFFICIENT_PERMISSIONS); printf("Unable to get random data: %s\n", yh_strerror(yrc)); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/generate_hmac.c0000644000175000017500000000703615167357110020046 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t data[] = "sudo make me a sandwich"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d using Authentication Key " "%04x\n", session_id, authkey); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("sign-hmac:verify-hmac", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_generate_hmac_key(session, &key_id, key_label, domain_five, &capabilities, YH_ALGO_HMAC_SHA256); assert(yrc == YHR_SUCCESS); printf("Generated HMAC-SHA256 key with ID %04x\n", key_id); uint8_t hmac_data[64]; size_t hmac_data_len = sizeof(hmac_data); yrc = yh_util_sign_hmac(session, key_id, data, sizeof(data) - 1, hmac_data, &hmac_data_len); assert(yrc == YHR_SUCCESS); printf("HMAC of data (%zu bytes) is:", hmac_data_len); for (size_t i = 0; i < hmac_data_len; i++) { printf(" %02x", hmac_data[i]); } printf("\n"); bool verified; yrc = yh_util_verify_hmac(session, key_id, hmac_data, hmac_data_len, data, sizeof(data) - 1, &verified); assert(yrc == YHR_SUCCESS); if (verified == true) { printf("Successfully verified HMAC\n"); } else { printf("Unable to verify HMAC\n"); } hmac_data[0] += 1; yrc = yh_util_verify_hmac(session, key_id, hmac_data, hmac_data_len, data, sizeof(data) - 1, &verified); assert(yrc == YHR_SUCCESS); if (verified == true) { printf("Successfully verified HMAC\n"); } else { printf("Unable to verify HMAC\n"); } yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/generate_ec.c0000644000175000017500000001126515167357110017524 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include #include "util.h" #include const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t data[] = "sudo make me a sandwich"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("sign-ecdsa", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_generate_ec_key(session, &key_id, key_label, domain_five, &capabilities, YH_ALGO_EC_P256); assert(yrc == YHR_SUCCESS); printf("Generated key with ID %04x\n", key_id); printf("Data to sign (%zu bytes) is: %s\n", sizeof(data) - 1, data); EVP_MD_CTX *mdctx = NULL; uint8_t hashed_data[32]; unsigned int hashed_data_len; mdctx = EVP_MD_CTX_create(); assert(mdctx != NULL); EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL); EVP_DigestUpdate(mdctx, data, sizeof(data) - 1); EVP_DigestFinal_ex(mdctx, hashed_data, &hashed_data_len); EVP_MD_CTX_destroy(mdctx); printf("Hash of data (%d bytes) is:", EVP_MD_size(EVP_sha256())); for (unsigned int i = 0; i < hashed_data_len; i++) { printf(" %02x", hashed_data[i]); } printf("\n"); uint8_t signature[128]; size_t signature_len = sizeof(signature); yrc = yh_util_sign_ecdsa(session, key_id, hashed_data, hashed_data_len, signature, &signature_len); assert(yrc == YHR_SUCCESS); printf("Signature (%zu bytes) is:", signature_len); for (unsigned int i = 0; i < signature_len; i++) { printf(" %02x", signature[i]); } printf("\n"); uint8_t public_key[512]; size_t public_key_len = sizeof(public_key); yrc = yh_util_get_public_key(session, key_id, public_key, &public_key_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public key (%zu bytes) is:", public_key_len); for (unsigned int i = 0; i < public_key_len; i++) { printf(" %02x", public_key[i]); } printf("\n"); EC_KEY *eckey = EC_KEY_new(); int nid = algo2nid(YH_ALGO_EC_P256); EC_POINT *point; EC_GROUP *group = EC_GROUP_new_by_curve_name(nid); assert(group != NULL); EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); EC_KEY_set_group(eckey, group); point = EC_POINT_new(group); memmove(public_key + 1, public_key, public_key_len); public_key[0] = 0x04; // hack to make it a valid ec pubkey.. public_key_len++; EC_POINT_oct2point(group, point, public_key, public_key_len, NULL); EC_KEY_set_public_key(eckey, point); if (ECDSA_verify(0, hashed_data, hashed_data_len, signature, signature_len, eckey) == 1) { printf("Signature successfully verified\n"); } else { printf("Unable to verify signature\n"); } EC_POINT_free(point); EC_KEY_free(eckey); EC_GROUP_free(group); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/rsa2048_pvtkey.pem0000644000175000017500000000321315167357110020321 0ustar aveenaveen-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA1LILtPHUKTGvzNKpNHCSmRfE54NoabtPtV/SqAI/6VFT1PIf dLBUsBL19g4yAfnyOSTo5o8CYl6LzfdPgkyESXKzOYCKuBDEn14yQ/F1vzzydl5G a65dESVCFKUELu9IJwX1hjXpHLkwb9Wj8Z4h/Uikn6Xh3C6GvVOIJZGb9Kjcz+Mo Kx9IFAFAIWDV88DKUG9EontXYq4p2Vk6/XvAW63eQPWjUWeOSUiQp8UWtWA3SMZ9 GwxUh9ZRyd4gw1kqcrqMzwbJyEtmjBbYNnIGPYDCkr4YQJIoGPwNq6hh2HGa1J+M EYYZWVbl2GOW1FVMn75q45tnaCaWOlT0H7Om/wIDAQABAoIBAByVHJuhT9iFU9Gb kZ95bUnjdtOBxjtHL6v5B48KVlpdUn2wV+fPdmH++kyplbDMTO++9QleuHxNpk30 aRvieniAUHNuwbWAk1uzRd/5h9A+OXsMqjv4P4t5TUsG7ev8vd54n4j8n6n7fPXa aOCkVn76Dx1hJlv3aKXynr4ltiaHeABXz2ph5f7wHsC9cEqXjr4Tt+sXu9tURKMq hGNNYFgJPIsa0q07dqClJtNxS0hCkCp4gEFjsCVLFPzxEP+TU8OND7eNgXqQ9TYG zQGNEVN2Dmk/HFatTRnKY2wqlYjfFXhUsubVSPm0krIU04JeBgqo/B7u20G3wwW/ EWhA8skCgYEA73gkpHxKnykzJBx3jbPNgcegBJA2cqv7IonOO+KG1nqccnOzzYZX DFrEqemVuESPUSz1dzvilKkb2Fz+t8PFg9Qq4nV2Oa7h5TYp05T6dyuwrcmoPiIM 9kT7YGohaucf9EqRIYkjMbefWn9reiXKOztemD8Nq40GqT96zWdll+0CgYEA42DC vHnNS3ChPN6ueiiGrSYNiu0o35/+Zv0/YAXF69gC118qtBof8lVr74/vSE3SqNyh /8y8WhM/TlErZSSKoUZCIkQE3LhIsbR0Nh95RwY0It/jbnVTwb11/PkILfvaQlwQ 8DM2WXYg39QdPlYw1GNTvKuAYtzeROUqOoF5BRsCgYEA3qDTcBgdR9sFsIzGmPaQ GBd+rL9l3zYERBfZo9L1iHB1AfKPNoOuac35B/4hMy6KDu29Rxxlic+uE3hhVnar KeQV+nM5dmcfm/i+6fWW5TO5DdhskVcWtd1r1jbU2o4FJxgr1QGpto7/lyLeyLBZ UrffOatlChgSGUbq5As8aAECgYAogmivY5PryNkxGwtCwE2eM5VeFvqdPMf6WUwd M2obppR7An19MNpYNlfQing7DYJmi0hhZnx4H827ikKM9oGsUfQeXrfvCvYIkvnR WrIksTpArFq8pzKQ5cxLkaKfbqtn/zcVVEpujdk1h3jeTkTM0hVtG7D37Bm9dIad fcut2QKBgGwhl9lil+kDVkmWajQGHzxrct1hWlcn8hsXcO6bu8TGSYTjeT0XQUog OjdB5pTbPXncE/3ExaMttiBV8eLkhW+HRXq+IxyWPG3ROu5N1tTxBtV7X5tkzY9m V5rUvEN+bLOUGLGA4qd66j5DC0QwP1gaAHlpnMoipNvgXmEcriSu -----END RSA PRIVATE KEY----- yubihsm-shell-2.7.3/examples/import_ec.c0000644000175000017500000001220715167357110017241 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include #include "util.h" #include const char p256_pvtkey_file[] = "p256_pvtkey.pem"; const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t data[] = "sudo make me a sandwich"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); FILE *fp = fopen(p256_pvtkey_file, "rb"); assert(fp != NULL); yh_algorithm algorithm = 0; uint8_t key[2048]; size_t key_material_len = sizeof(key); if (!read_file(fp, key, &key_material_len)) { assert(false); } bool ret = read_private_key(key, key_material_len, &algorithm, key, &key_material_len, false); assert(ret == true); assert(algorithm == YH_ALGO_EC_P256); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("sign-ecdsa", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_import_ec_key(session, &key_id, key_label, domain_five, &capabilities, algorithm, key); assert(yrc == YHR_SUCCESS); printf("Key imported with ID %04x\n", key_id); printf("Data to sign (%zu bytes) is: %s\n", sizeof(data) - 1, data); EVP_MD_CTX *mdctx = NULL; uint8_t hashed_data[32]; unsigned int hashed_data_len; mdctx = EVP_MD_CTX_create(); assert(mdctx != NULL); EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL); EVP_DigestUpdate(mdctx, data, sizeof(data) - 1); EVP_DigestFinal_ex(mdctx, hashed_data, &hashed_data_len); EVP_MD_CTX_destroy(mdctx); printf("Hash of data (%d bytes) is:", EVP_MD_size(EVP_sha256())); for (unsigned int i = 0; i < hashed_data_len; i++) { printf(" %02x", hashed_data[i]); } printf("\n"); uint8_t signature[128]; size_t signature_len = sizeof(signature); yrc = yh_util_sign_ecdsa(session, key_id, hashed_data, hashed_data_len, signature, &signature_len); assert(yrc == YHR_SUCCESS); printf("Signature (%zu bytes) is:", signature_len); for (unsigned int i = 0; i < signature_len; i++) { printf(" %02x", signature[i]); } printf("\n"); uint8_t public_key[512]; size_t public_key_len = sizeof(public_key); yrc = yh_util_get_public_key(session, key_id, public_key, &public_key_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public key (%zu bytes) is:", public_key_len); for (unsigned int i = 0; i < public_key_len; i++) { printf(" %02x", public_key[i]); } printf("\n"); EC_KEY *eckey = EC_KEY_new(); int nid = algo2nid(YH_ALGO_EC_P256); EC_POINT *point; EC_GROUP *group = EC_GROUP_new_by_curve_name(nid); assert(group != NULL); EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); EC_KEY_set_group(eckey, group); point = EC_POINT_new(group); memmove(public_key + 1, public_key, public_key_len); public_key[0] = 0x04; // hack to make it a valid ec pubkey.. public_key_len++; EC_POINT_oct2point(group, point, public_key, public_key_len, NULL); EC_KEY_set_public_key(eckey, point); if (ECDSA_verify(0, hashed_data, hashed_data_len, signature, signature_len, eckey) == 1) { printf("Signature successfully verified\n"); } else { printf("Unable to verify signature\n"); } EC_POINT_free(point); EC_KEY_free(eckey); EC_GROUP_free(group); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/attest.c0000644000175000017500000002452715167357110016574 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include "openssl-compat.h" #include "util.h" const char attestation_template_file[] = "attestation_template.pem"; const char *key_label = "label"; const uint8_t password[] = "password"; static void print_extension(X509_EXTENSION *extension) { // Quick and dirty solution for printing extensions const uint8_t version[] = {0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x04, 0x01}; const uint8_t serial[] = {0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x04, 0x02}; const uint8_t origin[] = {0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x04, 0x03}; const uint8_t domains[] = {0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x04, 0x04}; const uint8_t capabilities[] = {0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x04, 0x05}; const uint8_t id[] = {0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x04, 0x06}; const uint8_t label[] = {0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, 0x04, 0x09}; ASN1_OBJECT *a_object = X509_EXTENSION_get_object(extension); ASN1_OCTET_STRING *a_value = X509_EXTENSION_get_data(extension); uint8_t object[1024]; uint8_t *ptr = object; if (i2d_ASN1_OBJECT(a_object, NULL) > 1024) { printf("Extension to long.\n"); return; } unsigned int object_len = i2d_ASN1_OBJECT(a_object, &ptr); uint8_t value[1024]; ptr = value; if (i2d_ASN1_OCTET_STRING(a_value, NULL) > 1024) { printf("Extension value to long.\n"); return; } unsigned int value_len = i2d_ASN1_OCTET_STRING(a_value, &ptr); if (object_len == sizeof(version) && memcmp(object, version, sizeof(version)) == 0) { printf("Version:"); } else if (object_len == sizeof(serial) && memcmp(object, serial, sizeof(serial)) == 0) { printf("Serial:"); } else if (object_len == sizeof(origin) && memcmp(object, origin, sizeof(origin)) == 0) { printf("Origin:"); } else if (object_len == sizeof(domains) && memcmp(object, domains, sizeof(domains)) == 0) { printf("Domains:"); } else if (object_len == sizeof(capabilities) && memcmp(object, capabilities, sizeof(capabilities)) == 0) { printf("Capabilities:"); } else if (object_len == sizeof(id) && memcmp(object, id, sizeof(id)) == 0) { printf("ID:"); } else if (object_len == sizeof(label) && memcmp(object, label, sizeof(label)) == 0) { printf("Label:"); } else { printf("Unknown:"); } for (unsigned int i = 0; i < value_len; i++) { printf(" %02x", value[i]); } printf("\n"); } int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("sign-attestation-certificate", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t attesting_key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_generate_ec_key(session, &attesting_key_id, key_label, domain_five, &capabilities, YH_ALGO_EC_P256); assert(yrc == YHR_SUCCESS); printf("Generated attesting key with ID %04x\n", attesting_key_id); uint8_t public_key[256]; size_t public_key_len = sizeof(public_key) - 1; yh_algorithm algo; yrc = yh_util_get_public_key(session, attesting_key_id, public_key + 1, &public_key_len, &algo); assert(yrc == YHR_SUCCESS); public_key[0] = 0x04; // hack to make it a valid ec pubkey.. public_key_len++; int nid = algo2nid(algo); assert(nid); EC_GROUP *group = EC_GROUP_new_by_curve_name(nid); assert(group != NULL); EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); EC_POINT *point = EC_POINT_new(group); assert(point != NULL); assert(EC_POINT_oct2point(group, point, public_key, public_key_len, NULL)); EC_KEY *eckey = EC_KEY_new(); assert(eckey != NULL); assert(EC_KEY_set_group(eckey, group)); assert(EC_KEY_set_public_key(eckey, point)); EVP_PKEY *attesting_key = EVP_PKEY_new(); assert(attesting_key != NULL); assert(EVP_PKEY_set1_EC_KEY(attesting_key, eckey) == 1); EC_KEY_free(eckey); FILE *fp = fopen(attestation_template_file, "rb"); assert(fp != NULL); X509 *attestation_template = PEM_read_X509(fp, NULL, NULL, NULL); assert(attestation_template != NULL); fclose(fp); uint8_t attestation_template_buffer[3072]; uint16_t attestation_template_buffer_len = i2d_X509(attestation_template, NULL); assert(sizeof(attestation_template_buffer) >= attestation_template_buffer_len); unsigned char *certptr = attestation_template_buffer; i2d_X509(attestation_template, &certptr); X509_free(attestation_template); memset(capabilities.capabilities, 0, YH_CAPABILITIES_LEN); yrc = yh_util_import_opaque(session, &attesting_key_id, key_label, domain_five, &capabilities, YH_ALGO_OPAQUE_X509_CERTIFICATE, attestation_template_buffer, attestation_template_buffer_len); assert(yrc == YHR_SUCCESS); uint8_t tmpbuf[3072]; size_t tmpbuf_len = sizeof(tmpbuf); yrc = yh_util_get_opaque(session, attesting_key_id, tmpbuf, &tmpbuf_len); assert(yrc == YHR_SUCCESS); assert(tmpbuf_len == attestation_template_buffer_len); assert(memcmp(attestation_template_buffer, tmpbuf, tmpbuf_len) == 0); memset(capabilities.capabilities, 0, YH_CAPABILITIES_LEN); yrc = yh_string_to_capabilities("sign-ecdsa", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t attested_key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_generate_ec_key(session, &attested_key_id, key_label, domain_five, &capabilities, YH_ALGO_EC_P256); assert(yrc == YHR_SUCCESS); printf("Generated attested key with ID %04x\n", attested_key_id); uint8_t attestation[2048]; size_t attestation_len = sizeof(attestation); yrc = yh_util_sign_attestation_certificate(session, attested_key_id, attesting_key_id, attestation, &attestation_len); assert(yrc == YHR_SUCCESS); const unsigned char *ptr = attestation; X509 *x509 = d2i_X509(NULL, &ptr, attestation_len); assert(x509 != NULL); BIO *STDout = BIO_new_fp(stdout, BIO_NOCLOSE); X509_print_ex(STDout, x509, 0, 0); BIO_free(STDout); const STACK_OF(X509_EXTENSION) *extensions_list = X509_get0_extensions(x509); assert(sk_X509_EXTENSION_num(extensions_list) >= 6); for (int i = 0; i < sk_X509_EXTENSION_num(extensions_list); i++) { X509_EXTENSION *extension = sk_X509_EXTENSION_value(extensions_list, i); print_extension(extension); } assert(X509_verify(x509, attesting_key)); X509_free(x509); attestation_len = sizeof(attestation); yrc = yh_util_sign_attestation_certificate(session, attesting_key_id, attesting_key_id, attestation, &attestation_len); assert(yrc == YHR_SUCCESS); ptr = attestation; x509 = d2i_X509(NULL, &ptr, attestation_len); assert(x509 != NULL); STDout = BIO_new_fp(stdout, BIO_NOCLOSE); X509_print_ex(STDout, x509, 0, 0); BIO_free(STDout); extensions_list = X509_get0_extensions(x509); assert(sk_X509_EXTENSION_num(extensions_list) >= 6); for (int i = 0; i < sk_X509_EXTENSION_num(extensions_list); i++) { X509_EXTENSION *extension = sk_X509_EXTENSION_value(extensions_list, i); print_extension(extension); } assert(X509_verify(x509, attesting_key)); #ifdef ATTEST_DEVICE_PUBKEY X509_free(x509); attestation_len = sizeof(attestation); yrc = yh_util_sign_attestation_certificate(session, 0, attesting_key_id, attestation, &attestation_len); assert(yrc == YHR_SUCCESS); ptr = attestation; x509 = d2i_X509(NULL, &ptr, attestation_len); assert(x509 != NULL); STDout = BIO_new_fp(stdout, BIO_NOCLOSE); X509_print_ex(STDout, x509, 0, 0); BIO_free(STDout); extensions_list = X509_get0_extensions(x509); assert(sk_X509_EXTENSION_num(extensions_list) >= 6); for (int i = 0; i < sk_X509_EXTENSION_num(extensions_list); i++) { X509_EXTENSION *extension = sk_X509_EXTENSION_value(extensions_list, i); print_extension(extension); } assert(X509_verify(x509, attesting_key)); #endif X509_free(x509); EVP_PKEY_free(attesting_key); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yrc = yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/CMakeLists.txt0000644000175000017500000001335215167357110017656 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(${CMAKE_SOURCE_DIR}/cmake/openssl.cmake) find_libcrypto() set ( SOURCE_IMPORT_RSA import_rsa.c ../common/hash.c ../common/util.c ../common/openssl-compat.c ) set ( SOURCE_GENERATE_EC generate_ec.c ../common/hash.c ../common/util.c ../common/openssl-compat.c ) set ( SOURCEINFO info.c ) set ( SOURCE_IMPORT_AUTHKEY import_authkey.c ) set ( SOURCE_GENERATE_HMAC generate_hmac.c ) set ( SOURCE_WRAP wrap.c ../common/util.c ../common/hash.c ../common/openssl-compat.c ) set ( SOURCE_WRAP_DATA wrap_data.c ) set ( SOURCE_ATTEST attest.c ../common/util.c ../common/hash.c ../common/openssl-compat.c ) set ( SOURCE_YUBICO_OTP yubico_otp.c ) set ( SOURCE_ECHO echo.c ) set ( SOURCE_ASYM_AUTH asym_auth.c ../common/openssl-compat.c ) set ( SOURCE_IMPORT_EC import_ec.c ../common/hash.c ../common/util.c ../common/openssl-compat.c ) set ( SOURCE_GENERATE_RSA generate_rsa.c ../common/openssl-compat.c ) set ( SOURCE_LOGS logs.c ../common/hash.c ../common/util.c ../common/openssl-compat.c ) set ( SOURCE_SSH ssh.c ../common/hash.c ../common/util.c ../common/openssl-compat.c ) set ( SOURCE_DECRYPT_RSA decrypt_rsa.c ../common/hash.c ../common/util.c ../common/openssl-compat.c ) set ( SOURCE_P11_GENERATE_RSA p11_generate_rsa.c ../common/openssl-compat.c ) set ( SOURCE_DECRYPT_EC decrypt_ec.c ../common/hash.c ../common/util.c ../common/openssl-compat.c ) set ( SOURCE_IMPORT_ED import_ed.c ../common/hash.c ../common/util.c ../common/openssl-compat.c ) set ( SOURCE_CHANGE_AUTHKEY change_authkey.c ) set( SOURCE_ENCRYPT_AES encrypt_aes.c ) include_directories ( ${LIBCRYPTO_INCLUDEDIR} ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${CMAKE_CURRENT_SOURCE_DIR}/../pkcs11 ${CMAKE_CURRENT_SOURCE_DIR}/../common ) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/rsa2048_pvtkey.pem ${CMAKE_CURRENT_BINARY_DIR}/rsa2048_pvtkey.pem COPYONLY) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/p256_pvtkey.pem ${CMAKE_CURRENT_BINARY_DIR}/p256_pvtkey.pem COPYONLY) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/attestation_template.pem ${CMAKE_CURRENT_BINARY_DIR}/attestation_template.pem COPYONLY) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/ssh_ca_pvtkey.pem ${CMAKE_CURRENT_BINARY_DIR}/ssh_ca_pvtkey.pem COPYONLY) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/ssh_req.dat ${CMAKE_CURRENT_BINARY_DIR}/ssh_req.dat COPYONLY) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/ed25519_pvtkey.pem ${CMAKE_CURRENT_BINARY_DIR}/ed25519_pvtkey.pem COPYONLY) add_executable (import_rsa ${SOURCE_IMPORT_RSA}) target_link_libraries ( import_rsa ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (generate_ec ${SOURCE_GENERATE_EC}) target_link_libraries ( generate_ec ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (info ${SOURCEINFO}) target_link_libraries ( info ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (import_authkey ${SOURCE_IMPORT_AUTHKEY}) target_link_libraries ( import_authkey ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (generate_hmac ${SOURCE_GENERATE_HMAC}) target_link_libraries ( generate_hmac ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (wrap ${SOURCE_WRAP}) target_link_libraries ( wrap ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (wrap_data ${SOURCE_WRAP_DATA}) target_link_libraries ( wrap_data ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (attest ${SOURCE_ATTEST}) target_link_libraries ( attest ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (yubico_otp ${SOURCE_YUBICO_OTP}) target_link_libraries ( yubico_otp ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (echo ${SOURCE_ECHO}) target_link_libraries ( echo ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (asym_auth ${SOURCE_ASYM_AUTH}) target_link_libraries ( asym_auth ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (import_ec ${SOURCE_IMPORT_EC}) target_link_libraries ( import_ec ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (generate_rsa ${SOURCE_GENERATE_RSA}) target_link_libraries ( generate_rsa ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (logs ${SOURCE_LOGS}) target_link_libraries ( logs ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (ssh ${SOURCE_SSH}) target_link_libraries ( ssh ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (decrypt_rsa ${SOURCE_DECRYPT_RSA}) target_link_libraries ( decrypt_rsa ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (decrypt_ec ${SOURCE_DECRYPT_EC}) target_link_libraries ( decrypt_ec ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (import_ed ${SOURCE_IMPORT_ED}) target_link_libraries ( import_ed ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable (change_authkey ${SOURCE_CHANGE_AUTHKEY}) target_link_libraries ( change_authkey ${LIBCRYPTO_LDFLAGS} yubihsm ) add_executable(encrypt_aes ${SOURCE_ENCRYPT_AES}) target_link_libraries( encrypt_aes yubihsm ) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") add_executable (p11_generate_rsa ${SOURCE_P11_GENERATE_RSA}) target_link_libraries ( p11_generate_rsa ${LIBCRYPTO_LDFLAGS} dl ) endif() yubihsm-shell-2.7.3/examples/ed25519_pvtkey.pem0000644000175000017500000000016715167357110020221 0ustar aveenaveen-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7 -----END PRIVATE KEY----- yubihsm-shell-2.7.3/examples/yubico_otp.c0000644000175000017500000002103615167357110017434 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t otp_key[] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f}; static const struct { uint8_t key[16]; uint8_t id[6]; uint16_t use_counter; uint16_t timestamp_low; uint8_t timestamp_high; uint8_t session_counter; uint16_t random; uint16_t crc; uint8_t otp[32]; } test_vectors[] = {{{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, 0x0001, 0x0001, 0x01, 0x01, 0x0000, 0xfe36, {0x2f, 0x5d, 0x71, 0xa4, 0x91, 0x5d, 0xec, 0x30, 0x4a, 0xa1, 0x3c, 0xcf, 0x97, 0xbb, 0x0d, 0xbb}}, {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, 0x0001, 0x0001, 0x01, 0x02, 0x0000, 0x1152, {0xcb, 0x71, 0x0b, 0x46, 0x2b, 0x7b, 0x1c, 0x23, 0x10, 0x0c, 0xb2, 0x46, 0x85, 0xb6, 0x4d, 0x33}}, {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, 0x0fff, 0x0001, 0x01, 0x01, 0x0000, 0x9454, {0x77, 0x99, 0x78, 0x12, 0x9b, 0xcc, 0x26, 0x42, 0xc8, 0xad, 0xf5, 0xc1, 0x99, 0x81, 0xa0, 0x16}}, {{0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, {0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, 0x8888, 0x8888, 0x88, 0x88, 0x8888, 0xd3b6, {0x20, 0x76, 0x5f, 0xc6, 0x83, 0xe0, 0xfc, 0x7b, 0x62, 0x42, 0x21, 0x86, 0x48, 0x4d, 0x82, 0x37}}, {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x0000, 0x0000, 0x00, 0x00, 0x0000, 0xa96a, {0x99, 0x9b, 0x08, 0xbf, 0x0b, 0x3b, 0x98, 0xf8, 0x5b, 0x08, 0x76, 0xa8, 0x77, 0x15, 0x16, 0x16}}, {{0xc4, 0x42, 0x28, 0x90, 0x65, 0x30, 0x76, 0xcd, 0xe7, 0x3d, 0x44, 0x9b, 0x19, 0x1b, 0x41, 0x6a}, {0x33, 0xc6, 0x9e, 0x7f, 0x24, 0x9e}, 0x0001, 0x13a7, 0x24, 0x00, 0xc63c, 0x1c86, {0x7e, 0x0f, 0xc9, 0x87, 0x35, 0x16, 0x72, 0xc0, 0x70, 0xfa, 0x5c, 0x05, 0x95, 0xec, 0x68, 0xb8}}}; static uint16_t yubikey_crc16(const uint8_t *buf, size_t buf_size) { uint16_t m_crc = 0xffff; while (buf_size--) { int i, j; m_crc ^= (uint8_t) *buf++ & 0xFF; for (i = 0; i < 8; i++) { j = m_crc & 1; m_crc >>= 1; if (j) { m_crc ^= 0x8408; } } } return m_crc; } int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("create-otp-aead:decrypt-otp:randomize-otp-aead", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 16; // Domain five is 0b0000000000010000 uint16_t key_id = 0; // ID 0 lets the device generate an ID uint32_t nonce_id = 0x12345678; yrc = yh_util_generate_otp_aead_key(session, &key_id, key_label, domain_five, &capabilities, YH_ALGO_AES128_YUBICO_OTP, nonce_id); assert(yrc == YHR_SUCCESS); printf("Generated OTP key with ID %04x\n", key_id); yrc = yh_util_delete_object(session, key_id, YH_OTP_AEAD_KEY); assert(yrc == YHR_SUCCESS); yrc = yh_util_import_otp_aead_key(session, &key_id, key_label, domain_five, &capabilities, nonce_id, otp_key, sizeof(otp_key)); assert(yrc == YHR_SUCCESS); for (size_t i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) { uint8_t aead[512]; size_t aead_len = sizeof(aead); yrc = yh_util_create_otp_aead(session, key_id, test_vectors[i].key, test_vectors[i].id, aead, &aead_len); assert(yrc == YHR_SUCCESS); uint16_t use_counter; uint16_t timestamp_low; uint8_t timestamp_high; uint8_t session_counter; printf("Checking test vector %zu ... ", i); yrc = yh_util_decrypt_otp(session, key_id, aead, aead_len, test_vectors[i].otp, &use_counter, &session_counter, ×tamp_high, ×tamp_low); assert(yrc == YHR_SUCCESS); assert(test_vectors[i].use_counter == use_counter); assert(test_vectors[i].session_counter == session_counter); assert(test_vectors[i].timestamp_high == timestamp_high); assert(test_vectors[i].timestamp_low == timestamp_low); printf("OK\n"); } printf("Put OTP key with ID %04x\n", key_id); uint8_t otp_data[64]; size_t otp_data_len = sizeof(otp_data); size_t tag_len = 8; size_t nonce_len = 13; uint8_t nonce[13] = {0}; uint8_t out_buf[32]; int out_len; yrc = yh_util_randomize_otp_aead(session, key_id, otp_data, &otp_data_len); assert(yrc == YHR_SUCCESS); EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); // Select cipher assert(EVP_DecryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL) == 1); // Set nonce length assert(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, nonce_len, NULL) == 1); // Set expected tag value assert(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, otp_data + otp_data_len - tag_len) == 1); // Specify key and IV memcpy(nonce, &nonce_id, 4); memcpy(nonce + 4, otp_data, 6); assert(EVP_DecryptInit_ex(ctx, NULL, NULL, otp_key, nonce) == 1); // Decrypt plaintext, verify tag: can only be called once assert(EVP_DecryptUpdate(ctx, out_buf, &out_len, otp_data + 6, otp_data_len - 6 - tag_len) == 1); EVP_CIPHER_CTX_free(ctx); struct { union { struct { uint8_t id[6]; uint16_t use_counter; uint16_t timestamp_low; uint8_t timestamp_high; uint8_t session_counter; uint16_t rnd; uint16_t crc; }; uint8_t raw[16]; }; } token = {.raw = {0}}; uint8_t otp[16] = {0}; memcpy(token.id, out_buf + 16, 6); token.use_counter = 0xabcd; token.timestamp_low = 0xdcba; token.timestamp_high = 0xff; token.session_counter = 0x00; token.crc = ~yubikey_crc16(token.raw, 14); AES_KEY k; AES_set_encrypt_key(out_buf, 128, &k); AES_ecb_encrypt(token.raw, otp, &k, AES_ENCRYPT); uint16_t use_counter; uint16_t timestamp_low; uint8_t timestamp_high; uint8_t session_counter; yrc = yh_util_decrypt_otp(session, key_id, otp_data, otp_data_len, otp, &use_counter, &session_counter, ×tamp_high, ×tamp_low); assert(yrc == YHR_SUCCESS); assert(use_counter == token.use_counter); assert(timestamp_low == token.timestamp_low); assert(timestamp_high == token.timestamp_high); assert(session_counter == token.session_counter); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/generate_rsa.c0000644000175000017500000001057115167357110017721 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include "util.h" #include "openssl-compat.h" #include const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t data[] = "sudo make me a sandwich"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("sign-pkcs", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_generate_rsa_key(session, &key_id, key_label, domain_five, &capabilities, YH_ALGO_RSA_2048); assert(yrc == YHR_SUCCESS); printf("Generated key with ID %04x\n", key_id); printf("Data to sign (%zu bytes) is: %s\n", sizeof(data) - 1, data); EVP_MD_CTX *mdctx = NULL; uint8_t hashed_data[32]; unsigned int hashed_data_len; mdctx = EVP_MD_CTX_create(); assert(mdctx != NULL); EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL); EVP_DigestUpdate(mdctx, data, sizeof(data) - 1); EVP_DigestFinal_ex(mdctx, hashed_data, &hashed_data_len); EVP_MD_CTX_destroy(mdctx); printf("Hash of data (%d bytes) is:", EVP_MD_size(EVP_sha256())); for (unsigned int i = 0; i < hashed_data_len; i++) { printf(" %02x", hashed_data[i]); } printf("\n"); uint8_t signature[512]; size_t signature_len = sizeof(signature); yrc = yh_util_sign_pkcs1v1_5(session, key_id, true, hashed_data, hashed_data_len, signature, &signature_len); assert(yrc == YHR_SUCCESS); printf("Signature (%zu bytes) is:", signature_len); for (unsigned int i = 0; i < signature_len; i++) { printf(" %02x", signature[i]); } printf("\n"); uint8_t public_key[512]; size_t public_key_len = sizeof(public_key); yrc = yh_util_get_public_key(session, key_id, public_key, &public_key_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public key (%zu bytes) is:", public_key_len); for (unsigned int i = 0; i < public_key_len; i++) { printf(" %02x", public_key[i]); } printf("\n"); BIGNUM *n = BN_bin2bn(public_key, public_key_len, NULL); assert(n != NULL); BIGNUM *e = BN_bin2bn((const unsigned char *) "\x01\x00\x01", 3, NULL); assert(e != NULL); RSA *rsa = RSA_new(); assert(RSA_set0_key(rsa, n, e, NULL) != 0); if (RSA_verify(EVP_MD_type(EVP_sha256()), hashed_data, hashed_data_len, signature, signature_len, rsa) == 1) { printf("Signature successfully verified\n"); } else { printf("Unable to verify signature\n"); } RSA_free(rsa); rsa = NULL; yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/import_rsa.c0000644000175000017500000001256515167357110017446 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include "util.h" #include "openssl-compat.h" #include const char rsa2048_pvtkey_file[] = "rsa2048_pvtkey.pem"; const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t data[] = "sudo make me a sandwich"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); FILE *fp = fopen(rsa2048_pvtkey_file, "rb"); assert(fp != NULL); yh_algorithm algorithm = 0; uint8_t privkey[2048]; size_t key_material_len = sizeof(privkey); if (!read_file(fp, privkey, &key_material_len)) { assert(false); } bool ret = read_private_key(privkey, key_material_len, &algorithm, privkey, &key_material_len, false); assert(ret == true); assert(algorithm == YH_ALGO_RSA_2048); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("sign-pss", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_import_rsa_key(session, &key_id, key_label, domain_five, &capabilities, algorithm, privkey, privkey + (key_material_len / 2)); assert(yrc == YHR_SUCCESS); printf("Key imported with ID %04x\n", key_id); printf("Data to sign (%zu bytes) is: %s\n", sizeof(data) - 1, data); EVP_MD_CTX *mdctx = NULL; uint8_t hashed_data[32]; unsigned int hashed_data_len; mdctx = EVP_MD_CTX_create(); assert(mdctx != NULL); EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL); EVP_DigestUpdate(mdctx, data, sizeof(data) - 1); EVP_DigestFinal_ex(mdctx, hashed_data, &hashed_data_len); EVP_MD_CTX_destroy(mdctx); printf("Hash of data (%d bytes) is:", EVP_MD_size(EVP_sha256())); for (unsigned int i = 0; i < hashed_data_len; i++) { printf(" %02x", hashed_data[i]); } printf("\n"); uint8_t signature[512]; size_t signature_len = sizeof(signature); yrc = yh_util_sign_pss(session, key_id, hashed_data, hashed_data_len, signature, &signature_len, 32, YH_ALGO_MGF1_SHA256); assert(yrc == YHR_SUCCESS); printf("Signature (%zu bytes) is:", signature_len); for (unsigned int i = 0; i < signature_len; i++) { printf(" %02x", signature[i]); } printf("\n"); uint8_t public_key[512]; size_t public_key_len = sizeof(public_key); yrc = yh_util_get_public_key(session, key_id, public_key, &public_key_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public key (%zu bytes) is:", public_key_len); for (unsigned int i = 0; i < public_key_len; i++) { printf(" %02x", public_key[i]); } printf("\n"); BIGNUM *n = BN_bin2bn(public_key, public_key_len, NULL); assert(n != NULL); BIGNUM *e = BN_bin2bn((const unsigned char *) "\x01\x00\x01", 3, NULL); assert(e != NULL); RSA *rsa = RSA_new(); assert(RSA_set0_key(rsa, n, e, NULL) != 0); EVP_PKEY *key = EVP_PKEY_new(); assert(EVP_PKEY_assign_RSA(key, rsa) == 1); EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key, NULL); assert(ctx != NULL); assert(EVP_PKEY_verify_init(ctx) == 1); assert(EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) == 1); assert(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) == 1); assert(EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, 32) == 1); assert(EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256()) == 1); if (EVP_PKEY_verify(ctx, signature, signature_len, hashed_data, hashed_data_len) == 1) { printf("Signature successfully verified\n"); } else { printf("Unable to verify signature\n"); } EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(key); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/decrypt_rsa.c0000644000175000017500000001172515167357110017603 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include "util.h" #include #include "openssl-compat.h" const char rsa2048_pvtkey_file[] = "rsa2048_pvtkey.pem"; const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t data[] = "sudo make me a sandwich"; const uint8_t sha1_empty_string[] = {0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09}; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); FILE *fp = fopen(rsa2048_pvtkey_file, "rb"); assert(fp != NULL); yh_algorithm algorithm = 0; uint8_t key[2048]; size_t key_material_len = sizeof(key); if (!read_file(fp, key, &key_material_len)) { assert(false); } bool ret2 = read_private_key(key, key_material_len, &algorithm, key, &key_material_len, false); assert(ret2 == true); assert(algorithm == YH_ALGO_RSA_2048); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_import_rsa_key(session, &key_id, key_label, domain_five, &capabilities, algorithm, key, key + (key_material_len / 2)); assert(yrc == YHR_SUCCESS); printf("Key imported with ID %04x\n", key_id); uint8_t public_key[512]; size_t public_key_len = sizeof(public_key); yrc = yh_util_get_public_key(session, key_id, public_key, &public_key_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public key (%zu bytes) is:", public_key_len); for (unsigned int i = 0; i < public_key_len; i++) { printf(" %02x", public_key[i]); } printf("\n"); BIGNUM *n = BN_bin2bn(public_key, public_key_len, NULL); assert(n != NULL); BIGNUM *e = BN_bin2bn((const unsigned char *) "\x01\x00\x01", 3, NULL); assert(e != NULL); RSA *rsa = RSA_new(); assert(RSA_set0_key(rsa, n, e, NULL) != 0); uint8_t encrypted[512]; int ret = RSA_public_encrypt(sizeof(data), data, encrypted, rsa, RSA_PKCS1_PADDING); assert(ret == RSA_size(rsa)); uint8_t decrypted[512]; size_t decrypted_len = sizeof(decrypted); yrc = yh_util_decrypt_pkcs1v1_5(session, key_id, encrypted, ret, decrypted, &decrypted_len); assert(yrc == YHR_SUCCESS); assert(memcmp(data, decrypted, decrypted_len) == 0); printf("PKCS1v1.5 decrypted data matches\n"); ret = RSA_public_encrypt(sizeof(data), data, encrypted, rsa, RSA_PKCS1_OAEP_PADDING); assert(ret == RSA_size(rsa)); decrypted_len = sizeof(decrypted); yrc = yh_util_decrypt_oaep(session, key_id, encrypted, ret, decrypted, &decrypted_len, (const uint8_t *) sha1_empty_string, sizeof(sha1_empty_string), YH_ALGO_MGF1_SHA1); assert(yrc == YHR_SUCCESS); assert(memcmp(data, decrypted, decrypted_len) == 0); printf("OAEP decrypted data matches\n"); RSA_free(rsa); rsa = NULL; yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/ssh_ca_pvtkey.pem0000644000175000017500000000321715167357110020462 0ustar aveenaveen-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA0zWtGoriTQmqtCmLHr3JQSK+EdMOqyXtvF4vqvJIFFsU7uMD m/FShw1hCVFgyZu7P77+RUaIMAUEbtYKF4vYvPPxUFDL1YyHF6VsNvwkMNDSmRZy D6lH5D/QFcGGZtn6Rz1SfJuynrT+/ZltM/NroddaITA23NSmJrIi/lwm5vruvFQJ 7JD4+tiR8iLOqWsGXlUtIXDt09sQs+/HCbziHUeoWP8TSphKfc6LjNtSx6pmynC2 wRF7LYd0Cm7Nq0HQ+xPxuaBBWeqdKUJ7/0Rqt7smrGGcqWu3P9yxcxiYVlFgZSBA UVjHMYaCRiWZKPs6wDTYnJOBE9vFqHHjT+7mnwIDAQABAoIBAQCL375WF6grML22 NtUFdNa1plaN42KRgbrhxtZ2taF6qZ9BXWJkgfsPqZKb4yLgIZxuaQRnyIAknQ4E gQeJ9HmDGWK0t+1l7X0B8fGqsG0fTwxJig3bxVXxGTmrTtC9iJoxV7ErCMnQRTmh pVwmzYx4T/BGjnGm6cVnVw3JuimhSVWQnMLUNcwTBQjcwbKI3o/Y4FhoDe0GYof8 6gJq+cj7jFn+x89e1uuXev562CidbOzfGYEc45X+I+DLEN9+xjRPZM0bfnyBS/bM /SCmvcgprITomY+d7H4iJ08BTEEo1z0fWcT8yfM2UgzOrUsjGCOBoZsOnr5zpnlC hfmBc+1BAoGBAOvIt1YN8YpOa/6+y2s8+c95S9yPmdTuO3QanybQMrb1W7iWlOb5 bi3aEuU7cUY+cHbzAYf2WC93pT3cKDPbuvG09EUTXExWw1hOGQ3ot3pgkbshmcBK 8TeQn3kp4d7YM92hnzDLPoEpkWuPdN+If3x2+CQ0Bs8IZjCRJGn5yMAPAoGBAOVR kiLV2qltk5xnOEvlzNXJoaxYeJBiQhXZOrwzYXJXUxz1Kk4QROlSVRboFvHImdGS MoLaUJ5WDE77z77v2f8+zaAeoSakbFaIofJ4qTvXrsc7L4djg9prveQvDZY50mbH SR5la5aQxJkA+TeE1hEowRhNK69aUJIfyfnga+BxAoGBAJG3946IiYm3k8jZs7Av /Be8WCUU3raZEUddGJUNQPqPwsLe1WG2L+DIkLr5NLV761eoMX8MwU18vTPw9yut lejBs+Fo6LcJPCs8AQH2nEZWnlovlu0fo9p6WASy3LQznEJSG6c1RQjgXs5B17I6 kseiYxNE0BxtjXJgkUeppucDAoGAZd5Tlaf8Z9Fmhk8QIh8mXD4i1MXEYRdVFhGW 1u3YNwv1vuJl9aGiiydo5zEYqDWdpwxT5e8Hax78fsW75qzz4UBL5fpVSi42dkZh 8q2JOC061gRDu9gIRaohA9GnLnnnLoMOxzL0lUEgJHvbOb+HvL2m8Z2ub0omipMW jSsVoPECgYEAodn6s+oG9zpq9Gl4Q8jsPiQAgsjwc4CGzz/oBvWooGf8pei0N2gj MIByXmIhpexBlJ4o/MgEMj7g299usGKq06Dg4dMn1DtunkSF/Vd1OcjlZVJpRmrJ m2HWLeo2pjD9W9KaMzZWQ5jxpGliC2TtpWuP44/ihZODFrQZc8DytPo= -----END RSA PRIVATE KEY----- yubihsm-shell-2.7.3/examples/attestation_template.pem0000644000175000017500000000207215167357110022050 0ustar aveenaveen-----BEGIN CERTIFICATE----- MIIC8TCCAdmgAwIBAgIJAI4siOgx84SNMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV BAMMBHRlc3QwHhcNMTcwMzE3MTMwODAyWhcNMjcwMzE1MTMwODAyWjAPMQ0wCwYD VQQDDAR0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv0J9YugQ 3po8PtkrhQsq4aUbU0y2MtruYvZjRG0tMMtTrE92FXqrBltL+LXjhC6nOcgkjb4U JFdJzK+QsQ3jpJNOpGWSWHCrEk8CVJnl2klq6vhlcSTlojHu912WYdiCudA0KhQ+ ffFhfGpAItctLMvaD7aS01l/OKzXAUkCv+8f2p+/+2I7mEnv88gOsisf78kqRPrQ b1xuRvHdNsehtxo+VN5bbKICkNskd18EloX46LjYi9oQ0zihmm24yGYPWUmDv1zm CBlM2AT2kHxHtHMl+DyewZERYtHKUN3irzyEq/9H2TxsfsYk2wR8QtAADU+mMe9M ne9lXrkgusx4RQIDAQABo1AwTjAdBgNVHQ4EFgQUGzIsrm1ZNd37V7vCLXolfTtM xEEwHwYDVR0jBBgwFoAUGzIsrm1ZNd37V7vCLXolfTtMxEEwDAYDVR0TBAUwAwEB /zANBgkqhkiG9w0BAQsFAAOCAQEAh7S+9c8Mcg/aK6qhQ/m0WJUSW5W4QL0p3fwG ettK+4tntI6ufgaJgxgvG8ucrcOJ/j/s7ZDqJ7MjRsZm391616oZixkPzCrBhWgr 3Vv6gFtnxXrwQMdgvzpKhtSrxjoDyUnFLs14H/e/L0+qGAlAN2adHHha7zouaWwY +KyyK5sX2m/yQg/uQm4KeVqz3wsA6zJXIg0EEH/ISj7JBCCyux3ouS3x/z+43Hl4 DzFJtJotn34HKe02gcCd4qxginQJJ84j2G4JZ42deVFPPp6dbHIuLFHunCH8HTkA jpI5R8+6LS+5+gci9J5OaVMAgvy6cYqx85lbaoyXdXB8aGLkNw== -----END CERTIFICATE----- yubihsm-shell-2.7.3/examples/asym_auth.c0000644000175000017500000001441415167357110017254 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include const uint8_t password[] = "password"; const uint8_t data[] = "sudo make me a sandwich"; static int compare_algorithm(const void *a, const void *b) { return (*(const yh_algorithm *) a - *(const yh_algorithm *) b); } int main(void) { yh_connector *connector = NULL; yh_rc yrc = YHR_GENERIC_ERROR; const char *connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); if (yrc != YHR_SUCCESS) { fprintf(stderr, "unable to initialize yubihsm: %s\n", yh_strerror(yrc)); exit(EXIT_FAILURE); } yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); char *received_url; yrc = yh_get_connector_address(connector, &received_url); assert(yrc == YHR_SUCCESS); yh_set_verbosity(connector, YH_VERB_ALL); uint8_t d_major, d_minor, d_patch; uint32_t serial; uint8_t log_total, log_used; yh_algorithm algorithms[YH_MAX_ALGORITHM_COUNT]; size_t n_algorithms = sizeof(algorithms); yrc = yh_util_get_device_info(connector, &d_major, &d_minor, &d_patch, &serial, &log_total, &log_used, algorithms, &n_algorithms); assert(yrc == YHR_SUCCESS); yh_algorithm key = YH_ALGO_EC_P256_YUBICO_AUTHENTICATION; if (!bsearch(&key, algorithms, n_algorithms, sizeof(key), compare_algorithm)) { fprintf(stderr, "Skipping this test because the device does not support " "aymmetric authentication\n"); exit(EXIT_SUCCESS); } printf("Send a plain (unencrypted, unauthenticated) echo command\n"); uint16_t data_len = sizeof(data) - 1; uint8_t response[sizeof(data)] = {0}; size_t response_len = sizeof(response); yh_cmd response_cmd; yrc = yh_send_plain_msg(connector, YHC_ECHO, data, data_len, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to send ECHO command: %s\n", yh_strerror(yrc)); exit(EXIT_FAILURE); } printf("Response (%zu bytes): \"%s\"\n", response_len, response); yh_session *session = NULL; uint16_t authkey = 1; yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); authkey = 2; yh_util_delete_object(session, authkey, YH_AUTHENTICATION_KEY); // Ignore result here uint8_t sk_oce[YH_EC_P256_PRIVKEY_LEN], pk_oce[YH_EC_P256_PUBKEY_LEN]; yrc = yh_util_generate_ec_p256_key(sk_oce, sizeof(sk_oce), pk_oce, sizeof(pk_oce)); assert(yrc == YHR_SUCCESS); yh_capabilities caps = {{0}}; yrc = yh_string_to_capabilities("change-authentication-key,get-pseudo-random", &caps); assert(yrc == YHR_SUCCESS); // The public key is imported without the uncompressed point marker (value // 0x04), so skip the first byte yrc = yh_util_import_authentication_key(session, &authkey, "EC Auth Key", 0xffff, &caps, &caps, pk_oce + 1, sizeof(pk_oce) - 1, NULL, 0); assert(yrc == YHR_SUCCESS); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); uint8_t pk_sd[YH_EC_P256_PUBKEY_LEN]; size_t pk_sd_len = sizeof(pk_sd); yrc = yh_util_get_device_pubkey(connector, pk_sd, &pk_sd_len, NULL); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_asym(connector, authkey, sk_oce, sizeof(sk_oce), pk_sd, pk_sd_len, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); uint8_t buf[32]; size_t buf_len = sizeof(buf); yrc = yh_util_get_pseudo_random(session, buf_len, buf, &buf_len); assert(yrc == YHR_SUCCESS); printf("Send a secure echo command\n"); uint8_t response2[sizeof(data)] = {0}; size_t response2_len = sizeof(response); yh_cmd response2_cmd; yrc = yh_send_secure_msg(session, YHC_ECHO, data, data_len, &response2_cmd, response2, &response2_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to send ECHO command: %s\n", yh_strerror(yrc)); exit(EXIT_FAILURE); } printf("Response (%zu bytes): \"%s\"\n", response_len, response); assert(response_len == response2_len); assert(memcmp(response, response2, response_len) == 0); yrc = yh_util_generate_ec_p256_key(sk_oce, sizeof(sk_oce), pk_oce, sizeof(pk_oce)); assert(yrc == YHR_SUCCESS); yrc = yh_util_change_authentication_key(session, &authkey, pk_oce + 1, sizeof(pk_oce) - 1, NULL, 0); assert(yrc == YHR_SUCCESS); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_asym(connector, authkey, sk_oce, sizeof(sk_oce), pk_sd, pk_sd_len, &session); assert(yrc == YHR_SUCCESS); buf_len = sizeof(buf); yrc = yh_util_get_pseudo_random(session, buf_len, buf, &buf_len); assert(yrc == YHR_SUCCESS); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yrc = yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/echo.c0000644000175000017500000000636615167357110016207 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include const uint8_t password[] = "password"; const uint8_t data[] = "sudo make me a sandwich"; int main(void) { yh_connector *connector = NULL; yh_rc yrc = YHR_GENERIC_ERROR; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); if (yrc != YHR_SUCCESS) { fprintf(stderr, "unable to initialize yubihsm: %s\n", yh_strerror(yrc)); exit(EXIT_FAILURE); } yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); char *received_url; yrc = yh_get_connector_address(connector, &received_url); assert(yrc == YHR_SUCCESS); yh_set_verbosity(connector, YH_VERB_ALL); printf("Send a plain (unencrypted, unauthenticated) echo command\n"); uint16_t data_len = sizeof(data) - 1; uint8_t response[sizeof(data)] = {0}; size_t response_len = sizeof(response); yh_cmd response_cmd; yrc = yh_send_plain_msg(connector, YHC_ECHO, data, data_len, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to send ECHO command: %s\n", yh_strerror(yrc)); exit(EXIT_FAILURE); } printf("Response (%zu bytes): \"%s\"\n", response_len, response); yh_session *session = NULL; uint16_t authkey = 1; yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); printf("Send a secure echo command\n"); uint8_t response2[sizeof(data)] = {0}; size_t response2_len = sizeof(response); yh_cmd response2_cmd; yrc = yh_send_secure_msg(session, YHC_ECHO, data, data_len, &response2_cmd, response2, &response2_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to send ECHO command: %s\n", yh_strerror(yrc)); exit(EXIT_FAILURE); } printf("Response (%zu bytes): \"%s\"\n", response_len, response); assert(response_len == response2_len); assert(memcmp(response, response2, response_len) == 0); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/ssh_req.dat0000644000175000017500000000207315167357110017252 0ustar aveenaveen[*q Pa[A|Ž“gÁ÷”ÑA¨uNAOïÝ7.G11ioõZf¢‰‰£Ïd)º Š{hÂ^ IùÀš§êÙ†óã´ÎѦ†]pÄZ…o_*)¥äÌ^ÿ2A0œÕÃòÊý›·¶ˆX=ä‘ÞIZI2Gþ²‘3µçÏÎK áÓ¹–åÂþõò ð7ÞÃfhÄüÛ„k ÷4›”×B\ªÓS]`Ë„å/“¡Ü؆>J?'ƒuþÔÉW„ßô˜1ýÇ*“2mÍîq°ÝBJʶÙÙ|Ðe»Kìù¼$äF?íÔÈà$ü £‚éZH*„+o×ðšWhX¾òEž—ssh-rsa-cert-v01@openssh.com ‘ç„4нR,O§Yû—ÒK½­¯SšP5q°cdâˆÏØ*V@[åÇí”o‡3Æúßøõ¯‰Ú]9ÒUxA·‰Qœ ༠#include #include #include int main(void) { yh_connector *connector = NULL; yh_rc yrc = YHR_GENERIC_ERROR; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); if (yrc != YHR_SUCCESS) { fprintf(stderr, "unable to initialize yubihsm: %s\n", yh_strerror(yrc)); exit(EXIT_FAILURE); } yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); char *received_url; yrc = yh_get_connector_address(connector, &received_url); assert(yrc == YHR_SUCCESS); printf("Successfully connected to %s, device is ", received_url); if (yh_connector_has_device(connector) == false) { printf("not present\n"); exit(EXIT_FAILURE); // This won't happen since we manged to connect } printf("present\n"); uint8_t c_major, c_minor, c_patch; yrc = yh_get_connector_version(connector, &c_major, &c_minor, &c_patch); assert(yrc == YHR_SUCCESS); printf("Connector Version: %hhu.%hhu.%hhu\n", c_major, c_minor, c_patch); uint8_t d_major, d_minor, d_patch; uint32_t serial; uint8_t log_total, log_used; yh_algorithm algorithms[YH_MAX_ALGORITHM_COUNT]; size_t n_algorithms = sizeof(algorithms); yrc = yh_util_get_device_info(connector, &d_major, &d_minor, &d_patch, &serial, &log_total, &log_used, algorithms, &n_algorithms); assert(yrc == YHR_SUCCESS); printf("Device Version: %hhu.%hhu.%hhu\n", d_major, d_minor, d_patch); printf("Serial: %d\n", serial); printf("Log: %d/%d (used/total)\n", log_used, log_total); printf("Supported algorithms:\n"); for (size_t i = 0; i < n_algorithms; i++) { const char *str; yh_algo_to_string(algorithms[i], &str); printf("%s\n", str); } yrc = yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/decrypt_ec.c0000644000175000017500000001340615167357110017403 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include #include "util.h" #include const char *key_label = "label"; const uint8_t password[] = "password"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("derive-ecdh", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_generate_ec_key(session, &key_id, key_label, domain_five, &capabilities, YH_ALGO_EC_P256); assert(yrc == YHR_SUCCESS); printf("Generated key with ID %04x\n", key_id); uint8_t public_key[512]; size_t public_key_len = sizeof(public_key); yrc = yh_util_get_public_key(session, key_id, public_key, &public_key_len, NULL); assert(yrc == YHR_SUCCESS); printf("Public key (%zd bytes) is:", public_key_len); for (size_t i = 0; i < public_key_len; i++) { printf(" %02x", public_key[i]); } printf("\n"); EC_KEY *eckey = EC_KEY_new(); int nid = algo2nid(YH_ALGO_EC_P256); EC_POINT *point; EC_GROUP *group = EC_GROUP_new_by_curve_name(nid); assert(group != NULL); EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); EC_KEY_set_group(eckey, group); point = EC_POINT_new(group); memmove(public_key + 1, public_key, public_key_len); public_key[0] = 0x04; // hack to make it a valid ec pubkey.. public_key_len++; EC_POINT_oct2point(group, point, public_key, public_key_len, NULL); EC_KEY_set_public_key(eckey, point); // Create the context for parameter generation EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); assert(pctx != NULL); // Initialise the parameter generation assert(EVP_PKEY_paramgen_init(pctx) == 1); // We're going to use the ANSI X9.62 Prime 256v1 curve assert(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) == 1); // Create the parameter object params EVP_PKEY *params = NULL; assert(EVP_PKEY_paramgen(pctx, ¶ms) == 1); // Create the context for the key generation EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(params, NULL); assert(kctx != NULL); // Generate the key EVP_PKEY *pkey = NULL; assert(EVP_PKEY_keygen_init(kctx) == 1); assert(EVP_PKEY_keygen(kctx, &pkey) == 1); // Get the peer's public key, and provide the peer with our public key EVP_PKEY *peerkey = EVP_PKEY_new(); assert(peerkey != NULL); assert(EVP_PKEY_set1_EC_KEY(peerkey, eckey) == 1); // Create the context for the shared secret derivation EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); assert(ctx != NULL); // Initialise assert(EVP_PKEY_derive_init(ctx) == 1); // Provide the peer public key assert(EVP_PKEY_derive_set_peer(ctx, peerkey) == 1); uint8_t secret[64]; size_t secret_len = sizeof(secret_len); // Determine buffer length for shared secret assert(EVP_PKEY_derive(ctx, NULL, &secret_len)); // Derive the shared secret assert(EVP_PKEY_derive(ctx, secret, &secret_len) == 1); EC_KEY *eckey2 = EVP_PKEY_get1_EC_KEY(pkey); const EC_POINT *pub = EC_KEY_get0_public_key(eckey2); uint8_t pubkey[128]; size_t pubkey_len = sizeof(pubkey); pubkey_len = EC_POINT_point2oct(group, pub, POINT_CONVERSION_UNCOMPRESSED, pubkey, pubkey_len, NULL); assert(pubkey_len == 65); uint8_t computed_secret[128]; size_t computed_secret_len = sizeof(computed_secret); yrc = yh_util_derive_ecdh(session, key_id, pubkey, pubkey_len, computed_secret, &computed_secret_len); assert(yrc == YHR_SUCCESS); assert(computed_secret_len == secret_len); assert(memcmp(secret, computed_secret, computed_secret_len) == 0); printf("Secrets match\n"); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(peerkey); EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(kctx); EVP_PKEY_free(params); EVP_PKEY_CTX_free(pctx); EC_POINT_free(point); EC_KEY_free(eckey); EC_KEY_free(eckey2); EC_GROUP_free(group); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/import_ed.c0000644000175000017500000001130615167357110017241 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include "util.h" #include const char ed25519_pvtkey_file[] = "ed25519_pvtkey.pem"; const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t data[] = {0x72}; const uint8_t expected_signature[] = {0x92, 0xa0, 0x09, 0xa9, 0xf0, 0xd4, 0xca, 0xb8, 0x72, 0x0e, 0x82, 0x0b, 0x5f, 0x64, 0x25, 0x40, 0xa2, 0xb2, 0x7b, 0x54, 0x16, 0x50, 0x3f, 0x8f, 0xb3, 0x76, 0x22, 0x23, 0xeb, 0xdb, 0x69, 0xda, 0x08, 0x5a, 0xc1, 0xe4, 0x3e, 0x15, 0x99, 0x6e, 0x45, 0x8f, 0x36, 0x13, 0xd0, 0xf1, 0x1d, 0x8c, 0x38, 0x7b, 0x2e, 0xae, 0xb4, 0x30, 0x2a, 0xee, 0xb0, 0x0d, 0x29, 0x16, 0x12, 0xbb, 0x0c, 0x00}; const uint8_t expected_public_key[] = {0x3d, 0x40, 0x17, 0xc3, 0xe8, 0x43, 0x89, 0x5a, 0x92, 0xb7, 0x0a, 0xa7, 0x4d, 0x1b, 0x7e, 0xbc, 0x9c, 0x98, 0x2c, 0xcf, 0x2e, 0xc4, 0x96, 0x8c, 0xc0, 0xcd, 0x55, 0xf1, 0x2a, 0xf4, 0x66, 0x0c}; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); FILE *fp = fopen(ed25519_pvtkey_file, "rb"); assert(fp != NULL); yh_algorithm algorithm = 0; uint8_t key[2048]; size_t key_material_len = sizeof(key); if (!read_file(fp, key, &key_material_len)) { assert(false); } bool ret = read_private_key(key, key_material_len, &algorithm, key, &key_material_len, false); assert(ret == true); assert(algorithm == YH_ALGO_EC_ED25519); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("sign-eddsa", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t key_id = 0; // ID 0 lets the device generate an ID yrc = yh_util_import_ed_key(session, &key_id, key_label, domain_five, &capabilities, algorithm, key); assert(yrc == YHR_SUCCESS); printf("Key imported with ID %04x\n", key_id); printf("Signing %zu bytes of data\n", sizeof(data)); uint8_t signature[128]; size_t signature_len = sizeof(signature); yrc = yh_util_sign_eddsa(session, key_id, data, sizeof(data), signature, &signature_len); assert(yrc == YHR_SUCCESS); printf("Signature (%zu bytes) is:", signature_len); for (unsigned int i = 0; i < signature_len; i++) { printf(" %02x", signature[i]); } printf("\n"); assert(signature_len == 64); assert(memcmp(signature, expected_signature, 64) == 0); uint8_t public_key[512]; size_t public_key_len = sizeof(public_key); yrc = yh_util_get_public_key(session, key_id, public_key, &public_key_len, NULL); assert(yrc == YHR_SUCCESS); assert(public_key_len == 32); assert(memcmp(public_key, expected_public_key, 32) == 0); printf("Public key (%zu bytes) is:", public_key_len); for (unsigned int i = 0; i < public_key_len; i++) { printf(" %02x", public_key[i]); } printf("\n"); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/p11_generate_rsa.c0000644000175000017500000000775615167357110020415 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: p11 /path/to/yubihsm_pkcs11/module\n"); exit(EXIT_FAILURE); } CK_C_GetFunctionList fn; void *handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL); assert(handle != NULL); *(void **) (&fn) = dlsym(handle, "C_GetFunctionList"); assert(fn != NULL); CK_FUNCTION_LIST_PTR p11; CK_RV rv = fn(&p11); assert(rv == CKR_OK); rv = p11->C_Initialize(NULL_PTR); assert(rv == CKR_OK); CK_SESSION_HANDLE session; rv = p11->C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session); assert(rv == CKR_OK); char password[] = "0001password"; rv = p11->C_Login(session, CKU_USER, (CK_UTF8CHAR_PTR) password, (CK_ULONG) strlen(password)); assert(rv == CKR_OK); CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0}; CK_ULONG modulus = 2048; CK_BYTE exponent[] = {0x00, 0x1, 0x0, 0x1}; // 65537 CK_BYTE id[] = {0, 0}; CK_BBOOL ck_true = CK_TRUE; CK_BBOOL ck_false = CK_FALSE; char pub_label[] = "RSA 2048 key"; char priv_label[] = "RSA 2048 key"; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_ENCRYPT, &ck_true, sizeof(ck_true)}, {CKA_DECRYPT, &ck_false, sizeof(ck_false)}, {CKA_SIGN, &ck_false, sizeof(ck_false)}, {CKA_VERIFY, &ck_true, sizeof(ck_true)}, {CKA_WRAP, &ck_true, sizeof(ck_true)}, {CKA_UNWRAP, &ck_false, sizeof(ck_false)}, {CKA_TOKEN, &ck_false, sizeof(ck_false)}, {CKA_PRIVATE, &ck_false, sizeof(ck_false)}, {CKA_EXTRACTABLE, &ck_true, sizeof(ck_true)}, {CKA_MODIFIABLE, &ck_false, sizeof(ck_false)}, {CKA_COPYABLE, &ck_false, sizeof(ck_false)}, {CKA_DESTROYABLE, &ck_true, sizeof(ck_true)}, {CKA_ID, id, sizeof(id)}, {CKA_MODULUS_BITS, &modulus, sizeof(modulus)}, {CKA_PUBLIC_EXPONENT, exponent, sizeof(exponent)}, {CKA_LABEL, pub_label, sizeof(pub_label)}, }; CK_ULONG publicKeyAttributeCount = sizeof(publicKeyTemplate) / sizeof(publicKeyTemplate[0]); CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_ENCRYPT, &ck_false, sizeof(ck_false)}, {CKA_DECRYPT, &ck_true, sizeof(ck_true)}, {CKA_SIGN, &ck_true, sizeof(ck_true)}, {CKA_VERIFY, &ck_false, sizeof(ck_false)}, {CKA_WRAP, &ck_false, sizeof(ck_false)}, {CKA_UNWRAP, &ck_true, sizeof(ck_true)}, {CKA_TOKEN, &ck_true, sizeof(ck_true)}, {CKA_PRIVATE, &ck_true, sizeof(ck_true)}, {CKA_EXTRACTABLE, &ck_true, sizeof(ck_true)}, {CKA_MODIFIABLE, &ck_false, sizeof(ck_false)}, {CKA_COPYABLE, &ck_false, sizeof(ck_false)}, {CKA_DESTROYABLE, &ck_true, sizeof(ck_true)}, {CKA_ID, id, sizeof(id)}, {CKA_LABEL, priv_label, sizeof(priv_label)}, }; CK_ULONG privateKeyAttributeCount = sizeof(privateKeyTemplate) / sizeof(privateKeyTemplate[0]); CK_OBJECT_HANDLE publicKey, privateKey; rv = p11->C_GenerateKeyPair(session, &mechanism, publicKeyTemplate, publicKeyAttributeCount, privateKeyTemplate, privateKeyAttributeCount, &publicKey, &privateKey); assert(rv == CKR_OK); rv = p11->C_Logout(session); assert(rv == CKR_OK); rv = p11->C_CloseSession(session); assert(rv == CKR_OK); rv = p11->C_Finalize(NULL); assert(rv == CKR_OK); dlclose(handle); return 0; } yubihsm-shell-2.7.3/examples/logs.c0000644000175000017500000001334415167357110016227 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include #include "util.h" #include #define N_OPERATIONS 5 const uint8_t password[] = "password"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); printf("Flushing existing logs\n"); uint16_t unlogged_boot, unlogged_auth; yh_log_entry logs[YH_MAX_LOG_ENTRIES]; size_t n_items = sizeof(logs) / sizeof(yh_log_entry); yh_log_entry last_previous_log; yh_log_entry *last_previous_log_ptr = &last_previous_log; uint8_t option[256]; size_t option_len; option[0] = YHC_SET_OPTION; option[1] = 0x01; option[2] = YHC_SET_LOG_INDEX; option[3] = 0x01; option[4] = YHC_GET_OBJECT_INFO; option[5] = 0x01; option_len = 2 * 3; yrc = yh_util_set_option(session, YH_OPTION_COMMAND_AUDIT, option_len, option); assert(yrc == YHR_SUCCESS); yrc = yh_util_get_log_entries(session, &unlogged_boot, &unlogged_auth, logs, &n_items); assert(yrc == YHR_SUCCESS); if (n_items != 0) { memcpy(&last_previous_log, logs + n_items - 1, sizeof(yh_log_entry)); } else { last_previous_log_ptr = NULL; } uint16_t last_index = logs[n_items - 1].number; yrc = yh_util_set_log_index(session, last_index); assert(yrc == YHR_SUCCESS); printf("Performing some operations\n"); for (uint16_t i = 0; i < N_OPERATIONS; i++) { yh_object_descriptor descriptor; yrc = yh_util_get_object_info(session, authkey, YH_AUTHENTICATION_KEY, &descriptor); assert(yrc == YHR_SUCCESS); } printf("Getting logs\n"); n_items = sizeof(logs) / sizeof(yh_log_entry); yrc = yh_util_get_log_entries(session, &unlogged_boot, &unlogged_auth, logs, &n_items); assert(yrc == YHR_SUCCESS); assert(n_items == N_OPERATIONS + 1); fprintf(stdout, "%d unlogged boots found\n", unlogged_boot); fprintf(stdout, "%d unlogged authentications found\n", unlogged_auth); char digest_buf[(2 * YH_LOG_DIGEST_SIZE) + 1]; if (n_items == 0) { fprintf(stdout, "No logs to extract\n"); return 0; } else if (n_items == 1) { fprintf(stdout, "Found 1 item\n"); } else { fprintf(stdout, "Found %zu items\n", n_items); } for (uint16_t i = 0; i < n_items; i++) { format_digest(logs[i].digest, digest_buf, YH_LOG_DIGEST_SIZE); fprintf(stdout, "item: %5u -- cmd: 0x%02x -- length: %4u -- session key: " "0x%04x -- target key: 0x%04x -- second key: 0x%04x -- " "result: 0x%02x -- tick: %lu -- hash: %s\n", logs[i].number, logs[i].command, logs[i].length, logs[i].session_key, logs[i].target_key, logs[i].second_key, logs[i].result, (unsigned long) logs[i].systick, digest_buf); } bool ret = yh_verify_logs(logs, n_items, last_previous_log_ptr); assert(ret == true); printf("Logs correctly verified\n"); option[0] = YHC_SET_OPTION; option[1] = 0x00; option_len = 2; yrc = yh_util_set_option(session, YH_OPTION_COMMAND_AUDIT, option_len, option); assert(yrc == YHR_SUCCESS); option_len = sizeof(option); yrc = yh_util_get_option(session, YH_OPTION_COMMAND_AUDIT, option, &option_len); assert(yrc == YHR_SUCCESS); assert(option_len % 2 == 0); bool option_found = false; for (size_t i = 0; i < option_len; i += 2) { if (option[i] == YHC_SET_OPTION) { assert(option[i + 1] == 0); option_found = true; break; } } assert(option_found == true); option[0] = YHC_SET_OPTION; option[1] = 0x01; option_len = 2; yrc = yh_util_set_option(session, YH_OPTION_COMMAND_AUDIT, option_len, option); assert(yrc == YHR_SUCCESS); option_len = sizeof(option); yrc = yh_util_get_option(session, YH_OPTION_COMMAND_AUDIT, option, &option_len); assert(yrc == YHR_SUCCESS); assert(option_len % 2 == 0); option_found = false; for (size_t i = 0; i < option_len; i += 2) { if (option[i] == YHC_SET_OPTION) { assert(option[i + 1] == 1); option_found = true; break; } } assert(option_found == true); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return EXIT_SUCCESS; } yubihsm-shell-2.7.3/examples/ssh.c0000644000175000017500000003430315167357110016056 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include #include #include "util.h" #include "openssl-compat.h" #include const char ssh_ca_pvtkey_file[] = "ssh_ca_pvtkey.pem"; const char *key_label = "label"; const uint8_t password[] = "password"; const unsigned char template_dat[] = { // Timestamp key algorithm RSA2048 0x01, 0x00, 0x01, 0x09, // Timestamp public key 0x02, 0x01, 0x00, 0xc2, 0x55, 0x62, 0x08, 0xf5, 0xd2, 0xc2, 0x81, 0xb8, 0xa5, 0x16, 0xfd, 0x27, 0x25, 0xe6, 0x7e, 0x88, 0xcd, 0xc5, 0xd2, 0xcf, 0xdf, 0xd3, 0xea, 0x2d, 0x35, 0xdf, 0x35, 0x27, 0x93, 0x44, 0x45, 0xa6, 0x14, 0x84, 0xee, 0xcb, 0x02, 0xc4, 0x7b, 0x67, 0xc5, 0x94, 0x16, 0xde, 0xe4, 0xa6, 0x1f, 0x25, 0x52, 0x4b, 0x27, 0x9d, 0x4d, 0x09, 0xb1, 0x9b, 0x3e, 0xc5, 0x89, 0xde, 0xe2, 0x90, 0xda, 0xa0, 0x64, 0xc7, 0xb3, 0xaa, 0xae, 0xc7, 0x23, 0x55, 0x37, 0xa0, 0xea, 0x63, 0xb4, 0x1b, 0x65, 0x4a, 0x7f, 0x71, 0xc6, 0x5c, 0xc2, 0x34, 0xfe, 0xa6, 0x02, 0xc9, 0xd6, 0x65, 0x13, 0x5d, 0xca, 0x74, 0x32, 0xf8, 0x7c, 0x01, 0x4b, 0x67, 0x61, 0xdf, 0x27, 0xdd, 0x1d, 0xed, 0x2f, 0x71, 0xcb, 0x8b, 0x23, 0x74, 0x4c, 0xfc, 0x99, 0xe2, 0x23, 0xed, 0xa5, 0xd8, 0x41, 0xe2, 0x9f, 0x82, 0x19, 0xbd, 0xae, 0x50, 0xfb, 0xb9, 0xc7, 0xe6, 0x83, 0x01, 0xac, 0x1c, 0x63, 0x89, 0xb2, 0xac, 0xa7, 0xfd, 0x01, 0x2a, 0xa3, 0xd4, 0x0d, 0x88, 0xf4, 0xcf, 0x9f, 0xed, 0xc1, 0x19, 0xc8, 0x64, 0x71, 0xd3, 0x02, 0x6b, 0x9f, 0x0d, 0xc2, 0xdf, 0x81, 0x5d, 0x53, 0x82, 0x3e, 0xa0, 0xab, 0xf2, 0x93, 0xc9, 0xa4, 0xa8, 0x3b, 0x71, 0xc1, 0xf4, 0xe3, 0x31, 0xa5, 0xdc, 0xfe, 0xc7, 0x9e, 0x7f, 0xd8, 0x2d, 0xd9, 0xfc, 0x90, 0xde, 0xa8, 0xdb, 0x77, 0x0b, 0x2f, 0xb0, 0xf4, 0x49, 0x21, 0x95, 0x95, 0x4b, 0x7e, 0xa0, 0x6f, 0x15, 0x8f, 0x95, 0xdd, 0x72, 0x39, 0x7a, 0x13, 0xb6, 0xcc, 0xfa, 0x9a, 0x07, 0x2d, 0x41, 0xcf, 0x12, 0xaf, 0x8e, 0x87, 0x9f, 0x97, 0xf1, 0x1e, 0x00, 0xac, 0xce, 0x2d, 0x12, 0xd4, 0x34, 0x0c, 0x40, 0x84, 0x33, 0x3a, 0x6c, 0x9f, 0x22, 0x7d, 0x6f, 0x89, 0x87, 0xfb, // CA key allowlist (0x0001, 0x00ab, 0x0014, 0x0005, 0x003a) 0x03, 0x00, 0x0a, 0x00, 0x01, 0x00, 0xab, 0x00, 0x14, 0x00, 0x05, 0x00, 0x3a, // Not before 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, // Not after 0x05, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, // Principals blocklist (root, toor) 0x06, 0x00, 0x0a, 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x74, 0x6f, 0x6f, 0x72, 0x00}; const char ssh_req_file[] = "ssh_req.dat"; const unsigned char expected_result[] = {0x00, 0x00, 0x00, 0x1c, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x2d, 0x63, 0x65, 0x72, 0x74, 0x2d, 0x76, 0x30, 0x31, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x20, 0x91, 0xe7, 0x84, 0x34, 0x8a, 0xbd, 0x1f, 0x52, 0x2c, 0x4f, 0xa7, 0x59, 0xfb, 0x97, 0xd2, 0x4b, 0x07, 0xbd, 0xad, 0x1f, 0xaf, 0x53, 0x9a, 0x50, 0x35, 0x71, 0xb0, 0x63, 0x64, 0xe2, 0x88, 0xcf, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xd8, 0x2a, 0x18, 0x56, 0x40, 0x5b, 0xe5, 0xc7, 0xed, 0x94, 0x6f, 0x1f, 0x18, 0x87, 0x33, 0x10, 0xc6, 0xfa, 0x00, 0x1e, 0xdf, 0xf8, 0xf5, 0xaf, 0x89, 0xda, 0x5d, 0x05, 0x39, 0xd2, 0x15, 0x55, 0x78, 0x41, 0xb7, 0x89, 0x51, 0x9c, 0x0b, 0xe0, 0xbc, 0x3c, 0x65, 0x40, 0xdf, 0x84, 0xd2, 0xf1, 0xaf, 0xd8, 0x0f, 0x0b, 0x40, 0x7e, 0x59, 0x84, 0x92, 0x24, 0xa9, 0xaa, 0x83, 0x70, 0x0b, 0x6e, 0x6a, 0xbc, 0xb1, 0x60, 0xbe, 0xa1, 0xad, 0xa1, 0x4f, 0x96, 0xe8, 0xa7, 0xfe, 0xc3, 0x21, 0x41, 0xa7, 0x73, 0xbc, 0x10, 0x0a, 0xdb, 0x4c, 0xfd, 0x7a, 0xef, 0x85, 0xac, 0x99, 0xe7, 0xfb, 0x94, 0x7e, 0x09, 0xb7, 0xb6, 0x8d, 0x5d, 0x03, 0x4b, 0x9c, 0x2e, 0xc6, 0xcc, 0x3b, 0x9c, 0xb3, 0xb2, 0xaf, 0x5d, 0x48, 0xd3, 0x51, 0x33, 0xc2, 0xb8, 0xc2, 0x21, 0x10, 0x40, 0x8e, 0x54, 0x26, 0x2e, 0xbb, 0x32, 0x6e, 0x69, 0x4b, 0x6d, 0xe9, 0x4a, 0xa3, 0x0b, 0xc6, 0xa3, 0x13, 0x1c, 0x72, 0x7d, 0x23, 0x4b, 0x29, 0xe9, 0x3b, 0xfb, 0x26, 0x4e, 0xe2, 0xa4, 0xbc, 0xad, 0xa0, 0x9c, 0xf2, 0xdd, 0xb4, 0x63, 0x21, 0x3b, 0x25, 0xb3, 0xd9, 0x20, 0xb8, 0x62, 0xdb, 0x0c, 0xd3, 0xdc, 0xdf, 0x9f, 0xdf, 0x0e, 0xea, 0x74, 0xd0, 0x3f, 0xb7, 0x04, 0x67, 0xac, 0xb7, 0xea, 0xe2, 0xc9, 0x0c, 0xe2, 0x44, 0x03, 0x3c, 0x6f, 0x9c, 0x56, 0xee, 0x7b, 0x0d, 0x7c, 0xfc, 0xe6, 0x76, 0xac, 0x7b, 0x10, 0x26, 0xf1, 0xb9, 0xaf, 0x53, 0x6c, 0x74, 0xbb, 0x8a, 0x24, 0xd5, 0x91, 0xd8, 0xc8, 0x72, 0xfb, 0x6f, 0x52, 0x58, 0x94, 0xeb, 0x8d, 0xc2, 0x12, 0xbc, 0xd1, 0xde, 0xfb, 0x49, 0xf3, 0x39, 0x51, 0x86, 0xd4, 0x32, 0x9f, 0x36, 0x1b, 0x37, 0xb7, 0x8a, 0x4f, 0x43, 0x7b, 0xd9, 0xf0, 0x26, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x05, 0x75, 0x73, 0x65, 0x72, 0x31, 0x00, 0x00, 0x00, 0x05, 0x75, 0x73, 0x65, 0x72, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x15, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x2d, 0x58, 0x31, 0x31, 0x2d, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2d, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x2d, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x2d, 0x70, 0x74, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x72, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xd3, 0x35, 0xad, 0x1a, 0x8a, 0xe2, 0x4d, 0x09, 0xaa, 0xb4, 0x29, 0x8b, 0x1e, 0xbd, 0xc9, 0x41, 0x22, 0xbe, 0x11, 0xd3, 0x0e, 0xab, 0x25, 0xed, 0xbc, 0x5e, 0x2f, 0xaa, 0xf2, 0x48, 0x14, 0x5b, 0x14, 0xee, 0xe3, 0x03, 0x9b, 0xf1, 0x52, 0x87, 0x0d, 0x61, 0x09, 0x51, 0x60, 0xc9, 0x9b, 0xbb, 0x3f, 0xbe, 0xfe, 0x45, 0x46, 0x88, 0x30, 0x05, 0x04, 0x6e, 0xd6, 0x0a, 0x17, 0x8b, 0xd8, 0xbc, 0xf3, 0xf1, 0x50, 0x50, 0xcb, 0xd5, 0x8c, 0x87, 0x17, 0xa5, 0x6c, 0x36, 0xfc, 0x24, 0x30, 0xd0, 0xd2, 0x99, 0x16, 0x72, 0x0f, 0xa9, 0x47, 0xe4, 0x3f, 0xd0, 0x15, 0xc1, 0x86, 0x66, 0xd9, 0xfa, 0x47, 0x3d, 0x52, 0x7c, 0x9b, 0xb2, 0x9e, 0xb4, 0xfe, 0xfd, 0x99, 0x6d, 0x33, 0xf3, 0x6b, 0xa1, 0xd7, 0x5a, 0x21, 0x30, 0x36, 0xdc, 0xd4, 0xa6, 0x26, 0xb2, 0x22, 0xfe, 0x5c, 0x26, 0xe6, 0xfa, 0xee, 0xbc, 0x54, 0x09, 0xec, 0x90, 0xf8, 0xfa, 0xd8, 0x91, 0xf2, 0x22, 0xce, 0xa9, 0x6b, 0x06, 0x5e, 0x55, 0x2d, 0x21, 0x70, 0xed, 0xd3, 0xdb, 0x10, 0xb3, 0xef, 0xc7, 0x09, 0xbc, 0xe2, 0x1d, 0x47, 0xa8, 0x58, 0xff, 0x13, 0x4a, 0x98, 0x4a, 0x7d, 0xce, 0x8b, 0x8c, 0xdb, 0x52, 0xc7, 0xaa, 0x66, 0xca, 0x70, 0xb6, 0xc1, 0x11, 0x7b, 0x2d, 0x87, 0x74, 0x0a, 0x6e, 0xcd, 0xab, 0x41, 0xd0, 0xfb, 0x13, 0xf1, 0xb9, 0xa0, 0x41, 0x59, 0xea, 0x9d, 0x29, 0x42, 0x7b, 0xff, 0x44, 0x6a, 0xb7, 0xbb, 0x26, 0xac, 0x61, 0x9c, 0xa9, 0x6b, 0xb7, 0x3f, 0xdc, 0xb1, 0x73, 0x18, 0x98, 0x56, 0x51, 0x60, 0x65, 0x20, 0x40, 0x51, 0x58, 0xc7, 0x31, 0x86, 0x82, 0x46, 0x25, 0x99, 0x28, 0xfb, 0x3a, 0xc0, 0x34, 0xd8, 0x9c, 0x93, 0x81, 0x13, 0xdb, 0xc5, 0xa8, 0x71, 0xe3, 0x4f, 0xee, 0xe6, 0x9f, 0x00, 0x00, 0x01, 0x0f, 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00, 0x00, 0x01, 0x00, 0x0a, 0xcc, 0x96, 0xd1, 0xc3, 0xa5, 0x05, 0xfb, 0x20, 0x2f, 0x3a, 0x70, 0x89, 0x73, 0x42, 0x01, 0x21, 0x14, 0x44, 0xc6, 0x61, 0xbd, 0xc7, 0x5f, 0xf0, 0x8b, 0x04, 0x30, 0xa8, 0x81, 0x81, 0x17, 0x6e, 0x8a, 0xe5, 0x88, 0x2a, 0x4a, 0xf8, 0x58, 0x82, 0x1c, 0x67, 0x18, 0x26, 0x9a, 0x24, 0xb5, 0xf9, 0x1c, 0xc9, 0xe8, 0x12, 0xe2, 0x93, 0xdc, 0x63, 0xc1, 0x4d, 0x39, 0x37, 0x44, 0xb4, 0x06, 0x27, 0x29, 0x53, 0x3b, 0xa1, 0x72, 0xb1, 0xb0, 0x7f, 0xec, 0x76, 0x88, 0x68, 0x54, 0xba, 0xff, 0xe4, 0x29, 0x67, 0xbc, 0xae, 0x0b, 0x33, 0xc3, 0x78, 0xf8, 0x90, 0xe0, 0x33, 0xda, 0x1c, 0x76, 0x5a, 0x18, 0xcf, 0xdf, 0x22, 0x17, 0x7a, 0xba, 0x7d, 0x84, 0x3f, 0xd1, 0x4a, 0x18, 0x6d, 0x67, 0x8c, 0xa0, 0x64, 0xe9, 0x57, 0xdc, 0xb9, 0x99, 0x89, 0x85, 0xd6, 0x28, 0x82, 0x33, 0x3f, 0x95, 0xda, 0xfb, 0x8b, 0x92, 0x35, 0xd2, 0x73, 0x1f, 0xdd, 0x4a, 0x62, 0x0a, 0x67, 0xfb, 0xdc, 0x08, 0x6d, 0x4b, 0xe4, 0xed, 0x9f, 0x22, 0xda, 0xe0, 0x02, 0x8e, 0x8c, 0xcb, 0x33, 0xe6, 0x08, 0x91, 0x4d, 0x26, 0xf3, 0xc7, 0xdd, 0xad, 0x08, 0xec, 0x63, 0xf0, 0xe8, 0x09, 0x14, 0x78, 0xd4, 0xf3, 0xc0, 0xb7, 0xd7, 0x5c, 0x9d, 0x62, 0x00, 0x8c, 0xde, 0xde, 0xcd, 0x75, 0x5c, 0x9b, 0xfb, 0x85, 0xce, 0x3d, 0x58, 0xb0, 0x4a, 0xc8, 0xc3, 0xc5, 0x86, 0xe5, 0x3f, 0xf4, 0x86, 0x29, 0x57, 0x2e, 0x7a, 0xd4, 0x64, 0x29, 0xa8, 0x42, 0xba, 0xf3, 0xb4, 0x92, 0x3f, 0x77, 0xc3, 0x44, 0xaa, 0xcc, 0x30, 0xb8, 0x82, 0xb2, 0xcb, 0x29, 0x9c, 0xea, 0x84, 0xa5, 0x0f, 0x58, 0x59, 0x3d, 0x43, 0xe3, 0xc4, 0xdd, 0x18, 0xdf, 0xe4, 0x82, 0x45, 0x22, 0xea, 0xa7, 0xe2, 0x26, 0xc8, 0x41, 0xfb, 0x37}; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; uint16_t authkey = 1; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, authkey, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); FILE *fp = fopen(ssh_ca_pvtkey_file, "rb"); assert(fp != NULL); yh_algorithm algorithm = 0; uint8_t key[2048]; size_t key_material_len = sizeof(key); if (!read_file(fp, key, &key_material_len)) { assert(false); } bool ret = read_private_key(key, key_material_len, &algorithm, key, &key_material_len, false); assert(ret == true); assert(algorithm == YH_ALGO_RSA_2048); yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("sign-ssh-certificate", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t ca_key_id = 5; // We use ID 5 because it is in the template's allowlist yrc = yh_util_get_object_info(session, ca_key_id, YH_ASYMMETRIC_KEY, NULL); if (yrc == YHR_SUCCESS) { yrc = yh_util_delete_object(session, ca_key_id, YH_ASYMMETRIC_KEY); assert(yrc == YHR_SUCCESS); } else { assert(yrc == YHR_DEVICE_OBJECT_NOT_FOUND); } yrc = yh_util_import_rsa_key(session, &ca_key_id, key_label, domain_five, &capabilities, algorithm, key, key + (key_material_len / 2)); assert(yrc == YHR_SUCCESS); printf("Key imported with ID %04x\n", ca_key_id); uint16_t template_id = 10; yrc = yh_util_get_object_info(session, template_id, YH_TEMPLATE, NULL); if (yrc == YHR_SUCCESS) { yrc = yh_util_delete_object(session, template_id, YH_TEMPLATE); assert(yrc == YHR_SUCCESS); } else { assert(yrc == YHR_DEVICE_OBJECT_NOT_FOUND); } yrc = yh_util_import_template(session, &template_id, key_label, domain_five, &capabilities, YH_ALGO_TEMPLATE_SSH, template_dat, sizeof(template_dat)); assert(yrc == YHR_SUCCESS); printf("Template imported with ID %04x\n", template_id); uint8_t template2[sizeof(template_dat)]; size_t template2_len = sizeof(template2); yrc = yh_util_get_template(session, template_id, template2, &template2_len); assert(yrc == YHR_SUCCESS); assert(sizeof(template_dat) == template2_len); assert(memcmp(template_dat, template2, template2_len) == 0); uint8_t ssh_req[2048]; size_t ssh_req_len = sizeof(ssh_req); fp = fopen(ssh_req_file, "rb"); assert(fp != NULL); fseek(fp, 0, SEEK_END); ssh_req_len = ftell(fp); assert(ssh_req_len <= sizeof(ssh_req)); fseek(fp, 0, SEEK_SET); size_t read = fread(ssh_req, 1, ssh_req_len, fp); fclose(fp); printf("actually read %zu, expected %zu\n", read, ssh_req_len); assert(read == ssh_req_len); size_t ssh_cert_len = sizeof(ssh_req) - ssh_req_len; yrc = yh_util_sign_ssh_certificate(session, ca_key_id, template_id, YH_ALGO_RSA_PKCS1_SHA1, ssh_req, ssh_req_len, ssh_req + ssh_req_len, &ssh_cert_len); assert(yrc == YHR_SUCCESS); assert(memcmp(expected_result, ssh_req + 4 + 256, sizeof(expected_result)) == 0); BIO *bio; BIO *b64; b64 = BIO_new(BIO_f_base64()); bio = BIO_new_fp(stdout, BIO_NOCLOSE); bio = BIO_push(b64, bio); fprintf(stdout, "ssh-rsa-cert-v01@openssh.com "); BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); assert(BIO_write(bio, ssh_req + 4 + 256, ssh_req_len + ssh_cert_len - 4 - 256) > 0); assert(BIO_flush(bio) == 1); fprintf(stdout, "\n"); BIO_free_all(bio); yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return 0; } yubihsm-shell-2.7.3/examples/encrypt_aes.c0000644000175000017500000001066615167357110017603 0ustar aveenaveen/* * Copyright 2021 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #undef NDEBUG #include #include #include #include #include #include const char *key_label = "label"; const uint8_t password[] = "password"; const uint8_t plaintext[16] = "singleblock msg"; int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; yh_rc yrc = YHR_GENERIC_ERROR; int r = EXIT_FAILURE; const char *connector_url; connector_url = getenv("DEFAULT_CONNECTOR_URL"); if (connector_url == NULL) { connector_url = DEFAULT_CONNECTOR_URL; } yrc = yh_init(); assert(yrc == YHR_SUCCESS); yrc = yh_init_connector(connector_url, &connector); assert(yrc == YHR_SUCCESS); yrc = yh_connect(connector, 0); assert(yrc == YHR_SUCCESS); yrc = yh_create_session_derived(connector, 1, password, sizeof(password) - 1, false, &session); assert(yrc == YHR_SUCCESS); uint8_t session_id; yrc = yh_get_session_id(session, &session_id); assert(yrc == YHR_SUCCESS); printf("Successfully established session %02d\n", session_id); yh_algorithm algorithms[YH_MAX_ALGORITHM_COUNT]; size_t algorithm_count = YH_MAX_ALGORITHM_COUNT; yrc = yh_util_get_device_info(connector, NULL, NULL, NULL, NULL, NULL, NULL, algorithms, &algorithm_count); assert(yrc == YHR_SUCCESS); int state = 0; /* unsupported */ for (size_t i = 0; i < algorithm_count; i++) { if (algorithms[i] == YH_ALGO_AES_ECB) { state |= 0x01; } else if (algorithms[i] == YH_ALGO_AES_CBC) { state |= 0x02; } } if (state != 0x03) { fprintf(stderr, "ECB/CBC unsupported or disabled (%#04x)\n", state); r = 64; /* arbitrarily chosen */ goto done; } yh_capabilities capabilities = {{0}}; yrc = yh_string_to_capabilities("encrypt-ecb,decrypt-ecb,encrypt-cbc,decrypt-cbc", &capabilities); assert(yrc == YHR_SUCCESS); uint16_t domain_five = 0; yrc = yh_string_to_domains("5", &domain_five); assert(yrc == YHR_SUCCESS); uint16_t aes_key_id = 0; yrc = yh_util_generate_aes_key(session, &aes_key_id, key_label, domain_five, &capabilities, YH_ALGO_AES256); assert(yrc == YHR_SUCCESS); printf("Generated AES key with ID %04x\n", aes_key_id); uint8_t data[16]; size_t data_len = sizeof(data); yrc = yh_util_encrypt_aes_ecb(session, aes_key_id, plaintext, sizeof(plaintext), data, &data_len); assert(yrc == YHR_SUCCESS); assert(memcmp(data, plaintext, sizeof(plaintext)) != 0); printf("AES-ECB encryption successful\n"); yrc = yh_util_decrypt_aes_ecb(session, aes_key_id, data, data_len, data, &data_len); assert(yrc == YHR_SUCCESS); assert(data_len == sizeof(plaintext)); assert(memcmp(data, plaintext, sizeof(plaintext)) == 0); printf("AES-ECB decryption successful\n"); uint8_t iv[16]; size_t iv_len = sizeof(iv); yrc = yh_util_get_pseudo_random(session, 16, iv, &iv_len); assert(yrc == YHR_SUCCESS); yrc = yh_util_encrypt_aes_cbc(session, aes_key_id, iv, plaintext, sizeof(plaintext), data, &data_len); assert(yrc == YHR_SUCCESS); assert(memcmp(data, plaintext, sizeof(plaintext)) != 0); printf("AES-CBC encryption successful\n"); yrc = yh_util_decrypt_aes_cbc(session, aes_key_id, iv, data, data_len, data, &data_len); assert(yrc == YHR_SUCCESS); assert(data_len == sizeof(plaintext)); assert(memcmp(data, plaintext, sizeof(plaintext)) == 0); printf("AES-CBC decryption successful\n"); r = EXIT_SUCCESS; done: yrc = yh_util_close_session(session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&session); assert(yrc == YHR_SUCCESS); yh_disconnect(connector); assert(yrc == YHR_SUCCESS); yrc = yh_exit(); assert(yrc == YHR_SUCCESS); return r; } yubihsm-shell-2.7.3/resources/0000755000175000017500000000000015167357110015306 5ustar aveenaveenyubihsm-shell-2.7.3/resources/tests/0000755000175000017500000000000015167357110016450 5ustar aveenaveenyubihsm-shell-2.7.3/resources/tests/bash/0000755000175000017500000000000015167357110017365 5ustar aveenaveenyubihsm-shell-2.7.3/resources/tests/bash/template.dat0000644000175000017500000000060415167357110021672 0ustar aveenaveenAQABCQIBAM3enEjbk5aw6JEezWDROOKvcLCmKB7kDPMn6IuLEUi7KsOjvetQJgD5kfRVwxYxCCAKlReTUvJFwg7gI5h3bF/xQF+FNZ2yojQ1rpvAAHvK8BROu6G6mlY4ZhzhzHDp6+8lUNDz5ljw2PTeGPj1T46MX3dY4r8OSljdsIn/IeVQoobriOF6cVXL5GGoLHzbqtr3jegM2WmrKUJjhKSEJL0WoAWRTYp+WeObMTlihZOM6KYYukQYE900K+YO3nnkEUHiQRDgYGTPNnUOXiGk5wcxk9xqHIHPUyzjdgwiP6/rWMCJ5fMc/EmyEBRFc1+sw1oZiT6cpJeqLHC0ocNKWB8DAAIACgQABAAAASwFAAQAAIygBgAFcm9vdAA=yubihsm-shell-2.7.3/resources/tests/bash/cmdline_test.bats0000644000175000017500000017326515167357110022730 0ustar aveenaveenload 'test_helper/bats-support/load' load 'test_helper/bats-assert/load' setup_file() { echo "--- Configuration via Environment Variables ---" >&3 echo "YUBIHSM_PATH: path to the yubihsm-shell command line tool - using default connector" >&3 echo "SPECIFIED_CONNECTOR: path to the yubihsm-shell command line tool - using specified connector" >&3 echo "TESTS: which tests to run. Possible values are: 'short', 'medium' or 'all'" >&3 echo "It is also possible to individually enable tests by setting the environment variables specified in the README file to 'true'" >&3 echo "-----------------------------------------------" >&3 case "$TESTS" in "all") ED_KEY_TESTS="true" EC_KEY_TESTS="true" RSA_KEY_TESTS="true" HMAC_KEY_TESTS="true" OTP_AEAD_TESTS="true" TEMPLATE_TESTS="true" WRAP_KEY_TESTS="true" LIST_TESTS="true" LABEL_TESTS="true" AUTHENTICATION_TESTS="true" ;; "medium") ED_KEY_TESTS="true" EC_KEY_TESTS="true" HMAC_KEY_TESTS="true" OTP_AEad_TESTS="true" TEMPLATE_TESTS="true" LIST_TESTS="true" LABEL_TESTS="true" AUTHENTICATION_TESTS="true" ;; "short") HMAC_KEY_TESTS="true" OTP_AEAD_TESTS="true" TEMPLATE_TESTS="true" LIST_TESTS="true" LABEL_TESTS="true" AUTHENTICATION_TESTS="true" ;; *) echo "---------------------------------------------------" >&3 echo "Warning: Unrecognized TEST level: '$TESTS'" >&3 echo "Ignore if you are setting individual test variables" >&3 echo "---------------------------------------------------" >&3 ;; esac export ED_KEY_TESTS=${ED_KEY_TESTS:-"false"} export EC_KEY_TESTS=${EC_KEY_TESTS:-"false"} export RSA_KEY_TESTS=${RSA_KEY_TESTS:-"false"} export HMAC_KEY_TESTS=${HMAC_KEY_TESTS:-"false"} export OTP_AEAD_TESTS=${OTP_AEAD_TESTS:-"false"} export TEMPLATE_TESTS=${TEMPLATE_TESTS:-"false"} export WRAP_KEY_TESTS=${WRAP_KEY_TESTS:-"false"} export LIST_TESTS=${LIST_TESTS:-"false"} export LABEL_TESTS=${LABEL_TESTS:-"false"} export AUTHENTICATION_TESTS=${AUTHENTICATION_TESTS:-"false"} local default_bin_path="yubihsm-shell" local os=$(uname -o) export c_var="" if [[ "$os" == "Msys" ]]; then default_bin_path="C:\Program Files\Yubico\YubiHSM Shell\bin\yubihsm-shell.exe" export MSYS2_ARG_CONV_EXCL=* # To prevent path conversion by MSYS2 elif [[ "$os" == "GNU/Linux" || "$os" == "Darwin" ]]; then default_bin_path="/usr/local/bin/yubihsm-shell" fi if [ -n "$SPECIFIED_CONNECTOR" ]; then echo "Specified connector exists" >&3 c_var="-C" fi export BIN=${YUBIHSM_PATH:-$default_bin_path} export SPECIFIED_CONNECTOR=${SPECIFIED_CONNECTOR:-""} echo "Variables Check:" >&3 echo "YubiHSM-shell: $BIN" >&3 echo "Connector: "$c_var" "$SPECIFIED_CONNECTOR"" >&3 echo "Tests to run: $TESTS" >&3 echo "These tests will reset your HSM" >&3 echo "Press Enter to continue or Ctrl-C + enter to abort" >&3 read -p "" if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt } @test "Test basic functions and get Pseudo-Random" { command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" --version assert_success "Version works" run "${command_args[@]}" --help assert_success "Help works" run "${command_args[@]}" -a get-device-info assert_success "Get device info" assert_output --partial "Serial number:" run "${command_args[@]}" -p password -a blink assert_success "Blink works" run "${command_args[@]}" -p password -a blink --duration=5 assert_success "Blink with duration works" run "${command_args[@]}" -p password -a get-pseudo-random assert_success output_data=$(echo "$output" | tail -n 1) local byte_count byte_count=$(echo -n "$output_data" | wc -c | xargs) assert_equal "$byte_count" 512 run "${command_args[@]}" -p password -a get-pseudo-random --out=random.txt assert_success "Get Pseudo-Random to file" length=$(cat random.txt | wc -c) if [ "$length" -ne 512 ]; then echo "Expected 512 but was "$length" characters. Without specifying byte count, 256 bytes (=512 characters) pseudo random number should have been produced." >&3 exit 1 fi rm random.txt run "${command_args[@]}" -p password -a get-pseudo-random --count=10 assert_success "Get pseudo-random with --count=10" output_data=$(echo "$output" | tail -n 1) local byte_count byte_count=$(echo -n "$output_data" | wc -c | xargs) assert_equal "$byte_count" 20 run "${command_args[@]}" -p password -a get-pseudo-random --count=10 --out=random.txt assert_success "Get pseudo-random with --count=10" length=$(cat random.txt | wc -c) if [ "$length" -ne 20 ]; then echo "Expected 20 but was "$length" characters." >&3 exit 1 fi rm random.txt } @test "ED Key tests" { [[ "$ED_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 #Generate run "${command_args[@]}" -p password -a generate-asymmetric-key -i 100 -l \"edKey\" -d 1,2,3 -c sign-eddsa -A ed25519 assert_success "Generate key" run "${command_args[@]}" -p password -a get-object-info -i 100 -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: 0x0064" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: ed25519" assert_output --partial 'label: ""edKey""' assert_output --partial "domains: 1:2:3" assert_output --partial "origin: generated" assert_output --partial "capabilities: sign-eddsa" #Get public key run "${command_args[@]}" -p password -a get-public-key -i 100 assert_success "Get public key" "${command_args[@]}" -p password -a get-public-key -i 100 > edkey1.pub 2>/dev/null run "${command_args[@]}" -p password -a get-public-key -i 100 --out edkey2.pub assert_success "Get public key to file" local content1 local content2 content1=$(tr -d '\r' < edkey1.pub) content2=$(tr -d '\r' < edkey2.pub) assert_equal "$content1" "$content2" #Signing run "${command_args[@]}" -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt assert_success "Sign to stdout" "${command_args[@]}" -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt > data.ed1.sig 2>/dev/null run "${command_args[@]}" -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt --out data.ed2.sig assert_success "Sign to file" content1=$(tr -d '[:space:]' < data.ed1.sig) content2=$(tr -d '[:space:]' < data.ed2.sig) assert_equal "$content1" "$content2" #Generating CSR run "${command_args[@]}" -p password -a generate-csr -i 100 -S /CN=test/ --out csr.pem assert_success "Generate CSR with yubihsm-shell" run openssl req -in csr.pem -verify assert_success "Verify CSR with openssl" #Delete run "${command_args[@]}" -p password -a delete-object -i 100 -t asymmetric-key assert_success "Delete key" run rm csr.pem assert_success "Remove CSR" } @test "EC Key tests" { [[ "$EC_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") genkey=100 import_key=200 run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 EC_ALGOS=("ecp224" "ecp256" "ecp384" "ecp521" "eck256") EC_CURVES=("secp224r1" "secp256r1" "secp384r1" "secp521r1" "secp256k1") if ! grep -q 'Fedora' /etc/os-release 2>/dev/null; then EC_ALGOS+=("ecbp256" "ecbp384" "ecbp512") EC_CURVES+=("brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1") fi for i in "${!EC_ALGOS[@]}"; do algo=${EC_ALGOS[i]} curve=${EC_CURVES[i]} echo "Testing $algo with curve $curve" >&3 #Generate Key run "${command_args[@]}" -p password -a generate-asymmetric-key -i "$genkey" -l \"ecKey\" -d 5,8,13 -c sign-ecdsa,derive-ecdh,sign-attestation-certificate -A "$algo" assert_success "Generate key" run "${command_args[@]}" -p password -a get-object-info -i "$genkey" -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: 0x0064" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: "$algo"" assert_output --partial 'label: ""ecKey""' assert_output --partial "domains: 5:8:13" assert_output --partial "origin: generated" assert_output --partial "capabilities: derive-ecdh:sign-attestation-certificate:sign-ecdsa" run "${command_args[@]}" -p password -a get-public-key -i "$genkey" --outformat=PEM --out "$algo"-gen.pubkey assert_success "Get public key" #Import Key run openssl ecparam -genkey -name "$curve" -noout -out "$curve"-keypair.pem assert_success "Generate key with openssl" run "${command_args[@]}" -p password -a put-asymmetric-key -i "$import_key" -l "ecKeyImport" -d "2,6,7" -c "sign-ecdsa,sign-attestation-certificate" --in="$curve"-keypair.pem assert_success "Import $algo key" run "${command_args[@]}" -p password -a get-object-info -i "$import_key" -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: 0x00c8" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: "$algo"" assert_output --partial 'label: "ecKeyImport"' assert_output --partial "domains: 2:6:7" assert_output --partial "origin: imported" assert_output --partial "capabilities: sign-attestation-certificate:sign-ecdsa" run "${command_args[@]}" -p password -a get-public-key -i "$import_key" --outformat=PEM --out "$algo"-import.pubkey assert_success "Get public key" #Signing run "${command_args[@]}" -p password -a sign-ecdsa -i "$genkey" -A ecdsa-sha1 --in data.txt --outformat=PEM --out data."$algo"-sha1gen.sig assert_success "Sign with generated key and ecdsa-sha1" run openssl dgst -sha1 -verify "$algo"-gen.pubkey -signature data."$algo"-sha1gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$genkey" -A ecdsa-sha256 --in data.txt --outformat=PEM --out data."$algo"-sha256gen.sig assert_success "Sign with generated key and ecdsa-sha256" run openssl dgst -sha256 -verify "$algo"-gen.pubkey -signature data."$algo"-sha256gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$genkey" -A ecdsa-sha384 --in data.txt --outformat=PEM --out data."$algo"-sha384gen.sig assert_success "Sign with generated key and ecdsa-sha384" run openssl dgst -sha384 -verify "$algo"-gen.pubkey -signature data."$algo"-sha384gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$genkey" -A ecdsa-sha512 --in data.txt --outformat=PEM --out data."$algo"-sha512gen.sig assert_success "Sign with generated key and ecdsa-sha512" run openssl dgst -sha512 -verify "$algo"-gen.pubkey -signature data."$algo"-sha512gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$import_key" -A ecdsa-sha1 --in data.txt --outformat=PEM --out data."$algo"-sha1import.sig assert_success "Sign with imported key and ecdsa-sha1" run openssl dgst -sha1 -verify "$algo"-import.pubkey -signature data."$algo"-sha1import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$import_key" -A ecdsa-sha256 --in data.txt --outformat=PEM --out data."$algo"-sha256import.sig assert_success "Sign with imported key and ecdsa-sha256" run openssl dgst -sha256 -verify "$algo"-import.pubkey -signature data."$algo"-sha256import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$import_key" -A ecdsa-sha384 --in data.txt --outformat=PEM --out data."$algo"-sha384import.sig assert_success "Sign with imported key and ecdsa-sha384" run openssl dgst -sha384 -verify "$algo"-import.pubkey -signature data."$algo"-sha384import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$import_key" -A ecdsa-sha512 --in data.txt --outformat=PEM --out data."$algo"-sha512import.sig assert_success "Sign with imported key and ecdsa-sha512" run openssl dgst -sha512 -verify "$algo"-import.pubkey -signature data."$algo"-sha512import.sig data.txt assert_success "Verify signature with openssl" #Get attestation certificate and selfsigned certificate if "${command_args[@]}" -p password -a sign-attestation-certificate -i "$genkey" --attestation-id 0 2>&1 > /dev/null;then # Some YubiHSMs does not have default attestation certificate run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$genkey" --attestation-id 0 --out cert.pem assert_success "Sign attestation cert with default key" run openssl x509 -in cert.pem -out cert.der -outform DER assert_success "Convert cert format" run "${command_args[@]}" -p password -a put-opaque -i "$genkey" -l template_cert -A opaque-x509-certificate --in cert.der assert_success "Import attestation cert as template cert (same ID as generated key)" run "${command_args[@]}" -p password -a put-opaque -i "$import_key" -l template_cert -A opaque-x509-certificate --in cert.der assert_success "Import attestation cert as template cert (same ID as imported key)" run rm cert.der assert_success "Remove der cert" else run "${command_args[@]}" -p password -a put-opaque -i "$genkey" -l template_cert_gen -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem assert_success "Import attestation cert as template cert (same ID as generated key)" run "${command_args[@]}" -p password -a put-opaque -i "$import_key" -l template_cert_imp -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem assert_success "Import attestation cert as template cert (same ID as imported key)" fi run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$genkey" --attestation-id="$genkey" --out selfsigned_cert.pem assert_success "Get selfsigned certificate" run "${command_args[@]}" -p password -a delete-object -i "$genkey" -t opaque assert_success "Delete template certificate" run "${command_args[@]}" -p password -a put-opaque -i "$genkey" -l java_cert -A opaque-x509-certificate --informat=PEM --in selfsigned_cert.pem assert_success "Import selfsigned with same key ID" run rm selfsigned_cert.pem assert_success "Remove selfsigned cert" #Sign attestation certificate run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$genkey" --attestation-id="$import_key" --out selfsigned_cert.pem assert_success "Sign attestation cert with imported key" run "${command_args[@]}" -p password -a delete-object -i "$genkey" -t opaque assert_success "Delete template certificate" run "${command_args[@]}" -p password -a delete-object -i "$import_key" -t opaque assert_success "Delete template certificate" run rm selfsigned_cert.pem assert_success "Remove selfsigned cert" #Derive ECDH run openssl ec -in "$curve"-keypair.pem -pubout -out "$curve"-pubkey.pem assert_success "Get imported key public key with OpenSSL" run "${command_args[@]}" -p password -a derive-ecdh -i "$genkey" --in "$curve"-pubkey.pem --outformat binary --out "$algo"-ecdh-shell.key assert_success "Derive ECDH key with yubihsm-shell" run openssl pkeyutl -derive -inkey "$curve"-keypair.pem -peerkey "$algo"-gen.pubkey -out "$algo"-ecdh-openssl.key assert_success "Derive ECDH key with OpenSSL" run cmp "$algo"-ecdh-shell.key "$algo"-ecdh-openssl.key assert_success "Compare derived keys" #make PKCS10 certificate signing request run "${command_args[@]}" -p password -a generate-csr -i "$genkey" -S /CN=test/ --out csr.pem assert_success "Generate CSR with yubihsm-shell" run openssl req -in csr.pem -verify assert_success "Verify CSR with openssl" run rm csr.pem assert_success "Remove CSR" #Clean up run "${command_args[@]}" -p password -a delete-object -i "$genkey" -t asymmetric-key assert_success "Delete generated key" run "${command_args[@]}" -p password -a delete-object -i "$import_key" -t asymmetric-key assert_success "Delete imported key" done } @test "RSA Key tests" { [[ "$RSA_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") RSA_KEYSIZE=("2048" "3072" "4096") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 for k in ${RSA_KEYSIZE[@]}; do echo "Testing RSA "$k" key" >&3 if [ "$k" -ne "2048" ]; then echo "This may take a while..." >&3 fi #Generate Key run "${command_args[@]}" -p password -a generate-asymmetric-key -i 0 -l rsaKey -d 1 -c sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate -A rsa"$k" assert_success "Generate RSA "$k" key" keyid=$(echo "$output" | tail -n 1 | awk '{print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: "$keyid"" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: rsa"$k"" assert_output --partial "label: \"rsaKey\"" assert_output --partial "domains: 1" assert_output --partial "origin: generated" assert_output --partial "decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss" run "${command_args[@]}" -p password -a get-public-key -i "$keyid" --outformat=PEM --out pubkey_rsa"$k".pem assert_success "Get public key" #Import key run openssl genrsa -out rsa"$k"-keypair.pem "$k" assert_success "Generate key with OpenSSL" run "${command_args[@]}" "${command_args[@]}" -p password -a put-asymmetric-key -i 0 -l rsaKeyImport -d 2 -c sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate --in=rsa"$k"-keypair.pem assert_success "Import key" import_keyid=$(echo "$output" | tail -n 1 | awk '{print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$import_keyid" -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: "$import_keyid"" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: rsa"$k"" assert_output --partial "label: \"rsaKeyImport\"" assert_output --partial "domains: 2" assert_output --partial "origin: imported" assert_output --partial "decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss" run "${command_args[@]}" -p password -a get-public-key -i "$import_keyid" --outformat=PEM --out pubkey_rsa"$k".imported.pem assert_success "Get public key" #Signing with generated key run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$keyid" -A rsa-pkcs1-sha1 --in data.txt --outformat binary --out data."$k"-pkcs1sha1gen.sig assert_success "Sign with rsa-pkcs1-sha1" run openssl dgst -sha1 -verify pubkey_rsa"$k".pem -signature data."$k"-pkcs1sha1gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$keyid" -A rsa-pkcs1-sha256 --in data.txt --outformat binary --out data."$k"-pkcs1sha256gen.sig assert_success "Sign with rsa-pkcs1-sha256" run openssl dgst -sha256 -verify pubkey_rsa"$k".pem -signature data."$k"-pkcs1sha256gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$keyid" -A rsa-pkcs1-sha384 --in data.txt --outformat binary --out data."$k"-pkcs1sha384gen.sig assert_success "Sign with rsa-pkcs1-sha384" run openssl dgst -sha384 -verify pubkey_rsa"$k".pem -signature data."$k"-pkcs1sha384gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$keyid" -A rsa-pkcs1-sha512 --in data.txt --outformat binary --out data."$k"-pkcs1sha512gen.sig assert_success "Sign with rsa-pkcs1-sha512" run openssl dgst -sha512 -verify pubkey_rsa"$k".pem -signature data."$k"-pkcs1sha512gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$keyid" -A rsa-pss-sha1 --in data.txt --outformat binary --out data."$k"-psssha1gen.sig assert_success "Sign with rsa-pss-sha1" run openssl dgst -sha1 -binary -out data.sha1 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha1 -sigfile data."$k"-psssha1gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$keyid" -A rsa-pss-sha256 --in data.txt --outformat binary --out data."$k"-psssha256gen.sig assert_success "Sign with rsa-pss-sha256" run openssl dgst -sha256 -binary -out data.sha256 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha256 -sigfile data."$k"-psssha256gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$keyid" -A rsa-pss-sha384 --in data.txt --outformat binary --out data."$k"-psssha384gen.sig assert_success "Sign with rsa-pss-sha384" run openssl dgst -sha384 -binary -out data.sha384 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha384 -sigfile data."$k"-psssha384gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$keyid" -A rsa-pss-sha512 --in data.txt --outformat binary --out data."$k"-psssha512gen.sig assert_success "Sign with rsa-pss-sha512" run openssl dgst -sha512 -binary -out data.sha512 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha512 -sigfile data."$k"-psssha512gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512 assert_success "Verify signature with openssl" #Signing with imported key run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$import_keyid" -A rsa-pkcs1-sha1 --in data.txt --outformat binary --out data."$k"-pkcs1sha1import.sig assert_success "Sign with rsa-pkcs1-sha1" run openssl dgst -sha1 -verify pubkey_rsa"$k".imported.pem -signature data."$k"-pkcs1sha1import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$import_keyid" -A rsa-pkcs1-sha256 --in data.txt --outformat binary --out data."$k"-pkcs1sha256import.sig assert_success "Sign with rsa-pkcs1-sha256" run openssl dgst -sha256 -verify pubkey_rsa"$k".imported.pem -signature data."$k"-pkcs1sha256import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$import_keyid" -A rsa-pkcs1-sha384 --in data.txt --outformat binary --out data."$k"-pkcs1sha384import.sig assert_success "Sign with rsa-pkcs1-sha384" run openssl dgst -sha384 -verify pubkey_rsa"$k".imported.pem -signature data."$k"-pkcs1sha384import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$import_keyid" -A rsa-pkcs1-sha512 --in data.txt --outformat binary --out data."$k"-pkcs1sha512import.sig assert_success "Sign with rsa-pkcs1-sha512" run openssl dgst -sha512 -verify pubkey_rsa"$k".imported.pem -signature data."$k"-pkcs1sha512import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$import_keyid" -A rsa-pss-sha1 --in data.txt --outformat binary --out data."$k"-psssha1import.sig assert_success "Sign with rsa-pss-sha1" run openssl dgst -sha1 -binary -out data.sha1 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha1 -sigfile data."$k"-psssha1import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$import_keyid" -A rsa-pss-sha256 --in data.txt --outformat binary --out data."$k"-psssha256import.sig assert_success "Sign with rsa-pss-sha256" run openssl dgst -sha256 -binary -out data.sha256 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha256 -sigfile data."$k"-psssha256import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$import_keyid" -A rsa-pss-sha384 --in data.txt --outformat binary --out data."$k"-psssha384import.sig assert_success "Sign with rsa-pss-sha384" run openssl dgst -sha384 -binary -out data.sha384 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha384 -sigfile data."$k"-psssha384import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$import_keyid" -A rsa-pss-sha512 --in data.txt --outformat binary --out data."$k"-psssha512import.sig assert_success "Sign with rsa-pss-sha512" run openssl dgst -sha512 -binary -out data.sha512 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha512 -sigfile data."$k"-psssha512import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512 assert_success "Verify signature with openssl" #Make self signed certificate if "${command_args[@]}" -p password -a sign-attestation-certificate -i "$keyid" --attestation-id 0 2>&1 > /dev/null;then #Some YubiHSMs does not have default attestation certificate run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$keyid" --attestation-id 0 --out cert.pem assert_success "Sign attestation cert with default key" run openssl x509 -in cert.pem -out cert.der -outform DER assert_success "Convert cert format" run "${command_args[@]}" -p password -a put-opaque -i "$keyid" -l template_cert -A opaque-x509-certificate --in cert.der assert_success "Import attestation cert as template cert (same ID as generated key)" run "${command_args[@]}" -p password -a put-opaque -i "$import_keyid" -l template_cert -A opaque-x509-certificate --in cert.der assert_success "Import attestation cert as template cert (same ID as imported key)" run rm cert.der assert_success "Remove der cert" else run "${command_args[@]}" -p password -a put-opaque -i "$keyid" -l template_cert_gen -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem assert_success "Import attestation cert as template cert (same ID as generated key)" run "${command_args[@]}" -p password -a put-opaque -i "$import_keyid" -l template_cert_imp -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem assert_success "Import attestation cert as template cert (same ID as imported key)" fi run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$keyid" --attestation-id="$keyid" --out selfsigned_cert.pem assert_success "Sign attestation with same key (aka. get selfsigned cert)" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t opaque assert_success "Delete template certificate" run "${command_args[@]}" -p password -a put-opaque -i "$keyid" -l java_cert -A opaque-x509-certificate --informat=PEM --in selfsigned_cert.pem assert_success "Import selfsigned with same key ID" run rm selfsigned_cert.pem assert_success "Remove selfsigned cert" #Sign attestation certificate run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$keyid" --attestation-id="$import_keyid" --out selfsigned_cert.pem assert_success "Sign attestation cert with imported key" run rm selfsigned_cert.pem assert_success "Remove selfsigned cert" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t opaque assert_success "Delete template certificate" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t opaque assert_success "Delete template certificate" #Decryption with generated key and PKCS1v15 run openssl rsautl -encrypt -inkey pubkey_rsa"$k".pem -pubin -in data.txt -out data.enc assert_success "Encrypt data with openssl" run "${command_args[@]}" -p password -a decrypt-pkcs1v15 -i "$keyid" --in data.enc --out data.dec assert_success "Decrypt data with yubihsm-shell" run cmp data.txt data.dec assert_success "Compare decrypted data with plain text data" run rm data.dec assert_success "Remove decrypted data" #Decryption with imported key and PKCS1v15 run openssl rsautl -encrypt -inkey pubkey_rsa"$k".imported.pem -pubin -in data.txt -out data.enc assert_success "Encrypt data with openssl" run "${command_args[@]}" -p password -a decrypt-pkcs1v15 -i "$import_keyid" --in data.enc --out data.dec assert_success "Decrypt data with yubihsm-shell" run cmp data.txt data.dec assert_success "Compare decrypted data with plain text data" run rm data.dec assert_success "Remove decrypted data" #Make PKCS10 Certificate Signing Request run openssl req -new -key rsa$k-keypair.pem -subj /CN=test -out csr-ossl.pem assert_success "Generate CSR with OpenSSL" run "${command_args[@]}" -p password -a generate-csr -i "$import_keyid" -S /CN=test/ --out csr.pem assert_success "Generate CSR with yubihsm-shell" run openssl req -in csr.pem -verify assert_success "Verify CSR with openssl" run cmp csr-ossl.pem csr.pem assert_success "Compare CSR with OpenSSL generated CSR" run rm csr.pem csr-ossl.pem assert_success "Remove CSR" #Clean up run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t asymmetric-key assert_success "Delete generated key" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t asymmetric-key assert_success "Delete imported key" done run openssl req -x509 -newkey rsa:4096 -out too_large_cert.pem -sha256 -days 3650 -nodes -subj '/C=01/ST=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/L=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/O=0123456789012345678901234567890123456789012345678901234567890123/OU=0123456789012345678901234567890123456789012345678901234567890123/CN=0123456789012345678901234567890123456789012345678901234567890123/CN=0123456789012345678901234567890123456789012345678901234567890123' > /dev/null 2>&1 assert_success "Generate too large certificate with OpenSSL" run "${command_args[@]}" -p password -a put-opaque -i 100 -l too_large_cert -A opaque-x509-certificate --in too_large_cert.pem --informat PEM if [ "$status" -eq 0 ]; then assert_success "Import large certificate raw" echo "Imported x509 certificate raw" >&3 elif [[ "$output" == *"Failed to store opaque object: Not enough space to store data"* ]]; then run "${command_args[@]}" -p password -a put-opaque -i 100 -l too_large_cert -A opaque-x509-certificate --with-compression --in too_large_cert.pem --informat PEM assert_success "Import compressed x509 certificate" echo "Imported compressed x509 Certificate" >&3 else fail "Import of x509 certificate failed" fi run "${command_args[@]}" -p password -a get-opaque -i 100 --outformat=PEM --out too_large_cert_out.pem assert_success "Get too large certificate" run cmp too_large_cert.pem too_large_cert_out.pem assert_success "Compare imported and read certificate" run "${command_args[@]}" -p password -a delete-object -i 100 -t opaque assert_success "Delete too large certificate" } @test "HMAC Key tests" { [[ "$HMAC_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") algorithms=("hmac-sha1" "hmac-sha256" "hmac-sha384" "hmac-sha512") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 for algo in ${algorithms[@]}; do echo "$algo" >&3 run "${command_args[@]}" -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A "$algo" assert_success "Generate "$algo" key" keyid=$(echo "$output" | tail -n 1 | awk '{print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t hmac-key assert_success "get-object-info" assert_output --partial "id: "$keyid"" assert_output --partial "type: hmac-key" assert_output --partial "algorithm: "$algo"" assert_output --partial "label: \"hmackey\"" assert_output --partial "domains: 1:2:3" assert_output --partial "origin: generated" assert_output --partial "sign-hmac" done } @test "OTP AEAD Key tests" { [[ "$OTP_AEAD_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") algorithms=("aes128" "aes192" "aes256") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 for algo in ${algorithms[@]}; do echo "$algo" >&3 run "${command_args[@]}" -p password -a generate-otp-aead-key -i 0 -l aeadkey -d 1,2,3 -c randomize-otp-aead -A "$algo"-yubico-otp --nonce 0x01020304 assert_success "Generate Key" keyid=$(echo "$output" | tail -n 1 | awk '{print $5}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t otp-aead-key assert_success "Get object info" assert_output --partial "id: "$keyid"" assert_output --partial "type: otp-aead-key" assert_output --partial "algorithm: "$algo"-yubico-otp" assert_output --partial "label: \"aeadkey\"" assert_output --partial "domains: 1:2:3" assert_output --partial "origin: generated" assert_output --partial "capabilities: randomize-otp-aead" run "${command_args[@]}" -p password -a randomize-otp-aead -i "$keyid" assert_success "Randomize OTP AEAD" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t otp-aead-key assert_success "Delete key" done } @test "Template tests" { [[ "$TEMPLATE_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a put-template -i 20 -l "SSH_Template" -d 1 -A template-ssh --in ../template.dat assert_success "Import template" id=$(echo "$output" | grep "Stored Template object" | awk '{print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$id" -t template assert_success "Get object info" assert_output --partial "id: "$id"" assert_output --partial "type: template" assert_output --partial "algorithm: template-ssh" assert_output --partial "label: \"SSH_Template\"" assert_output --partial "domains: 1" assert_output --partial "origin: imported" #This command doesn't work right now. #run "${command_args[@]}" --authkey=0x0001 -p password -a sign-ssh-certificate -i 10 --template-id 20 -A rsa-pkcs1-sha256 --in ../req.dat --out ./id_rsa-cert.pub #assert_success "sign request" run "${command_args[@]}" -p password -a get-template -i "$id" assert_success "Get template" run "${command_args[@]}" -p password -a delete-object -i "$id" -t template assert_success "Delete template" } @test "Wrap Keys tests" { [[ "$WRAP_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") algorithms=("aes128-ccm-wrap" "aes192-ccm-wrap" "aes256-ccm-wrap") eckey=100 aeskey=200 sequence=0 RSA_KEYSIZE=("2048" "3072" "4096") seq_ec=6 seq_aes=0 aes_enabled=false run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a generate-asymmetric-key -i "$eckey" -l eckey -d 1 -c exportable-under-wrap,sign-ecdsa -A ecp224 assert_success "Generate EC Key to wrap" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" assert_output --partial "sequence: "$sequence"" sequence=$((sequence+1)) assert_output --partial "origin: generated" for algo in ${algorithms[@]}; do echo "$algo" >&3 length=24 import_count=16 if [ "$algo" == "aes192-ccm-wrap" ]; then length=32 import_count=24 elif [ "$algo" == "aes256-ccm-wrap" ]; then length=40 import_count=32 fi #Generate key run "${command_args[@]}" -p password -a generate-wrap-key -i 0 -l wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap -A "$algo" assert_success "Generate wrap key" keyid=$(echo "$output" | awk '/Generated Wrap key/ {print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t wrap-key assert_success "Get object info" assert_output --partial "algorithm: "$algo"" assert_output --partial "length: "$length"" #Import key run "${command_args[@]}" -p password -a get-pseudo-random --count "$import_count" assert_success "Get random 16 bytes" wrapkey=$(echo "$output" | tail -n 1) run "${command_args[@]}" -p password -a put-wrap-key -i 0 -l imported_wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap --in="$wrapkey" assert_success "Import wrap key" import_keyid=$(echo "$output" | awk '/Stored Wrap key/ {print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$import_keyid" -t wrap-key assert_success "Get object info" assert_output --partial "algorithm: "$algo"" assert_output --partial "length: "$length"" assert_output --partial "origin: imported" #Wrap and unwrap with generated wrap key run "${command_args[@]}" -p password -a get-wrapped --wrap-id "$keyid" -i 100 -t asymmetric-key --out key.gen_wrapped assert_success "Wrap EC key" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-wrapped --wrap-id "$keyid" --in key.gen_wrapped assert_success "Wrap EC key" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" assert_output --partial "sequence: "$sequence"" sequence=$((sequence+1)) assert_output --partial "origin: generated:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped key" #Wrap and unwrap objects with imported wrap key run "${command_args[@]}" -p password -a get-wrapped --wrap-id "$import_keyid" -i 100 -t asymmetric-key --out key.imp_wrapped assert_success "Wrap EC key" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-wrapped --wrap-id "$import_keyid" --in key.imp_wrapped assert_success "Wrap EC key" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" assert_output --partial "sequence: "$sequence"" sequence=$((sequence+1)) assert_output --partial "origin: generated:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped key" #Clean up run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t wrap-key assert_success "Delete generated wrap key" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t wrap-key assert_success "Delete imported wrap key" run rm key.gen_wrapped key.imp_wrapped assert_success "Deleted generated and imported wrap keys" done run "${command_args[@]}" -p password -a get-device-info assert_success "Get device info" if [[ "$output" != *"aes-kwp"* ]]; then run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete object" skip "Device does not support aes-kwp, skipping these tests." fi run "${command_args[@]}" -p password -a get-device-info assert_success "Get device info" if [[ "$output" == *"aes-cbc"* ]]; then aes_enabled=true run "${command_args[@]}" -p password -a generate-symmetric-key -i "$aeskey" -l aeskey -d 1 -c exportable-under-wrap,encrypt-cbc,decrypt-cbc -A aes128 assert_success "Generate AES key to wrap" run "${command_args[@]}" -p password -a get-pseudo-random --count 16 assert_success "Get random 16 bytes" iv=$(echo "$output" | tail -n 1) run "${command_args[@]}" -p password -a get-pseudo-random --count 32 assert_success "Get random 32 bytes for encryption" data=$(echo "$output" | tail -n 1) fi for k in ${RSA_KEYSIZE[@]}; do echo "RSA"$k"" >&3 if [[ "$k" != "2048" ]]; then echo "This may take a while..." >&3 fi #Generate RSA wrap keys run "${command_args[@]}" -p password -a generate-wrap-key -i 0 -l wrapkey -c import-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc -A rsa"$k" assert_success "Generate RSA wrap key" keyid=$(echo "$output" | awk '/Generated Wrap key/ {print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t wrap-key assert_success "Get object into" assert_output --partial "algorithm: rsa"$k"" assert_output --partial "origin: generated" run "${command_args[@]}" -p password -a get-public-key -i "$keyid" -t wrap-key --out public_wrapkey.pem assert_success "Export rsa public wrap key" run "${command_args[@]}" -p password -a put-public-wrapkey -i "$keyid" -c export-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in public_wrapkey.pem assert_success "Import RSA public wrap key" run rm public_wrapkey.pem assert_success "Delete wrapkey" #Wrap and unwrap EC object with generated wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped --wrap-id "$keyid" -i "$eckey" -t asymmetric-key --out rsawrapped.object assert_success "Export wrapped EC object" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-rsa-wrapped --wrap-id "$keyid" --in rsawrapped.object assert_success "Import wrapped EC object" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" seq_ec=$((seq_ec+1)) assert_output --partial "sequence: "$seq_ec"" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run rm rsawrapped.object assert_success "Removed RSA wrapped object" #Wrap and unwrap EC key material with generated RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped-key --wrap-id "$keyid" -i "$eckey" -t asymmetric-key --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --out rsawrapped.key assert_success "Export wrapped EC key material" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-rsa-wrapped-key --wrap-id "$keyid" -i "$eckey" -t asymmetric-key -A ecp224 -c exportable-under-wrap,sign-ecdsa --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --in rsawrapped.key assert_success "Import wrapped EC key material" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" seq_ec=$((seq_ec+1)) assert_output --partial "sequence: "$seq_ec"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run rm rsawrapped.key assert_success "Removed RSA wrapped key" if [[ "$aes_enabled" = true ]]; then #Wrap and unwrap AES object with generated RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped --wrap-id "$keyid" -i "$aeskey" -t symmetric-key --out rsawrapped.object assert_success "Export wrapped AES object" run "${command_args[@]}" -p password -a delete-object -i "$aeskey" -t symmetric-key assert_success "Delete AES key" run "${command_args[@]}" -p password -a put-rsa-wrapped --wrap-id "$keyid" --in rsawrapped.object assert_success "Import wrapped AES object" run "${command_args[@]}" -p password -a get-object-info -i "$aeskey" -t symmetric-key assert_success "Get object info" seq_aes=$((seq_aes+1)) assert_output --partial "sequence: "$seq_aes"" assert_output --partial "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" run "${command_args[@]}" -p password -a encrypt-aescbc -i "$aeskey" --iv "$iv" --in "$data" --out data.enc assert_success "Perform encryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc decrypted_data=$(echo "$output" | tail -n 1) assert_equal "$decrypted_data" "$data" assert_success "Perform decryption with imported wrapped AES key" run rm rsawrapped.object data.enc assert_success "Removed RSA wrapped object and encrypted data" #Wrap and unwrap AES key material with generated RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped-key --wrap-id "$keyid" -i "$aeskey" -t symmetric-key --oaep rsa-oaep-sha384 --mgf1 mgf1-sha1 --out rsawrapped.key assert_success "Export wrapped AES key material" run "${command_args[@]}" -p password -a delete-object -i "$aeskey" -t symmetric-key assert_success "Delete AES key" run "${command_args[@]}" -p password -a put-rsa-wrapped-key --wrap-id "$keyid" -i "$aeskey" -t symmetric-key -A aes128 -c exportable-under-wrap,decrypt-cbc,encrypt-cbc --oaep rsa-oaep-sha384 --mgf1 mgf1-sha1 --in rsawrapped.key assert_success "Import wrapped AES key material" run "${command_args[@]}" -p password -a get-object-info -i "$aeskey" -t symmetric-key assert_success "Get object info" seq_aes=$((seq_aes+1)) assert_output --partial "sequence: "$seq_aes"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run "${command_args[@]}" -p password -a encrypt-aescbc -i "$aeskey" --iv "$iv" --in "$data" --out data.enc assert_success "Perform encryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Perform decryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Decryption succeeded" last_line_of_output=$(echo "$output" | tail -n 1) assert_equal "$last_line_of_output" "$data" run rm rsawrapped.key data.enc assert_success "Removed RSA wrapped key and encrypted data" fi #Import RSA wrap keys run openssl genrsa -out keypair.pem "$k" assert_success "Generate RSA key with openssl" run openssl rsa -in keypair.pem -pubout -out key.pub assert_success "Extract public key from openssl generated keypair" run "${command_args[@]}" -p password -a put-rsa-wrapkey -i 0 -d 1 -c import-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in keypair.pem assert_success "Import RSA wrap key" import_keyid=$(echo "$output" | awk '/Stored Wrap key/ {print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$import_keyid" -t wrap-key assert_success "Get object info" assert_output --partial "algorithm: rsa"$k"" assert_output --partial "origin: imported" run "${command_args[@]}" -p password -a put-public-wrapkey -i "$import_keyid" -c export-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in key.pub assert_success "Import RSA public wrap key" run rm keypair.pem key.pub assert_success "Remove keypairs" #Wrap and unwrap EC object with imported RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped --wrap-id "$import_keyid" -i "$eckey" -t asymmetric-key --out rsawrapped.object assert_success "Export wrapped EC object" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-rsa-wrapped --wrap-id "$import_keyid" --in rsawrapped.object assert_success "Import wrapped EC objects" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" seq_ec=$((seq_ec+1)) assert_output --partial "sequence: "$seq_ec"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run rm rsawrapped.object assert_success "Delete RSA wrapped object" #Wrap and unwrap EC key material with imported RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped-key --wrap-id "$import_keyid" -i "$eckey" -t asymmetric-key --oaep rsa-oaep-sha512 --mgf1 mgf1-sha512 --out rsawrapped.key assert_success "Export wrapped EC key material" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-rsa-wrapped-key --wrap-id "$import_keyid" -i "$eckey" -t asymmetric-key -A ecp224 -c exportable-under-wrap,sign-ecdsa --oaep rsa-oaep-sha512 --mgf1 mgf1-sha512 --in rsawrapped.key assert_success "Import wrapped EC key material" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" seq_ec=$((seq_ec+1)) assert_output --partial "sequence: "$seq_ec"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run rm rsawrapped.key assert_success "Removed RSA wrapped key" if [[ "$aes_enabled" = true ]]; then #Wrap and unwrap AES object with imported RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped --wrap-id "$import_keyid" -i "$aeskey" -t symmetric-key --out rsawrapped.object assert_success "Export wrapped AES object" run "${command_args[@]}" -p password -a delete-object -i "$aeskey" -t symmetric-key assert_success "Deleta AES key" run "${command_args[@]}" -p password -a put-rsa-wrapped --wrap-id "$import_keyid" --in rsawrapped.object assert_success "Import wrapped AES object" run "${command_args[@]}" -p password -a get-object-info -i "$aeskey" -t symmetric-key assert_success "Get object info" seq_aes=$((seq_aes+1)) assert_output --partial "sequence: "$seq_aes"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" run "${command_args[@]}" -p password -a encrypt-aescbc -i "$aeskey" --iv "$iv" --in "$data" --out data.enc assert_success "Perform encryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Perform decryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Decryption succeeded" last_line_of_output=$(echo "$output" | tail -n 1) assert_equal "$last_line_of_output" "$data" run rm rsawrapped.object data.enc assert_success "Removed RSA wrapped object and encrypted data" #Wrap and unwrap AES key material with imported RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped-key --wrap-id "$import_keyid" -i "$aeskey" -t symmetric-key --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --out rsawrapped.key assert_success "Export wrapped AES key material" run "${command_args[@]}" -p password -a delete-object -i "$aeskey" -t symmetric-key assert_success "Delete AES key" run "${command_args[@]}" -p password -a put-rsa-wrapped-key --wrap-id "$import_keyid" -i "$aeskey" -t symmetric-key -A aes128 -c exportable-under-wrap,decrypt-cbc,encrypt-cbc --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --in rsawrapped.key assert_success "Import wrapped AES key materiak" run "${command_args[@]}" -p password -a get-object-info -i "$aeskey" -t symmetric-key assert_success "Get object info" seq_aes=$((seq_aes+1)) assert_output --partial "sequence: "$seq_aes"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform encryption with imported wrapped EC key" run "${command_args[@]}" -p password -a encrypt-aescbc -i "$aeskey" --iv "$iv" --in "$data" --out data.enc assert_success "Perform encryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Perform decryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Decryption succeeded" last_line_of_output=$(echo "$output" | tail -n 1) assert_equal "$last_line_of_output" "$data" run rm rsawrapped.key data.enc assert_success "Removed RSA wrapped key and encrypted data" fi #Clean up run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t wrap-key assert_success "Delete generated RSA wrap key" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t public-wrap-key assert_success "Delete generated RSA public wrap key" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t wrap-key assert_success "Delete imported RSA wrap key" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t public-wrap-key assert_success "Delete imported RSA public wrap key" done } @test "List Objects" { [[ "$LIST_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a generate-asymmetric-key -i 100 -l ecKey -d 5,8,13 -c sign-ecdsa,derive-ecdh,sign-attestation-certificate -A ecp224 assert_success "Generate EC key for testing" run "${command_args[@]}" -p password -a list-objects -A any -t any -i 100 assert_success "List objects by ID" assert_output --partial "Found 1 object(s)" run "${command_args[@]}" -p password -a list-objects -A any -t asymmetric-key assert_success "List objects by type" assert_output --partial "Found 1 object(s)" run "${command_args[@]}" -p password -a list-objects -A any -t any -d 5,8,13 assert_success "List objects by domain" assert_output --partial "Found 2 object(s)" run "${command_args[@]}" -p password -a list-objects -A any -t any -c sign-ecdsa,derive-ecdh,sign-attestation-certificate assert_success "List objects by capabilities" assert_output --partial "Found 2 object(s)" run "${command_args[@]}" -p password -a list-objects -A ecp224 -t any assert_success "List objects by algorithm" assert_output --partial "Found 1 object(s)" run "${command_args[@]}" -p password -a list-objects -A any -t any -l ecKey assert_success "List objects by label" assert_output --partial "Found 1 object(s)" run "${command_args[@]}" -p password -a delete-object -i 100 -t asymmetric-key assert_success "Delete key" } @test "Label Size" { [[ "$LABEL_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a generate-asymmetric-key -i 300 -d 5,8,13 -c sign-ecdsa -A ecp224 assert_success "Create key with no label" run "${command_args[@]}" -p password -a get-object-info -i 300 -t asymmetric-key assert_success "Get info for key with no label" assert_output --partial "label: \"\"" # --- Test with 39-character label --- run "${command_args[@]}" -p password -a generate-asymmetric-key -i 200 -l abcdefghijklmnopqrstuvwxyz0123456789abc -d 5,8,13 -c sign-ecdsa -A ecp224 assert_success "Create object with 39-character label" run "${command_args[@]}" -p password -a get-object-info -i 200 -t asymmetric-key assert_success "Get info for 39-character label" assert_output --partial "label: \"abcdefghijklmnopqrstuvwxyz0123456789abc\"" run "${command_args[@]}" -p password -a list-objects -A any -t any -l abcdefghijklmnopqrstuvwxyz0123456789abc assert_success "List objects with 39-character label" assert_output --partial "Found 1 object(s)" # --- Test with 40-character label --- run "${command_args[@]}" -p password -a generate-asymmetric-key -i 100 -l abcdefghijklmnopqrstuvwxyz0123456789abcd -d 5,8,13 -c sign-ecdsa -A ecp224 assert_success "Create object with 40-character label" run "${command_args[@]}" -p password -a list-objects -A any -t any -l abcdefghijklmnopqrstuvwxyz0123456789abcd assert_success "List objects with 40-character label" assert_output --partial "Found 1 object(s)" # --- Test that 41-character label FAILS --- run "${command_args[@]}" -p password -a generate-asymmetric-key -i 400 -l "abcdefghijklmnopqrstuvwxyz0123456789abcde" -d "5,8,13" -c "sign-ecdsa" -A "ecp224" assert_failure assert_output --partial "Invalid argument to a function" # --- Test listing a non-existent label --- run "${command_args[@]}" -p password -a list-objects -A any -t any -l doesnotexist assert_success "List objects by non-existent label" assert_output --partial "Found 0 object(s)" # --- Clean up created objects --- run "${command_args[@]}" -p password -a delete-object -i 100 -t asymmetric-key assert_success "Clean up key 100" run "${command_args[@]}" -p password -a delete-object -i 200 -t asymmetric-key assert_success "Clean up key 200" run "${command_args[@]}" -p password -a delete-object -i 300 -t asymmetric-key assert_success "Clean up key 300" } @test "Authentication" { [[ "$AUTHENTICATION_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a put-authentication-key -i 0 -l authkey -d 1,2,3 -c all --delegated all --new-password foo123 assert_success "Create new authentication key" keyid=$(echo "$output" | tail -1 | awk '{print $4}') run "${command_args[@]}" --authkey "$keyid" -p foo123 -a get-object-info -i 1 -t authentication-key assert_success "Authenticate with new authentication key" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t authentication-key assert_success "Delete authentication key" }yubihsm-shell-2.7.3/resources/tests/bash/test_x509template.pem0000644000175000017500000000172515167357110023375 0ustar aveenaveen-----BEGIN CERTIFICATE----- MIICpzCCAY+gAwIBAgIRALnaMgizd13cmPh34E4HNz0wDQYJKoZIhvcNAQELBQAw KjEoMCYGA1UEAwwfWXViaUhTTTIgQXR0ZXN0YXRpb24gKDEzMjAwNTAxKTAgFw0x NzAxMDEwMDAwMDBaGA8yMDcxMTAwNTAwMDAwMFowKDEmMCQGA1UEAwwdWXViaUhT TSBBdHRlc3RhdGlvbiBpZDoweDU2MGQwTjAQBgcqhkjOPQIBBgUrgQQAIQM6AATn 8QLCgsBZlpkoqdMOTbWS/tOiXfI1aOMrUQC+w6rWw8WwEbJ7LjqoPwdWg0DKrXeA 7sAEMUKX4aOBnTCBmjATBgorBgEEAYLECgQBBAUEAwIBAzAUBgorBgEEAYLECgQC BAYCBADJbHUwEgYKKwYBBAGCxAoEAwQEAwIAATATBgorBgEEAYLECgQEBAUDAwAQ kDAZBgorBgEEAYLECgQFBAsDCQAAAAAEAAAIgDASBgorBgEEAYLECgQGBAQCAlYN MBUGCisGAQQBgsQKBAkEBwwFZWNLZXkwDQYJKoZIhvcNAQELBQADggEBAEV/0jl7 ulAmLLiYGV8ELoavjtJ3wmMLyJpSURC8WPO8MucAopIsh0URXKpjLjHQHqscdAbP DyT+/l1VfFS7Fvsz/OXeMP1dYzpoYzw4iyHFkvf5G8k0hxY+BEqBa89MXKGrcDo0 iu0lSusaEJF2zq3PH3hnPIXm9SJDfWcZ7iueA0xGu6miUz3rHklnbPUqaM/omGyV MgAtLOolX7rnW7E3MEkAOII1kbwv8C/NlseKXyECRvAn2reAMH11c/t2BvGMbD81 OGTPZ2OvfNJcPnzy1olxE0Ajew5CrOB2XrOaqhVrNPA4aqpCT3ukMv60m6TXsHnU RdEhPSf0SomH7MQ= -----END CERTIFICATE----- yubihsm-shell-2.7.3/resources/tests/bash/test_hmackey.sh0000755000175000017500000000720415167357110022407 0ustar aveenaveen#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e echo "====================== HMAC keys ===================== " echo "------------- hmac-sha1" test_with_resp "$BIN -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A hmac-sha1" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t hmac-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t hmac-key 2> /dev/null) test "echo $info | grep \"id: $keyid\"" " Object info contains correct ID" test "echo $info | grep \"type: hmac-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: hmac-sha1\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"hmackey\"'" " Object info contains correct label" test "echo $info | grep \"domains: 1:2:3\"" " Object info contains correct domains" test "echo $info | grep \"origin: generated\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: sign-hmac\"" " Object info contains correct capabilities" #$BIN -p password -a sign-hmac -i $keyid --in data.txt test "$BIN -p password -a delete-object -i $keyid -t hmac-key" " Delete key" echo "------------- hmac-sha256" test_with_resp "$BIN -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A hmac-sha256" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t hmac-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t hmac-key 2> /dev/null) test "echo $info | grep \"algorithm: hmac-sha256\"" " Object info contains correct algorithm" #$BIN -p password -a sign-hmac -i $keyid --in data.txt test "$BIN -p password -a delete-object -i $keyid -t hmac-key" " Delete key" echo "------------- hmac-sha384" test_with_resp "$BIN -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A hmac-sha384" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t hmac-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t hmac-key 2> /dev/null) test "echo $info | grep \"algorithm: hmac-sha384\"" " Object info contains correct algorithm" #$BIN -p password -a sign-hmac -i $keyid --in data.txt test "$BIN -p password -a delete-object -i $keyid -t hmac-key" " Delete key" echo "------------- hmac-sha512" test_with_resp "$BIN -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A hmac-sha512" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t hmac-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t hmac-key 2> /dev/null) test "echo $info | grep \"algorithm: hmac-sha512\"" " Object info contains correct algorithm" #$BIN -p password -a sign-hmac -i $keyid --in data.txt test "$BIN -p password -a delete-object -i $keyid -t hmac-key" " Delete key" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.7.3/resources/tests/bash/cmdline_test.sh0000755000175000017500000002154715167357110022407 0ustar aveenaveen#!/bin/bash if [ "$#" -eq 1 ]; then BIN=$1 # path to the yubihsm-shell command line tool - using default connector elif [ "$#" -gt 1 ]; then BIN="$1 -C $2" # path to the yubihsm-shell command line tool - using specified connector else BIN="yubihsm-shell" fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e test "$BIN --version" "yubihsm-shell --version" test "$BIN --help" "yubihsm-shell --help" test "$BIN -a get-device-info | grep \"Serial number:\"" "yubihsm-shell -a get-device-info" echo "********************************************************** " echo " Reset YubiHSM" echo "********************************************************** " test "$BIN -p password -a reset" sleep 3 echo "********************************************************** " echo " Blink" echo "********************************************************** " test "$BIN -p password -a blink" "-a blink" test "$BIN -p password -a blink --duration=5" "-a blink --duration=5" test "$BIN -p password -a blink-device" "blink-device" test "$BIN -p password -a blink-device --duration=5" "-a blink-device --duration=5" echo "********************************************************** " echo " Get Pseudo-random" echo "********************************************************** " test "$BIN -p password -a get-pseudo-random | wc -c | grep 513" "get-pseudo-random" # includes a new line test "$BIN -p password -a get-pseudo-random --out=random.txt" get-pseudo-random --out=random.txt length=$(cat random.txt | wc -c) if [ $length -ne 512 ]; then echo "Expected 512 but was $length characters. Without specifying byte count, 256 bytes (=512 characters) pseudo random number should have been produced." exit 1; fi rm random.txt test "$BIN -p password -a get-pseudo-random --count=10 | wc -c | grep 21" "get-pseudo-random --count=10" # includes a new line test "$BIN -p password -a get-pseudo-random --count=10 --out=random.txt" "get-pseudo-random --count=10 --out=random.txt" length=$(cat random.txt | wc -c) if [ $length -ne 20 ]; then echo "Expected 20 but was $length characters." exit 1; fi rm random.txt echo "********************************************************** " echo " Asymmetric Keys" echo "********************************************************** " ./test_edkey.sh "$BIN" if [ -z ${DOCKER_IMAGE} ] || [ ${DOCKER_IMAGE} != "centos:7" ]; then # This DOCKER_IMAGE environment variable is set in the build_and_test.yml github workflow. ./test_eckey.sh "$BIN" fi ./test_rsakey.sh "$BIN" echo "********************************************************** " echo " HMAC Keys" echo "********************************************************** " ./test_hmackey.sh "$BIN" echo "********************************************************** " echo " AEAD Keys" echo "********************************************************** " ./test_otpaeadkey.sh "$BIN" echo "********************************************************** " echo " Template" echo "********************************************************** " test "$BIN -p password -a get-pseudo-random --count=512 --out=template.txt" " Generate 512 pseudo random bytes" test_with_resp "$BIN -p password -a put-template -i 0 -l template -d 1 -A template-ssh --in template.txt" " Import template" id=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $id -t template" " Get object info" info=$($BIN -p password -a get-object-info -i $id -t template 2> /dev/null) test "echo $info | grep \"id: $id\"" " Object info contains correct ID" test "echo $info | grep \"type: template\"" " Object info contains correct type" test "echo $info | grep \"algorithm: template-ssh\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"template\"'" " Object info contains correct label" test "echo $info | grep \"domains: 1\"" " Object info contains correct domains" test "echo $info | grep \"origin: imported\"" " Object info contains correct origin" test "$BIN -p password -a get-template -i $id" " Get template" test "$BIN -p password -a delete-object -i $id -t template" " Delete template" rm resp.txt rm template.txt echo "********************************************************** " echo " Wrap Keys" echo "********************************************************** " ./test_wrapkey.sh "$BIN" echo "********************************************************** " echo " List Objects" echo "********************************************************** " test "$BIN -p password -a generate-asymmetric-key -i 100 -l ecKey -d 5,8,13 -c sign-ecdsa,derive-ecdh,sign-attestation-certificate -A ecp224" " Generate EC key for testing" test "$BIN -p password -a list-objects -A any -t any -i 100 | grep \"Found 1 object(s)\"" " List objects by ID" test "$BIN -p password -a list-objects -A any -t asymmetric-key | grep \"Found 1 object(s)\"" " List objects by type" test "$BIN -p password -a list-objects -A any -t any -d 5,8,13 | grep \"Found 2 object(s)\"" " List objects by domain" test "$BIN -p password -a list-objects -A any -t any -c sign-ecdsa,derive-ecdh,sign-attestation-certificate | grep \"Found 2 object(s)\"" " List objects by capabilities" test "$BIN -p password -a list-objects -A ecp224 -t any | grep \"Found 1 object(s)\"" " List objects by algorithm" test "$BIN -p password -a list-objects -A any -t any -l ecKey | grep \"Found 1 object(s)\"" " List objects by label" test "$BIN -p password -a delete-object -i 100 -t asymmetric-key" " Delete key" echo "********************************************************** " echo " Label Size" echo "********************************************************** " # Label 0 chars test "$BIN -p password -a generate-asymmetric-key -i 300 -d 5,8,13 -c sign-ecdsa -A ecp224" " Create key with no label" test "$BIN -p password -a get-object-info -i 300 -t asymmetric-key | grep 'label: \"\"'" " Object info contains empty label" #$BIN -p password -a list-objects -A any -t any -l "" | grep "Found 1 object(s)" # Label 39 chars test "$BIN -p password -a generate-asymmetric-key -i 200 -l abcdefghijklmnopqrstuvwxyz0123456789abc -d 5,8,13 -c sign-ecdsa -A ecp224" " Create object with 39 characters label" test "$BIN -p password -a get-object-info -i 200 -t asymmetric-key | grep 'label: \"abcdefghijklmnopqrstuvwxyz0123456789abc\"'" " Object info contains correct lable with 39 characters" test "$BIN -p password -a list-objects -A any -t any -l abcdefghijklmnopqrstuvwxyz0123456789abc | grep \"Found 1 object(s)\"" " list-objects found object with 39 characters" # Label 40 chars test "$BIN -p password -a generate-asymmetric-key -i 100 -l abcdefghijklmnopqrstuvwxyz0123456789abcd -d 5,8,13 -c sign-ecdsa -A ecp224" " Create object with 40 characters label" test "$BIN -p password -a get-object-info -i 100 -t asymmetric-key | grep 'label: \"abcdefghijklmnopqrstuvwxyz0123456789abcd\"'" " Object info contains correct lable with 40 characters" test "$BIN -p password -a list-objects -A any -t any -l abcdefghijklmnopqrstuvwxyz0123456789abcd | grep \"Found 1 object(s)\"" " list-objects found object with 40 characters" # Label 41 chars (set +e; $BIN -p password -a generate-asymmetric-key -i 400 -l "abcdefghijklmnopqrstuvwxyz0123456789abcde" -d "5,8,13" -c "sign-ecdsa" -A "ecp224"; true) 2>&1 >/dev/null | grep "Failed to generate asymmetric key: Invalid argument to a function" # Label doesn't exist test "$BIN -p password -a list-objects -A any -t any -l doesnotexist | grep \"Found 0 object(s)\"" " List objects by label that does not exist" test "$BIN -p password -a delete-object -i 100 -t asymmetric-key" " Clean up" test "$BIN -p password -a delete-object -i 200 -t asymmetric-key" " Clean up" test "$BIN -p password -a delete-object -i 300 -t asymmetric-key" " Clean up" echo "********************************************************** " echo " Authentication Keys" echo "********************************************************** " test_with_resp "$BIN -p password -a put-authentication-key -i 0 -l authkey -d 1,2,3 -c all --delegated all --new-password foo123" " Create new authentication key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN --authkey $keyid -p foo123 -a get-object-info -i 1 -t authentication-key" " Login using new authetication key" test "$BIN -p password -a delete-object -i $keyid -t authentication-key" " Delete new authentication key" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.7.3/resources/tests/bash/reg.dat0000644000175000017500000000264015167357110020636 0ustar aveenaveenZ355tsD9teEqE1c5Viy90V1J6S9/vFJVofKeCQ2ssvwwgfT7fHp54KPc4fpZKn3Y1ZRdNBkfxFVu7e1bMpL1vCxOsIwtKGnIShx42Te7iVo9oFBzjomisnRmauAx+drsFX2T0HPdQnexo+uZ8cXQ1LfOPfI80fHfnnZ97aC3YYtomxv4ieCqQNzn17pUhP/QBUHvr3huq63+1CQ7P5iHPq4/HzmQmA8zbeYPMgRxX3r7DMF8GphgsJRU/sFJC3IL2XhYVoR/j5WgzG4ugPz2001wefAO3JOe7nryNTrnl+BbD0CcvF5u7i9bfME5pZTnkqsz7o3Wu+kXAb+LGwVyQt1KRtEAAAAcc3NoLXJzYS1jZXJ0LXYwMUBvcGVuc3NoLmNvbQAAACCboUHYTJF015XKlH4MqI+aaPJePR7MbI2teXDYvVKUhAAAAAMBAAEAAAEBAK3EX7uFmuRyX/X3eGz+Mn7EyLn/76taYJzPP4WXd0KftRV2Y0TqAK8qvQUOReMaloQzRqRgxhbnuQP/l8Zz4eXKpE8jEFvlJng+HZbvYCGW3oMOjLBjN1c0zy1zM8tjxw9LAYSXD8vtvaa77owR1Jive5PB4kNQ9zF+UCyukOAeuqcDI43W8XVIjBmxaUOIKQxy5hF6anXdXlUFf/mtD2WM+tmT60hhW1JT9T8l+49et9XywWTJpYDLoz8c6JuBq92aDfR+MKdZM46MR96JKxP1AQpSXSjWktWt3WPnFcVhHHi8D6ZO1VQA2PDOTqOWZq9FY3EFqi1PQDo/2B5QOGkAAAAAAAAAAAAAAAEAAAAPdXNlckB5dWJpY28uY29tAAAACAAAAAR1c2VyAAAAAGd+eIoAAAAAZ38GVgAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCtRLg8mAY0p1CiXxrdTttMMXAI0BAdLMWe4xHbgll2zOSkVWl2z/+Bbb1MNxPOzGrahp6hI8kumeTmq976LY2+6An1grKrvmGHmBP8GmlCKl43hXMsYE+lWrFVoXuZvL6XYe0w09GEdswvVmoHbpARMRY+x03xq/uUNL91J0qYdscndQVpvv0vbRCEq31yBnMXznaj1vhs99SX9SENa6HBwzt6a1ezhPo7bvLbKi5sxAOYJlkgceK0X8Do/v9IUGV0gMRrouky/88SSiKN/8+PGqDUgVFs0Ntq9YcibWVdzGgUQ6G4nKlEIyYDJIn+9NXze6mV1PJ0yJNLYAyVUWBRyubihsm-shell-2.7.3/resources/tests/bash/test_rsakey.sh0000755000175000017500000003534715167357110022275 0ustar aveenaveen#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubihsm-shell command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing and decryption data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo " $2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo " $2 ... OK!" fi set -e } set -e echo "====================== RSA keys ===================== " RSA_KEYSIZE=("2048" "3072" "4096") for k in ${RSA_KEYSIZE[@]}; do echo "**********************************" echo " RSA$k" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-asymmetric-key -i 0 -l rsaKey -d 1 -c sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate -A rsa$k" "Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t asymmetric-key" "Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t asymmetric-key 2> /dev/null) test "echo $info | grep \"id: $keyid\"" "Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" "Object info contains correct type" test "echo $info | grep \"algorithm: rsa$k\"" "Object info contains correct algorithm" test "echo $info | grep 'label: \"rsaKey\"'" "Object info contains correct label" test "echo $info | grep \"domains: 1\"" "Object info contains correct domains" test "echo $info | grep \"origin: generated\"" "Object info contains correct origin" test "echo $info | grep \"capabilities: decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss\"" "Object info contains correct capabilities" test "$BIN -p password -a get-public-key -i $keyid --outformat=PEM --out pubkey_rsa$k.pem" "Get public key" echo "=== Import key:" test "openssl genrsa -out rsa$k-keypair.pem $k" "Generate key with OpenSSL" test_with_resp "$BIN -p password -a put-asymmetric-key -i 0 -l rsaKeyImport -d 2 -c sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate --in=rsa$k-keypair.pem" "Import key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $import_keyid -t asymmetric-key" "Get object info" info=$($BIN -p password -a get-object-info -i $import_keyid -t asymmetric-key 2> /dev/null) test "echo $info | grep \"id: $import_keyid\"" "Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" "Object info contains correct type" test "echo $info | grep \"algorithm: rsa$k\"" "Object info contains correct algorithm" test "echo $info | grep 'label: \"rsaKeyImport\"'" "Object info contains correct label" test "echo $info | grep \"domains: 2\"" "Object info contains correct domains" test "echo $info | grep \"origin: imported\"" "Object info contains correct origin" test "echo $info | grep \"capabilities: decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss\"" "Object info contains correct capabilities" test "$BIN -p password -a get-public-key -i $import_keyid --outformat=PEM --out pubkey_rsa$k.imported.pem" "Get public key" echo "=== Signing with generated key:" test "$BIN -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha1 --in data.txt --outformat binary --out data.$k-pkcs1sha1gen.sig" "Sign with rsa-pkcs1-sha1" test "openssl dgst -sha1 -verify pubkey_rsa$k.pem -signature data.$k-pkcs1sha1gen.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha256 --in data.txt --outformat binary --out data.$k-pkcs1sha256gen.sig" "Sign with rsa-pkcs1-sha256" test "openssl dgst -sha256 -verify pubkey_rsa$k.pem -signature data.$k-pkcs1sha256gen.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha384 --in data.txt --outformat binary --out data.$k-pkcs1sha384gen.sig" "Sign with rsa-pkcs1-sha384" test "openssl dgst -sha384 -verify pubkey_rsa$k.pem -signature data.$k-pkcs1sha384gen.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha512 --in data.txt --outformat binary --out data.$k-pkcs1sha512gen.sig" "Sign with rsa-pkcs1-sha512" test "openssl dgst -sha512 -verify pubkey_rsa$k.pem -signature data.$k-pkcs1sha512gen.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $keyid -A rsa-pss-sha1 --in data.txt --outformat binary --out data.$k-psssha1gen.sig" "Sign with rsa-pss-sha1" test "openssl dgst -sha1 -binary -out data.sha1 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha1 -sigfile data.$k-psssha1gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $keyid -A rsa-pss-sha256 --in data.txt --outformat binary --out data.$k-psssha256gen.sig" "Sign with rsa-pss-sha256" test "openssl dgst -sha256 -binary -out data.sha256 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha256 -sigfile data.$k-psssha256gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $keyid -A rsa-pss-sha384 --in data.txt --outformat binary --out data.$k-psssha384gen.sig" "Sign with rsa-pss-sha384" test "openssl dgst -sha384 -binary -out data.sha384 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha384 -sigfile data.$k-psssha384gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $keyid -A rsa-pss-sha512 --in data.txt --outformat binary --out data.$k-psssha512gen.sig" "Sign with rsa-pss-sha512" test "openssl dgst -sha512 -binary -out data.sha512 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha512 -sigfile data.$k-psssha512gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512" "Verify signature with OpenSSL" echo "=== Signing with imported key:" test "$BIN -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha1 --in data.txt --outformat binary --out data.$k-pkcs1sha1import.sig" "Sign with rsa-pkcs1-sha1" test "openssl dgst -sha1 -verify pubkey_rsa$k.imported.pem -signature data.$k-pkcs1sha1import.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha256 --in data.txt --outformat binary --out data.$k-pkcs1sha256import.sig" "Sign with rsa-pkcs1-sha256" test "openssl dgst -sha256 -verify pubkey_rsa$k.imported.pem -signature data.$k-pkcs1sha256import.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha384 --in data.txt --outformat binary --out data.$k-pkcs1sha384import.sig" "Sign with rsa-pkcs1-sha384" test "openssl dgst -sha384 -verify pubkey_rsa$k.imported.pem -signature data.$k-pkcs1sha384import.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha512 --in data.txt --outformat binary --out data.$k-pkcs1sha512import.sig" "Sign with rsa-pkcs1-sha512" test "openssl dgst -sha512 -verify pubkey_rsa$k.imported.pem -signature data.$k-pkcs1sha512import.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $import_keyid -A rsa-pss-sha1 --in data.txt --outformat binary --out data.$k-psssha1import.sig" "Sign with rsa-pss-sha1" test "openssl dgst -sha1 -binary -out data.sha1 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha1 -sigfile data.$k-psssha1import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $import_keyid -A rsa-pss-sha256 --in data.txt --outformat binary --out data.$k-psssha256import.sig" "Sign with rsa-pss-sha256" test "openssl dgst -sha256 -binary -out data.sha256 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha256 -sigfile data.$k-psssha256import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $import_keyid -A rsa-pss-sha384 --in data.txt --outformat binary --out data.$k-psssha384import.sig" "Sign with rsa-pss-sha384" test "openssl dgst -sha384 -binary -out data.sha384 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha384 -sigfile data.$k-psssha384import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $import_keyid -A rsa-pss-sha512 --in data.txt --outformat binary --out data.$k-psssha512import.sig" "Sign with rsa-pss-sha512" test "openssl dgst -sha512 -binary -out data.sha512 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha512 -sigfile data.$k-psssha512import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512" "Verify signature with OpenSSL" echo "=== Make self signed certificate:" set +e $BIN -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 2>&1 > /dev/null # Some YubiHSMs does not have default attestation certificate def_attestation=$? set -e if [ $def_attestation -eq 0 ]; then test "$BIN -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem" "Sign attestation cert with default key" test "openssl x509 -in cert.pem -out cert.der -outform DER" "Convert cert format" test "$BIN -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der" "Import attestation cert as template cert (same ID as generated key)" test "$BIN -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der" "Import attestation cert as template cert (same ID as imported key)" test "rm cert.der" "Cleaning up" else test "$BIN -p password -a put-opaque -i $keyid -l template_cert_gen -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem" "Import attestation cert as template cert (same ID as generated key)" test "$BIN -p password -a put-opaque -i $import_keyid -l template_cert_imp -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem" "Import attestation cert as template cert (same ID as imported key)" fi test "$BIN -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem" "Sign attestation with same key (aka. get selfsigned cert)" test "$BIN -p password -a delete-object -i $keyid -t opaque" "Delete template cert" test "$BIN -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --informat=PEM --in selfsigned_cert.pem" "Import selfsigned cert with same key ID" test "rm selfsigned_cert.pem" "Cleaning up" #-- Sign attestation certificate test "$BIN -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.pem" "Sign attestation cert with imported key" test "rm selfsigned_cert.pem" "Cleaning up" test "$BIN -p password -a delete-object -i $import_keyid -t opaque" "Delete certificate template" test "$BIN -p password -a delete-object -i $keyid -t opaque" "Delete certificate" echo "=== Decrypt with generated key and PKCS1v15:" test "openssl rsautl -encrypt -inkey pubkey_rsa$k.pem -pubin -in data.txt -out data.enc" "Encryp with OpenSSL" test "$BIN -p password -a decrypt-pkcs1v15 -i $keyid --in data.enc --out data.dec" "Decrypt with yubihsm-shell" test "cmp data.txt data.dec" "Compare decrypted data with plain text data" test "rm data.dec" "Clean up" echo "=== Decrypt with imported key and PKCS1v15:" test "openssl rsautl -encrypt -inkey pubkey_rsa$k.imported.pem -pubin -in data.txt -out data.enc" "Encryp with OpenSSL" test "$BIN -p password -a decrypt-pkcs1v15 -i $import_keyid --in data.enc --out data.dec" "Decrypt with yubihsm-shell" test "cmp data.txt data.dec" "Compare decrypted data with plain text data" test "rm data.dec" "Clean up" echo "=== Make PKCS10 Certificate Signing Request:" test "openssl req -new -key rsa$k-keypair.pem -subj /CN=test -out csr-ossl.pem" "Generate CSR with OpenSSL" test "$BIN -p password -a generate-csr -i $import_keyid -S /CN=test/ --out csr.pem" "Generate CSR with yubihsm-shell" test "openssl req -in csr.pem -verify" "Verify CSR with openssl" test "cmp csr-ossl.pem csr.pem" "Compare CSRs generated with openssl and yubihsm-shell" test "rm csr.pem csr-ossl.pem" "Clean up" echo "=== Clean up:" test "$BIN -p password -a delete-object -i $keyid -t asymmetric-key" "Delete generated key" test "$BIN -p password -a delete-object -i $import_keyid -t asymmetric-key" "Delete imported key" done echo "****************************************************" echo " Compress X509 Certificate" echo "****************************************************" openssl req -x509 -newkey rsa:4096 -out too_large_cert.pem -sha256 -days 3650 -nodes -subj '/C=01/ST=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/L=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/O=0123456789012345678901234567890123456789012345678901234567890123/OU=0123456789012345678901234567890123456789012345678901234567890123/CN=0123456789012345678901234567890123456789012345678901234567890123/CN=0123456789012345678901234567890123456789012345678901234567890123' > /dev/null 2>&1 test "$BIN -p password -a put-opaque -i 100 -l too_large_cert -A opaque-x509-certificate --with-compression --in too_large_cert.pem --informat PEM" "Import compressed X509 certificate" test "$BIN -p password -a get-opaque -i 100 --outformat=PEM --out too_large_cert_out.pem" "Read the large certificate from device" test "cmp too_large_cert.pem too_large_cert_out.pem" "Compare read certificate with the one imported" test "$BIN -p password -a delete-object -i 100 -t opaque" "Delete certificate" cd .. rm -rf yubihsm-shell_test_dir set +e set +xyubihsm-shell-2.7.3/resources/tests/bash/test_wrapkey.sh0000755000175000017500000005677215167357110022466 0ustar aveenaveen#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } cmp_str_content () { set +e if [[ $1 == *"$2"* ]]; then echo " $3 in object info ... OK!" else echo "Wrong $3" echo $1 exit 1 fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e test "$BIN -p password -a reset" " Reset device" sleep 3 eckey=100 aeskey=200 test "$BIN -p password -a generate-asymmetric-key -i $eckey -l eckey -d 1 -c exportable-under-wrap,sign-ecdsa -A ecp224" " Generate EC Key to wrap" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 0" "Sequence" cmp_str_content "$info" "origin: generated" "Origin" echo "**********************************" echo " aes128-ccm-wrap" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-wrap-key -i 0 -l wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap -A aes128-ccm-wrap" " Generate wrap key" keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes128-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 24" "Length" echo "=== Import key" test_with_resp "$BIN -p password -a get-pseudo-random --count 16" " Get random 16 bytes" wrapkey=$(tail -1 resp.txt | awk '{print $0}') test_with_resp "$BIN -p password -a put-wrap-key -i 0 -l imported_wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap --in=$wrapkey" " Import wrap key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $import_keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes128-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 24" "Length" cmp_str_content "$info" "origin: imported" "Origin" echo "=== Wrap and unwrap objects with generated wrap key" test "$BIN -p password -a get-wrapped --wrap-id $keyid -i 100 -t asymmetric-key --out key.gen_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $keyid --in key.gen_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 1" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Wrap and unwrap objects with imported wrap key" test "$BIN -p password -a get-wrapped --wrap-id $import_keyid -i 100 -t asymmetric-key --out key.imp_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $import_keyid --in key.imp_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 2" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Clean up" test "$BIN -p password -a delete-object -i $keyid -t wrap-key" " Delete generated wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t wrap-key" " Delete imported wrap key" rm key.gen_wrapped rm key.imp_wrapped echo "**********************************" echo " aes192-ccm-wrap" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-wrap-key -i 0 -l wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap -A aes192-ccm-wrap" " Generate wrap key" keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes192-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 32" "Length" echo "=== Import key" test_with_resp "$BIN -p password -a get-pseudo-random --count 24" " Get random 16 bytes" wrapkey=$(tail -1 resp.txt | awk '{print $0}') test_with_resp "$BIN -p password -a put-wrap-key -i 0 -l imported_wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap --in=$wrapkey" " Import wrap key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $import_keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes192-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 32" "Length" cmp_str_content "$info" "origin: imported" "Origin" echo "=== Wrap and unwrap objects with generated wrap key" test "$BIN -p password -a get-wrapped --wrap-id $keyid -i 100 -t asymmetric-key --out key.gen_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $keyid --in key.gen_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 3" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Wrap and unwrap objects with imported wrap key" test "$BIN -p password -a get-wrapped --wrap-id $import_keyid -i 100 -t asymmetric-key --out key.imp_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $import_keyid --in key.imp_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 4" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Clean up" test "$BIN -p password -a delete-object -i $keyid -t wrap-key" " Delete generated wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t wrap-key" " Delete imported wrap key" rm key.gen_wrapped rm key.imp_wrapped echo "**********************************" echo " aes256-ccm-wrap" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-wrap-key -i 0 -l wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap -A aes256-ccm-wrap" " Generate wrap key" keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes256-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 40" "Length" echo "=== Import key" test_with_resp "$BIN -p password -a get-pseudo-random --count 32" " Get random 16 bytes" wrapkey=$(tail -1 resp.txt | awk '{print $0}') test_with_resp "$BIN -p password -a put-wrap-key -i 0 -l imported_wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap --in=$wrapkey" " Import wrap key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $import_keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes256-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 40" "Length" cmp_str_content "$info" "origin: imported" "Origin" echo "=== Wrap and unwrap objects with generated wrap key" test "$BIN -p password -a get-wrapped --wrap-id $keyid -i 100 -t asymmetric-key --out key.gen_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $keyid --in key.gen_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 5" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Wrap and unwrap objects with imported wrap key" test "$BIN -p password -a get-wrapped --wrap-id $import_keyid -i 100 -t asymmetric-key --out key.imp_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $import_keyid --in key.imp_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 6" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Clean up" test "$BIN -p password -a delete-object -i $keyid -t wrap-key" " Delete generated wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t wrap-key" " Delete imported wrap key" rm key.gen_wrapped rm key.imp_wrapped device_info=$($BIN -p password -a get-device-info 2> /dev/null) if [[ "$device_info" != *"aes-kwp"* ]]; then test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" exit 0 fi aes_enabled=false if [[ "$device_info" == *"aes-cbc"* ]]; then aes_enabled=true test "$BIN -p password -a generate-symmetric-key -i $aeskey -l aeskey -d 1 -c exportable-under-wrap,encrypt-cbc,decrypt-cbc -A aes128" " Generate AES Key to wrap" test_with_resp "$BIN -p password -a get-pseudo-random --count 16" " Get random 16 bytes for IV" iv=$(tail -1 resp.txt | awk '{print $0}') test_with_resp "$BIN -p password -a get-pseudo-random --count 32" " Get random 32 bytes to test encryption" data=$(tail -1 resp.txt | awk '{print $0}') fi RSA_KEYSIZE=("2048" "3072" "4096") seq_ec=6 seq_aes=0 for k in ${RSA_KEYSIZE[@]}; do echo "**********************************" echo " RSA$k" echo "**********************************" echo "=== Generate RSA wrap keys" test_with_resp "$BIN -p password -a generate-wrap-key -i 0 -l wrapkey -c import-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc -A rsa$k" " Generate RSA wrap key" keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: rsa$k" "Algorithm" cmp_str_content "$info" "origin: generated" "Origin" test "$BIN -p password -a get-public-key -i $keyid -t wrap-key --out public_wrapkey.pem" " Export rsa public wrap key" test "$BIN -p password -a put-public-wrapkey -i $keyid -c export-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in public_wrapkey.pem" " Import RSA public wrap key" rm public_wrapkey.pem echo "=== Wrap and unwrap EC object with generated RSA wrap key" test "$BIN -p password -a get-rsa-wrapped --wrap-id $keyid -i $eckey -t asymmetric-key --out rsawrapped.object" " Export wrapped EC object" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-rsa-wrapped --wrap-id $keyid --in rsawrapped.object" " Import wrapped EC object" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) seq_ec=$((seq_ec+1)) cmp_str_content "$info" "sequence: $seq_ec" "Sequence" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" rm rsawrapped.object echo "=== Wrap and unwrap EC key material with generated RSA wrap key" test "$BIN -p password -a get-rsa-wrapped-key --wrap-id $keyid -i $eckey -t asymmetric-key --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --out rsawrapped.key" " Export wrapped EC key material" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-rsa-wrapped-key --wrap-id $keyid -i $eckey -t asymmetric-key -A ecp224 -c exportable-under-wrap,sign-ecdsa --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --in rsawrapped.key" " Import wrapped EC key material" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) seq_ec=$((seq_ec+1)) cmp_str_content "$info" "sequence: $seq_ec" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" rm rsawrapped.key if [[ "$aes_enabled" = true ]]; then echo "=== Wrap and unwrap AES object with generated RSA wrap key" test "$BIN -p password -a get-rsa-wrapped --wrap-id $keyid -i $aeskey -t symmetric-key --out rsawrapped.object" " Export wrapped AES object" test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" test "$BIN -p password -a put-rsa-wrapped --wrap-id $keyid --in rsawrapped.object" " Import wrapped AES object" info=$($BIN -p password -a get-object-info -i $aeskey -t symmetric-key 2> /dev/null) seq_aes=$((seq_aes+1)) cmp_str_content "$info" "sequence: $seq_aes" "Sequence" cmp_str_content "$info" "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" "Capabilities" test "$BIN -p password -a encrypt-aescbc -i $aeskey --iv $iv --in $data --out data.enc" " Perform encryption with imported wrapped AES key" test_with_resp "$BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc" " Perform decryption with imported wrapped AES key" data_dec=$(tail -1 resp.txt | awk '{print $0}') if [[ "$data" == "$data_dec" ]]; then echo " Compare decrypted data to plain text ... OK!" else $BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc --out data.dec exit fi rm rsawrapped.object rm data.enc echo "=== Wrap and unwrap AES key material with generated RSA wrap key" test "$BIN -p password -a get-rsa-wrapped-key --wrap-id $keyid -i $aeskey -t symmetric-key --oaep rsa-oaep-sha384 --mgf1 mgf1-sha1 --out rsawrapped.key" " Export wrapped AES key material" test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" test "$BIN -p password -a put-rsa-wrapped-key --wrap-id $keyid -i $aeskey -t symmetric-key -A aes128 -c exportable-under-wrap,decrypt-cbc,encrypt-cbc --oaep rsa-oaep-sha384 --mgf1 mgf1-sha1 --in rsawrapped.key" " Import wrapped AES key material" info=$($BIN -p password -a get-object-info -i $aeskey -t symmetric-key 2> /dev/null) seq_aes=$((seq_aes+1)) cmp_str_content "$info" "sequence: $seq_aes" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" test "$BIN -p password -a encrypt-aescbc -i $aeskey --iv $iv --in $data --out data.enc" " Perform encryption with imported wrapped AES key" test_with_resp "$BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc" " Perform decryption with imported wrapped AES key" data_dec=$(tail -1 resp.txt | awk '{print $0}') if [[ "$data" == "$data_dec" ]]; then echo " Compare decrypted data to plain text ... OK!" else $BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc --out data.dec exit fi rm rsawrapped.key rm data.enc fi echo "=== Import RSA wrap keys" test "openssl genrsa -out keypair.pem $k" " Generate RSA key with OpenSSL" test "openssl rsa -in keypair.pem -pubout -out key.pub" " Extract public key from OpenSSL generated keypair" test_with_resp "$BIN -p password -a put-rsa-wrapkey -i 0 -d 1 -c import-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in keypair.pem" " Import RSA wrap key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $import_keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: rsa$k" "Algorithm" cmp_str_content "$info" "origin: imported" "Origin" test "$BIN -p password -a put-public-wrapkey -i $import_keyid -c export-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in key.pub" " Import RSA public wrap key" rm keypair.pem rm key.pub echo "=== Wrap and unwrap EC object with imported RSA wrap key" test "$BIN -p password -a get-rsa-wrapped --wrap-id $import_keyid -i $eckey -t asymmetric-key --out rsawrapped.object" " Export wrapped EC object" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-rsa-wrapped --wrap-id $import_keyid --in rsawrapped.object" " Import wrapped EC object" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) seq_ec=$((seq_ec+1)) cmp_str_content "$info" "sequence: $seq_ec" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" rm rsawrapped.object echo "=== Wrap and unwrap EC key material with imported RSA wrap key" test "$BIN -p password -a get-rsa-wrapped-key --wrap-id $import_keyid -i $eckey -t asymmetric-key --oaep rsa-oaep-sha512 --mgf1 mgf1-sha512 --out rsawrapped.key" " Export wrapped EC key material" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-rsa-wrapped-key --wrap-id $import_keyid -i $eckey -t asymmetric-key -A ecp224 -c exportable-under-wrap,sign-ecdsa --oaep rsa-oaep-sha512 --mgf1 mgf1-sha512 --in rsawrapped.key" " Import wrapped EC key material" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) seq_ec=$((seq_ec+1)) cmp_str_content "$info" "sequence: $seq_ec" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" rm rsawrapped.key if [[ "$aes_enabled" = true ]]; then echo "=== Wrap and unwrap AES object with imported RSA wrap key" test "$BIN -p password -a get-rsa-wrapped --wrap-id $import_keyid -i $aeskey -t symmetric-key --out rsawrapped.object" " Export wrapped AES object" test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" test "$BIN -p password -a put-rsa-wrapped --wrap-id $import_keyid --in rsawrapped.object" " Import wrapped AES object" info=$($BIN -p password -a get-object-info -i $aeskey -t symmetric-key 2> /dev/null) seq_aes=$((seq_aes+1)) cmp_str_content "$info" "sequence: $seq_aes" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" "Capabilities" test "$BIN -p password -a encrypt-aescbc -i $aeskey --iv $iv --in $data --out data.enc" " Perform encryption with imported wrapped AES key" test_with_resp "$BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc" " Perform decryption with imported wrapped AES key" data_dec=$(tail -1 resp.txt | awk '{print $0}') if [[ "$data" == "$data_dec" ]]; then echo " Compare decrypted data to plain text ... OK!" else $BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc --out data.dec exit fi rm rsawrapped.object rm data.enc echo "=== Wrap and unwrap AES key material with imported RSA wrap key" test "$BIN -p password -a get-rsa-wrapped-key --wrap-id $import_keyid -i $aeskey -t symmetric-key --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --out rsawrapped.key" " Export wrapped AES key material" test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" test "$BIN -p password -a put-rsa-wrapped-key --wrap-id $import_keyid -i $aeskey -t symmetric-key -A aes128 -c exportable-under-wrap,decrypt-cbc,encrypt-cbc --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --in rsawrapped.key" " Import wrapped AES key material" info=$($BIN -p password -a get-object-info -i $aeskey -t symmetric-key 2> /dev/null) seq_aes=$((seq_aes+1)) cmp_str_content "$info" "sequence: $seq_aes" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" test "$BIN -p password -a encrypt-aescbc -i $aeskey --iv $iv --in $data --out data.enc" " Perform encryption with imported wrapped AES key" test_with_resp "$BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc" " Perform decryption with imported wrapped AES key" data_dec=$(tail -1 resp.txt | awk '{print $0}') if [[ "$data" == "$data_dec" ]]; then echo " Compare decrypted data to plain text ... OK!" else $BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc --out data.dec exit fi rm rsawrapped.key rm data.enc fi echo "=== Clean up" test "$BIN -p password -a delete-object -i $keyid -t wrap-key" " Delete generated RSA wrap key" test "$BIN -p password -a delete-object -i $keyid -t public-wrap-key" " Delete generated RSA public wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t wrap-key" " Delete imported RSA wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t public-wrap-key" " Delete imported RSA public wrap key" done #test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" #if [[ "$aes_enabled" = true ]]; then # test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" #fi test "$BIN -p password -a reset" " Reset device" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.7.3/resources/tests/bash/test_otpaeadkey.sh0000755000175000017500000000646615167357110023125 0ustar aveenaveen#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e echo "====================== AEAD keys ===================== " echo "------------- AEAD Key 128" test_with_resp "$BIN -p password -a generate-otp-aead-key -i 0 -l aeadkey -d 1,2,3 -c randomize-otp-aead -A aes128-yubico-otp --nonce 0x01020304" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $5}') test "$BIN -p password -a get-object-info -i $keyid -t otp-aead-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t otp-aead-key 2> /dev/null) test "echo $info | grep \"id: $keyid\"" " Object info contains correct ID" test "echo $info | grep \"type: otp-aead-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: aes128-yubico-otp\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"aeadkey\"'" " Object info contains correct label" test "echo $info | grep \"domains: 1:2:3\"" " Object info contains correct domains" test "echo $info | grep \"origin: generated\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: randomize-otp-aead\"" " Object info contains correct capabilities" test "$BIN -p password -a randomize-otp-aead -i $keyid" " Randomize OTP AEAD" test "$BIN -p password -a delete-object -i $keyid -t otp-aead-key" " Delete key" echo "------------- AEAD Key 128" test_with_resp "$BIN -p password -a generate-otp-aead-key -i 0 -l aeadkey -d 1,2,3 -c randomize-otp-aead -A aes192-yubico-otp --nonce 0x01020304" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $5}') test "$BIN -p password -a get-object-info -i $keyid -t otp-aead-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t otp-aead-key 2> /dev/null) test "echo $info | grep \"algorithm: aes192-yubico-otp\"" " Object info contains correct algorithm" test "$BIN -p password -a randomize-otp-aead -i $keyid" " Randomize OTP AEAD" test "$BIN -p password -a delete-object -i $keyid -t otp-aead-key" " Delete key" echo "------------- AEAD Key 256" test_with_resp "$BIN -p password -a generate-otp-aead-key -i 0 -l aeadkey -d 1,2,3 -c randomize-otp-aead -A aes256-yubico-otp --nonce 0x01020304" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $5}') test "$BIN -p password -a get-object-info -i $keyid -t otp-aead-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t otp-aead-key 2> /dev/null) test "echo $info | grep \"algorithm: aes256-yubico-otp\"" " Object info contains correct algorithm" test "$BIN -p password -a randomize-otp-aead -i $keyid" " Randomize OTP AEAD" test "$BIN -p password -a delete-object -i $keyid -t otp-aead-key" " Delete key" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.7.3/resources/tests/bash/opensc_test.bats0000644000175000017500000005774615167357110022611 0ustar aveenaveenload 'test_helper/bats-support/load' load 'test_helper/bats-assert/load' setup_file() { echo "--- Configuration via Environment Variables ---" >&3 echo "MODULE: Path to the PKCS#11 module, default /usr/local/lib/yubihsm_pkcs11.so (Linux) or /usr/local/lib/yubihsm_pkcs11.dylib (Mac)" >&3 echo "EDIT_PATH: (Windows/Msys only) Path to directory where pkcs11-tool.exe and libyubihsm is located if not in default locations. Use delimiter ":". Example: export EDIT_PATH='C:\Path\To\OpenSC\tools:C:\Path\To\YubiHSM Shell\bin" >&3 echo "CONFIG_FILE: Path to the yubihsm_pkcs11 configuration file, default is in current directory" >&3 echo "-----------------------------------------------" >&3 echo "" >&3 export EC_CURVES="secp224r1 secp256r1 secp384r1 secp521r1 secp256k1" export pkcs11="pkcs11-tool" export RSA_LENGTHS="2048 3072 4096" export YUBIHSM_PKCS11_CONF=${CONFIG_FILE:-"$(pwd)/yubihsm_pkcs11.conf"} local default_module_path="/usr/local/lib/yubihsm_pkcs11.dylib" #Default path for Mac os=$(uname -o) if ! { [[ "$os" == "Linux" ]] && grep -q 'Fedora' /etc/os-release 2>/dev/null; }; then EC_CURVES="$EC_CURVES brainpoolP256r1 brainpoolP384r1 brainpoolP512r1" fi if [[ "$os" == "Msys" ]]; then echo "This script expects that the pkcs11-tool from OpenSC is installed under "C:\Program Files\OpenSC Project\OpenSC\tools" and that libyubihsm.dll is installed under "C:\Program Files\Yubico\YubiHSM Shell\bin" " echo "If that is not the case, please point to the correct locations via the environment variable EDIT_PATH" pkcs11="pkcs11-tool.exe" default_module_path="C:\Program Files\Yubico\YubiHSM Shell\bin\pkcs11\yubihsm_pkcs11.dll" export MSYS2_ARG_CONV_EXCL=* if ! [ -z "$EDIT_PATH" ]; then export PATH="$PATH:"$EDIT_PATH"" else # Adds pkcs11-tool and yubihsm-shell to PATH export PATH="$PATH:C:\Program Files\OpenSC Project\OpenSC\tools:C:\Program Files\Yubico\YubiHSM Shell\bin" fi elif [[ "$os" == "GNU/LINUX" ]]; then default_module_path="/usr/local/lib/yubihsm_pkcs11.so" fi export MODULE=${MODULE:-$default_module_path} echo "--------------------------------" >&3 echo "Variables Check:" >&3 echo "Using module: "$MODULE"" >&3 echo "Using pkcs11: "$pkcs11"" >&3 echo "EC Curves to test: "$EC_CURVES"" >&3 echo "RSA Lengths to test: "$RSA_LENGTHS"" >&3 echo "--------------------------------" >&3 echo "These tests will reset your HSM" >&3 echo "Press Enter to continue or Ctrl-C + enter to abort" >&3 read -p "" if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo "test signing data" > data.txt } @test "EC Curve tests" { for curve in $EC_CURVES; do echo "Testing curve: "$curve"" >&3 #Generate key run "$pkcs11" --module "$MODULE" --login --pin 0001password --keypairgen --id 1 --key-type EC:"$curve" assert_success "Generate EC key with curve $curve" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 1 --type pubkey --output-file pubkey.der assert_success "Get public key of generated key" #Sign with generated key run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m ECDSA-SHA1 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with generated key and ECDSA-SHA1" run openssl dgst -sha1 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m ECDSA-SHA256 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with generated key and ECDSA-SHA256" run openssl dgst -sha256 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m ECDSA-SHA384 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with generated key and ECDSA-SHA384" run openssl dgst -sha384 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m ECDSA-SHA512 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with generated key and ECDSA-SHA512" run openssl dgst -sha512 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" #Import key run openssl ecparam -name "$curve" -genkey -noout -out keypair.pem assert_success "Generate keypair with curve "$curve" using openssl" run "$pkcs11" --module "$MODULE" --login --pin 0001password --write-object keypair.pem --id 2 --type privkey --usage-sign assert_success "Import EC key with curve "$curve"" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 2 --type pubkey --output-file pubkey_imported.der assert_success "Get public key of imported key" #Sign with imported key run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m ECDSA-SHA1 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with imported key and ECDSA-SHA1" run openssl dgst -sha1 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m ECDSA-SHA256 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with imported key and ECDSA-SHA256" run openssl dgst -sha256 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m ECDSA-SHA384 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with imported key and ECDSA-SHA384" run openssl dgst -sha384 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m ECDSA-SHA512 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with imported key and ECDSA-SHA512" run openssl dgst -sha512 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" #Derive ECDH run "$pkcs11" --module "$MODULE" --login --pin 0001password --derive --id 1 --input-file pubkey_imported.der --output-file ecdh_pkcs11.bin assert_success "Derive ECDH usin pkcs11-tool" run openssl pkeyutl -derive -inkey keypair.pem -peerkey pubkey.der -out ecdh_openssl.bin assert_success "Derive ECDH using openssl" run cmp ecdh_pkcs11.bin ecdh_openssl.bin assert_success "Compare the derived ECDH keys" run rm ecdh_pkcs11.bin ecdh_openssl.bin assert_success "Delete ECDH keys" # Requires writable session? yubihs-pkcs11 only allowed regular users #run "$pkcs11" --module ""$MODULE"" --login --pin 0001password --test-ec --id 200 --key-type EC:secp256r1 # assert_success "Test EC key with yubihs-pkcs11" #Delete keys run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 1 --type privkey assert_success "Delete generated key" run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 2 --type privkey assert_success "Delete imported key" done } @test "RSA Key tests" { run openssl dgst -sha1 -binary -out data.sha1 data.txt assert_success "Hash data with SHA1 and OpenSSL" run openssl dgst -sha256 -binary -out data.sha256 data.txt assert_success "Hash data with SHA256 and OpenSSL" run openssl dgst -sha384 -binary -out data.sha384 data.txt assert_success "Hash data with SHA384 and OpenSSL" run openssl dgst -sha512 -binary -out data.sha512 data.txt assert_success "Hash data with SHA512 and OpenSSL" for length in $RSA_LENGTHS; do echo "Testing RSA key with length: "$length"" >&3 #Generate key run "$pkcs11" --module "$MODULE" --login --pin 0001password --keypairgen --id 1 --key-type rsa:"$length" --usage-sign --usage-decrypt assert_success "Generate RSA key with length "$length"" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 1 --type pubkey --output-file pubkey.der assert_success "Get public key of generated key" #Sign with generated key and RSA-PKCS run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA1-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with generated key and SHA1-RSA-PKCS" run openssl dgst -sha1 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA256-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with generated key and SHA256-RSA-PKCS" run openssl dgst -sha256 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA384-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with generated key and SHA384-RSA-PKCS" run openssl dgst -sha384 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA512-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with generated key and SHA512-RSA-PKCS" run openssl dgst -sha512 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" #Sign with generated key and RSA-PSS run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA1-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with generated key and SHA1-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA256-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with generated key and SHA256-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha256 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA384-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with generated key and SHA384-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha384 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA512-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with generated key and SHA512-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha512 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512 assert_success "Verify signature with openssl" #Decrypt with generated key and PKCS1v15 run openssl rsautl -encrypt -inkey pubkey.der -pubin -in data.txt -out data.enc assert_success "Encrypt with openssl using PKCS1v15" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key" run cmp data.dec data.txt assert_success "Compare decrypted data with plain text data" run rm data.enc data.dec assert_success "Delete test data" #Decrypt with generated key and OAEP run openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA1" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA-1 --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key with SHA1" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA1" run rm data.enc data.dec assert_success "Delete test data for SHA1" run openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA256" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA256 --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key with SHA256" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA256" run rm data.enc data.dec assert_success "Delete test data for SHA256" run openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA384" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA384 --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key with SHA384" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA384" run rm data.enc data.dec assert_success "Delete test data for SHA384" run openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA512" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA512 --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key with SHA512" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA512" run rm data.enc data.dec assert_success "Delete test data for SHA512" #Import key run openssl genrsa -out keypair.pem "$length" assert_success "Generate key with openssl" run "$pkcs11" --module "$MODULE" --login --pin 0001password --write-object keypair.pem --id 2 --type privkey --usage-sign --usage-decrypt assert_success "Import RSA"$length" key" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 2 --type pubkey --output-file pubkey_imported.der assert_success "Get public key of imported key" # Sign with imported key and PKCS run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA1-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with imported key and SHA1-RSA-PKCS" run openssl dgst -sha1 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA256-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with imported key and SHA256-RSA-PKCS" run openssl dgst -sha256 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA384-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with imported key and SHA384-RSA-PKCS" run openssl dgst -sha384 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify sgnature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA512-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with imported key and SHA512-RSA-PKCS" run openssl dgst -sha512 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" # Sign with imported key and RSA-PSS run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA1-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with imported key and SHA1-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA256-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with imported key and SHA256-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha256 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA384-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with imported key and SHA384-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha384 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA512-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with imported key and SHA512-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha512 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512 assert_success "Verify signature with openssl" # Decrypt with imported key and PKCS1v15 run openssl rsautl -encrypt -inkey pubkey_imported.der -pubin -in data.txt -out data.enc assert_success "Encryp with openssl using PKCS1v15" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key" run cmp data.dec data.txt assert_success "Compare decrypted data with plain text data" run rm data.enc data.dec assert_success "Delete test data" # Decrypt with imported key and OAEP run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc assert_success "Encrypt with openssl using OAEP and SHA1" run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA1" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA-1 --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key with SHA1" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA1" run rm data.enc data.dec assert_success "Delete test data for SHA1" run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA256" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA256 --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key with SHA256" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA256" run rm data.enc data.dec assert_success "Delete test data for SHA256" run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA384" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA384 --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key with SHA384" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA384" run rm data.enc data.dec assert_success "Delete test data for SHA384" run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA512" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA512 --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key with SHA512" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA512" run rm data.enc data.dec assert_success "Delete test data for SHA512" #Delete keys run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 1 --type privkey assert_success "Delete generated key" run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 2 --type privkey assert_success "Delete generated key" done run rm data.sha1 data.sha256 data.sha384 data.sha512 data.sig data.txt assert_success "Delete test data" run rm keypair.pem pubkey.der pubkey_imported.der assert_success "Delete key files" } @test "Compress x509 Certificate" { run openssl req -x509 -newkey rsa:4096 -out too_large_cert.der -outform DER -sha256 -days 3650 -nodes -subj '/C=01/ST=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/L=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/O=0123456789012345678901234567890123456789012345678901234567890123/OU=0123456789012345678901234567890123456789012345678901234567890123' > /dev/null 2>&1 assert_success "Generating a large certificate" run "$pkcs11" --module "$MODULE" --login --pin 0001password --write-object too_large_cert.der --id 6464 --type cert assert_success "Import large x509 certificate" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 6464 --type cert --output-file too_large_cert_out.der assert_success "Get imported certificate" run cmp too_large_cert.der too_large_cert_out.der assert_success "Compare read certificate with the one imported" run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 6464 --type cert assert_success "Delete certificate" run rm too_large_cert.der too_large_cert_out.der privkey.pem assert_success "Delete files" } yubihsm-shell-2.7.3/resources/tests/bash/test_eckey.sh0000755000175000017500000002303215167357110022063 0ustar aveenaveen#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e EC_ALGOS=("ecp224" "ecp256" "ecp384" "ecp521" "eck256") EC_CURVES=("secp224r1" "secp256r1" "secp384r1" "secp521r1" "secp256k1") set +e cat /etc/os-release | grep 'Fedora' is_fedora=$? set -e echo "====================== EC keys ===================== " if [ $is_fedora -ne 0 ]; then EC_ALGOS=(${EC_ALGOS[@]} "ecbp256" "ecbp384" "ecbp512") EC_CURVES=(${EC_CURVES[@]} "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1") fi genkey=100 import_key=200 for i in "${!EC_ALGOS[@]}"; do algo=${EC_ALGOS[i]} curve=${EC_CURVES[i]} echo "**********************************" echo " $algo" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-asymmetric-key -i $genkey -l \"ecKey\" -d 5,8,13 -c sign-ecdsa,derive-ecdh,sign-attestation-certificate -A $algo" " Generate key" test "$BIN -p password -a get-object-info -i $genkey -t asymmetric-key" " get-object-info" info=$($BIN -p password -a get-object-info -i $genkey -t asymmetric-key 2> /dev/null) test "echo $info | grep \"id: $genkey\"" " Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: $algo\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"ecKey\"'" " Object info contains correct label" test "echo $info | grep \"domains: 5:8:13\"" " Object info contains correct domains" test "echo $info | grep \"origin: generated\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: derive-ecdh:sign-attestation-certificate:sign-ecdsa\"" " Object info contains correct capabilities" test "$BIN -p password -a get-public-key -i $genkey --outformat=PEM --out $algo-gen.pubkey" " Get public key" echo "=== Import Key" test "openssl ecparam -genkey -name $curve -noout -out $curve-keypair.pem" " Generate key with OpenSSL" test_with_resp "$BIN -p password -a put-asymmetric-key -i $import_key -l "ecKeyImport" -d "2,6,7" -c "sign-ecdsa,sign-attestation-certificate" --in=$curve-keypair.pem" " Import key" test "$BIN -p password -a get-object-info -i $import_key -t asymmetric-key" " get-object-info" info=$($BIN -p password -a get-object-info -i $import_key -t asymmetric-key 2> /dev/null) test "echo $info | grep \"id: $import_key\"" " Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: $algo\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"ecKeyImport\"'" " Object info contains correct label" test "echo $info | grep \"domains: 2:6:7\"" " Object info contains correct domains" test "echo $info | grep \"origin: imported\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: sign-attestation-certificate:sign-ecdsa\"" " Object info contains correct capabilities" test "$BIN -p password -a get-public-key -i $import_key --outformat=PEM --out $algo-import.pubkey" " Get public key" echo "=== Signing" test "$BIN -p password -a sign-ecdsa -i $genkey -A ecdsa-sha1 --in data.txt --outformat=PEM --out data.$algo-sha1gen.sig" " Sign with generated key and ecdsa-sha1" test "openssl dgst -sha1 -verify $algo-gen.pubkey -signature data.$algo-sha1gen.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $genkey -A ecdsa-sha256 --in data.txt --outformat=PEM --out data.$algo-sha256gen.sig" " Sign with generated key and ecdsa-sha256" test "openssl dgst -sha256 -verify $algo-gen.pubkey -signature data.$algo-sha256gen.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $genkey -A ecdsa-sha384 --in data.txt --outformat=PEM --out data.$algo-sha384gen.sig" " Sign with generated key and ecdsa-sha384" test "openssl dgst -sha384 -verify $algo-gen.pubkey -signature data.$algo-sha384gen.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $genkey -A ecdsa-sha512 --in data.txt --outformat=PEM --out data.$algo-sha512gen.sig" " Sign with generated key and ecdsa-sha512" test "openssl dgst -sha512 -verify $algo-gen.pubkey -signature data.$algo-sha512gen.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $import_key -A ecdsa-sha1 --in data.txt --outformat=PEM --out data.$algo-sha1import.sig" " Sign with imported key and ecdsa-sha1" test "openssl dgst -sha1 -verify $algo-import.pubkey -signature data.$algo-sha1import.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $import_key -A ecdsa-sha256 --in data.txt --outformat=PEM --out data.$algo-sha256import.sig" " Sign with imported key and ecdsa-sha256" test "openssl dgst -sha256 -verify $algo-import.pubkey -signature data.$algo-sha256import.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $import_key -A ecdsa-sha384 --in data.txt --outformat=PEM --out data.$algo-sha384import.sig" " Sign with imported key and ecdsa-sha384" test "openssl dgst -sha384 -verify $algo-import.pubkey -signature data.$algo-sha384import.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $import_key -A ecdsa-sha512 --in data.txt --outformat=PEM --out data.$algo-sha512import.sig" " Sign with imported key and ecdsa-sha512" test "openssl dgst -sha512 -verify $algo-import.pubkey -signature data.$algo-sha512import.sig data.txt" " Verify signature with OpenSSL" echo "=== Get attestation certificate and a selfsigned certificate" set +e $BIN -p password -a sign-attestation-certificate -i $genkey --attestation-id 0 2>&1 > /dev/null # Some YubiHSMs does not have default attestation certificate def_attestation=$? set -e if [ $def_attestation -eq 0 ]; then test "$BIN -p password -a sign-attestation-certificate -i $genkey --attestation-id 0 --out cert.pem" " Sign attestation cert with default key" test "openssl x509 -in cert.pem -out cert.der -outform DER" " Convert cert format" test "$BIN -p password -a put-opaque -i $genkey -l template_cert -A opaque-x509-certificate --in cert.der" " Import attestation cert as template cert (same ID as generated key)" test "$BIN -p password -a put-opaque -i $import_key -l template_cert -A opaque-x509-certificate --in cert.der" " Import attestation cert as template cert (same ID as imported key)" test "rm cert.der" " Cleaning up" else test "$BIN -p password -a put-opaque -i $genkey -l template_cert_gen -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem" " Import attestation cert as template cert (same ID as generated key)" test "$BIN -p password -a put-opaque -i $import_key -l template_cert_imp -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem" " Import attestation cert as template cert (same ID as imported key)" fi test "$BIN -p password -a sign-attestation-certificate -i $genkey --attestation-id=$genkey --out selfsigned_cert.pem" " Sign attestation with same key (aka. get selfsigned cert)" test "$BIN -p password -a delete-object -i $genkey -t opaque" " Delete template cert" test "$BIN -p password -a put-opaque -i $genkey -l java_cert -A opaque-x509-certificate --informat=PEM --in selfsigned_cert.pem" " Import selfsigned cert with same key ID" test "rm selfsigned_cert.pem" " Cleaning up" #-- Sign attestation certificate test "$BIN -p password -a sign-attestation-certificate -i $genkey --attestation-id=$import_key --out selfsigned_cert.pem" " Sign attestation cert with imported key" test "$BIN -p password -a delete-object -i $genkey -t opaque" " Delete template cert" test "$BIN -p password -a delete-object -i $import_key -t opaque" " Delete template cert" test "rm selfsigned_cert.pem" " Cleaning up" echo "=== Derive ECDH:" test "openssl ec -in $curve-keypair.pem -pubout -out $curve-pubkey.pem" " Get imported key public key with OpenSSL" test "$BIN -p password -a derive-ecdh -i $genkey --in $curve-pubkey.pem --outformat binary --out $algo-ecdh-shell.key" " Derive ECDH using yubihsm-shell" test "openssl pkeyutl -derive -inkey $curve-keypair.pem -peerkey $algo-gen.pubkey -out $algo-ecdh-openssl.key" " Derive ECDH using OpenSSL" test "cmp $algo-ecdh-openssl.key $algo-ecdh-shell.key" " Compare ECDH value from yubihsm-shell and OpenSSL" echo "=== Make PKCS10 Certificate Signing Request:" test "$BIN -p password -a generate-csr -i $genkey -S /CN=test/ --out csr.pem" " Generate CSR with yubihsm-shell" test "openssl req -in csr.pem -verify" " Verify CSR with openssl" test "rm csr.pem" " Clean up" echo "=== Clean up:" test "$BIN -p password -a delete-object -i $genkey -t asymmetric-key" " Delete generated key" test "$BIN -p password -a delete-object -i $import_key -t asymmetric-key" " Delete imported key" doneyubihsm-shell-2.7.3/resources/tests/bash/test_edkey.sh0000755000175000017500000000553615167357110022075 0ustar aveenaveen#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } set -e echo "====================== ED keys ===================== " # Generate echo "Generate key:" test "$BIN -p password -a generate-asymmetric-key -i 100 -l \"edKey\" -d 1,2,3 -c sign-eddsa -A ed25519" " Generate key" test "$BIN -p password -a get-object-info -i 100 -t asymmetric-key" " get-object-info" info=$($BIN -p password -a get-object-info -i 100 -t asymmetric-key 2>&1) test "echo $info | grep \"id: 0x0064\"" " Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: ed25519\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"edKey\"'" " Object info contains correct label" test "echo $info | grep \"domains: 1:2:3\"" " Object info contains correct domains" test "echo $info | grep \"origin: generated\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: sign-eddsa\"" " Object info contains correct capabilities" # Import #ssh-keygen -t ed25519 -C "test@yubihsm.se" -f edkey -N foo123 #$BIN --verbose=5 -p password -a put-asymmetric-key -i 200 -l "edKey_imported" -d "5" -c "sign-eddsa" --in=edkey # Get public key echo "Get public key:" test "$BIN -p password -a get-public-key -i 100" " Get public key to stdout" $BIN -p password -a get-public-key -i 100 > edkey1.pub 2>/dev/null test "$BIN -p password -a get-public-key -i 100 --out edkey2.pub" " Get public key to file" test "cmp edkey1.pub edkey2.pub" " Match public key in stdout and file" # Signing echo "Signing:" test "$BIN -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt" " Sign to stdout" $BIN -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt > data.ed1.sig 2>/dev/null test "$BIN -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt --out data.ed2.sig" " Sign to file" if [[ $(cat data.ed1.sig) != $(cat data.ed2.sig) ]]; then echo "Signature in stdout and file are different" exit 2 fi echo " Matching signature in stdout and file ... OK" # Generating CSR echo "Generating CSR:" test "$BIN -p password -a generate-csr -i 100 -S /CN=test/ --out csr.pem" " Generate CSR with yubihsm-shell" test "openssl req -in csr.pem -verify" " Verify CSR with openssl" # Delete echo "Clean up:" test "$BIN -p password -a delete-object -i 100 -t asymmetric-key" " Delete key" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.7.3/resources/tests/bash/opensc_test.sh0000755000175000017500000004620515167357110022261 0ustar aveenaveen#!/bin/bash if [ "$#" -ne 1 ]; then echo "Usage: ./opensc_test.sh " echo "" echo "This script expects that YUBIHSM_PKCS11_CONF environment variable is defined" exit fi MODULE=$1 #$env:YUBIHSM_PKCS11_CONF=$YHPKCS11CFG test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } set -e echo "this is test data" > data.txt ### Note about pkcs11-tool and object id: ### When generating/importing private keys, an ID has to be specified otherwise, practically a random key will be used ### when, for example, signing. This is because pkcs11-tool, unless a specific ID is set in the command line, it will use ### the first private key it finds to perform the operation. Setting/using a key's label/alias will not have an effect ### because it will not look for a key by label/alias. However, specifying an object to delete by its label/alias seems ### to work just fine. EC_CURVES=("secp224r1" "secp256r1" "secp384r1" "secp521r1" "secp256k1") set +e cat /etc/os-release | grep 'Fedora' is_fedora=$? set -e if [ $is_fedora -ne 0 ]; then EC_CURVES=(${EC_CURVES[@]} "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1") fi for curve in "${EC_CURVES[@]}"; do echo "**********************************" echo " $curve" echo "**********************************" # # Generate key test "pkcs11-tool --module $MODULE --login --pin 0001password --keypairgen --id 1 --key-type EC:$curve" " Generate EC key with curve $curve" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 1 --type pubkey --output-file pubkey.der" " Get public key of generated key" # Sign with generated key test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m ECDSA-SHA1 --signature-format openssl -i data.txt -o data.sig" " Sign with generated key and ECDSA-SHA1" test "openssl dgst -sha1 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m ECDSA-SHA256 --signature-format openssl -i data.txt -o data.sig" " Sign with generated key and ECDSA-SHA256" test "openssl dgst -sha256 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m ECDSA-SHA384 --signature-format openssl -i data.txt -o data.sig" " Sign with generated key and ECDSA-SHA384" test "openssl dgst -sha384 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m ECDSA-SHA512 --signature-format openssl -i data.txt -o data.sig" " Sign with generated key and ECDSA-SHA512" test "openssl dgst -sha512 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" # Import key test "openssl ecparam -genkey -name $curve -noout -out keypair.pem" " Generate keypair with curve $curve using OpenSSL" test "pkcs11-tool --module $MODULE --login --pin 0001password --write-object keypair.pem --id 2 --type privkey --usage-sign" " Import EC key with curve $curve" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 2 --type pubkey --output-file pubkey_imported.der" " Get public key of imported key" # Sign with imported key test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA1 --signature-format openssl -i data.txt -o data.sig" " Sign with imported key and ECDSA-SHA1" test "openssl dgst -sha1 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA256 --signature-format openssl -i data.txt -o data.sig" " Sign with imported key and ECDSA-SHA256" test "openssl dgst -sha256 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA384 --signature-format openssl -i data.txt -o data.sig" " Sign with imported key and ECDSA-SHA384" test "openssl dgst -sha384 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA512 --signature-format openssl -i data.txt -o data.sig" " Sign with imported key and ECDSA-SHA512" test "openssl dgst -sha512 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" # Derive ECDH test "pkcs11-tool --module $MODULE --login --pin 0001password --derive --id 1 --input-file pubkey_imported.der --output-file ecdh_pkcs11.bin" " Derive ECDH using pkcs11-tool" test "openssl pkeyutl -derive -inkey keypair.pem -peerkey pubkey.der -out ecdh_openssl.bin" " Derive ECDH using OpenSSL" test "cmp ecdh_pkcs11.bin ecdh_openssl.bin" " Compare the derived ECDH keys" test "rm ecdh_pkcs11.bin ecdh_openssl.bin" " Delete ecdh keys" # Requires writable session? yubihsm-pkcs11 only allowed regular users #pkcs11-tool --module $MODULE --login --pin 0001password --test-ec --id 200 --key-type EC:secp256r1 # Delete keys test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 1 --type privkey" " Delete generated key" test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 2 --type privkey" " Delete imported key" done RSA_LENGTHS=("2048" "3072" "4096") test "openssl dgst -sha1 -binary -out data.sha1 data.txt" " Hash data with SHA1 and OpenSSL" test "openssl dgst -sha256 -binary -out data.sha256 data.txt" " Hash data with SHA256 and OpenSSL" test "openssl dgst -sha384 -binary -out data.sha384 data.txt" " Hash data with SHA384 and OpenSSL" test "openssl dgst -sha512 -binary -out data.sha512 data.txt" " Hash data with SHA512 and OpenSSL" for len in "${RSA_LENGTHS[@]}"; do echo "**********************************" echo " RSA$len" echo "**********************************" # Generate key test "pkcs11-tool --module $MODULE --login --pin 0001password --keypairgen --id 1 --key-type rsa:$len --usage-sign --usage-decrypt" " Generate RSA$len key" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 1 --type pubkey --output-file pubkey.der" " Get public key of generated key" # Sign with generated key and RSA-PKCS test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA1-RSA-PKCS -i data.txt -o data.sig" " Sign with generated key and SHA1-RSA-PKCS" test "openssl dgst -sha1 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA256-RSA-PKCS -i data.txt -o data.sig" " Sign with generated key and SHA256-RSA-PKCS" test "openssl dgst -sha256 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA384-RSA-PKCS -i data.txt -o data.sig" " Sign with generated key and SHA384-RSA-PKCS" test "openssl dgst -sha384 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA512-RSA-PKCS -i data.txt -o data.sig" " Sign with generated key and SHA512-RSA-PKCS" test "openssl dgst -sha512 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" # Sign with generated key and RSA-PSS test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA1-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with generated key and SHA1-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA256-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with generated key and SHA256-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha256 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA384-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with generated key and SHA384-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha384 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA512-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with generated key and SHA512-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha512 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512" " Verify signature with OpenSSL" # Decrypt with generated key and PKCS1v15 test "openssl rsautl -encrypt -inkey pubkey.der -pubin -in data.txt -out data.enc" " Encryp with OpenSSL using PKCS1v15" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" # Decrypt with generated key and OAEP test "openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA1" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA-1 --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA256" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA256 --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA384" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA384 --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA512" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA512 --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" # Import key test "openssl genrsa -out keypair.pem $len" " Generate key with OpenSSL" test "pkcs11-tool --module $MODULE --login --pin 0001password --write-object keypair.pem --id 2 --type privkey --usage-sign --usage-decrypt" " Import RSA$len key" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 2 --type pubkey --output-file pubkey_imported.der" " Get public key of imported key" # Sign with imported key and PKCS test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA1-RSA-PKCS -i data.txt -o data.sig" " Sign with imported key and SHA1-RSA-PKCS" test "openssl dgst -sha1 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA256-RSA-PKCS -i data.txt -o data.sig" " Sign with imported key and SHA256-RSA-PKCS" test "openssl dgst -sha256 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA384-RSA-PKCS -i data.txt -o data.sig" " Sign with imported key and SHA384-RSA-PKCS" test "openssl dgst -sha384 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA512-RSA-PKCS -i data.txt -o data.sig" " Sign with imported key and SHA512-RSA-PKCS" test "openssl dgst -sha512 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" # Sign with imported key and RSA-PSS test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA1-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with imported key and SHA1-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA256-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with imported key and SHA256-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha256 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA384-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with imported key and SHA384-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha384 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA512-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with imported key and SHA512-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha512 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512" " Verify signature with OpenSSL" # Decrypt with imported key and PKCS1v15 test "openssl rsautl -encrypt -inkey pubkey_imported.der -pubin -in data.txt -out data.enc" " Encryp with OpenSSL using PKCS1v15" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" # Decrypt with imported key and OAEP test "openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA1" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA-1 --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA256" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA256 --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA384" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA384 --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA512" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA512 --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" # Perform pkcs11-tool RSA tests pkcs11-tool --module $MODULE --login --pin 0001password --test # Delete keys test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 1 --type privkey" " Delete generated key" test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 2 --type privkey" " Delete generated key" done rm data.sha1 data.sha256 data.sha384 data.sha512 data.sig data.txt rm keypair.pem pubkey.der pubkey_imported.der echo "****************************************************" echo " Compress X509 Certificate" echo "****************************************************" openssl req -x509 -newkey rsa:4096 -out too_large_cert.der -outform DER -sha256 -days 3650 -nodes -subj '/C=01/ST=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/L=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/O=0123456789012345678901234567890123456789012345678901234567890123/OU=0123456789012345678901234567890123456789012345678901234567890123' > /dev/null 2>&1 test "pkcs11-tool --module $MODULE --login --pin 0001password --write-object too_large_cert.der --id 6464 --type cert" " Import large X509 certificate" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 6464 --type cert --output-file too_large_cert_out.der" " Get imported certificate" test "cmp too_large_cert.der too_large_cert_out.der" " Compare read certificate with the one imported" test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 6464 --type cert" " Delete certificate" set +eyubihsm-shell-2.7.3/resources/tests/ps1/0000755000175000017500000000000015167357110017153 5ustar aveenaveenyubihsm-shell-2.7.3/resources/tests/ps1/opensc_test.ps10000644000175000017500000000427715167357110022140 0ustar aveenaveen# This script runs on Powershell. If running tests on the current Powershell terminal is not permitted, run the # following command to allow it only on the current terminal: # >> Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process if($args.length -eq 0) { echo "Usage: ./opensc_tests.ps1 " echo "" echo "This script expects that libyubihsm.dll and the libcrypto.dll are on PATH and YUBIHSM_PKCS11_CONF environment variable is defined" exit } if ((Get-Command "pkcs11-tool.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path +=";C:\Program Files\OpenSC Project\OpenSC\tools" } $MODULE=$args[0] #$YHPKCS11CFG=$args[2] #$env:YUBIHSM_PKCS11_CONF=$YHPKCS11CFG Set-PSDebug -Trace 1 echo "******************* Generation Tests ********************* " pkcs11-tool.exe --module $MODULE --login --pin 0001password --keypairgen --id 100 --key-type EC:secp384r1 pkcs11-tool.exe --module $MODULE --login --pin 0001password --keypairgen --id 2 --key-type EC:prime256v1 pkcs11-tool.exe --module $MODULE --login --pin 0001password --keypairgen --id 4 --key-type rsa:2048 pkcs11-tool.exe --module $MODULE --login --pin 0001password --keypairgen --id 5 --key-type rsa:3072 #Set-PSDebug -Trace 0 #exit echo "******************* Signing Tests ********************* " echo "this is test data" > Z:/data.txt pkcs11-tool.exe --module $MODULE --sign --pin 0001password --id 100 -m ECDSA-SHA1 --signature-format openssl -i Z:/data.txt -o Z:/data.sig pkcs11-tool.exe --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA1 --signature-format openssl -i Z:/data.txt -o Z:/data.sig pkcs11-tool.exe --module $MODULE --sign --pin 0001password --id 4 -m SHA512-RSA-PKCS -i Z:/data.txt -o Z:/data.sig pkcs11-tool.exe --module $MODULE --sign --pin 0001password --id 5 -m SHA512-RSA-PKCS -i Z:/data.txt -o Z:/data.sig rm Z:/data.txt rm Z:/data.sig echo "******************* Testing RSA Tests ********************* " pkcs11-tool.exe --module $MODULE --login --pin 0001password --test #echo "******************* Testing EC Tests ********************* " #pkcs11-tool.exe --module $MODULE --login --login-type so --so-pin 0001password --test-ec --id 200 --key-type EC:secp256r1 Set-PSDebug -Trace 0yubihsm-shell-2.7.3/resources/tests/ps1/test_eckey.ps10000644000175000017500000010004615167357110021740 0ustar aveenaveen$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin;C:/Users/dev/vcpkg/vcpkg-master/packages/openssl-windows_x86-windows/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin;C:/Users/dev/vcpkg/vcpkg-master/packages/openssl-windows_x64-windows/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } $env:Path += ";C:\Users\dev\vcpkg\vcpkg-master\packages\openssl-windows_x64-windows\tools\openssl" echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } $keyid=100 $import_keyid=200 echo "---------------------- EC keys --------------------- " # ECP224 echo "**********************************" echo " ECP224" echo "**********************************" #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecp224"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t asymmetric-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: asymmetric-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: ec224df"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "ecKey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 5:8:13"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: derive-ecdh:sign-attestation-certificate:sign-ecdsa"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name secp224r1 -noout -out secp224r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "2,6,7" -c "sign-ecdsa,sign-attestation-certificate" --in=secp224r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? # -- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecp224sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecp224sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecp224sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecp224sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecp224sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecp224sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecp224sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecp224sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp224r1-keypair.pem -pubout -out secp224r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp224r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " ECP256" echo "**********************************" # ECP256 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecp256"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name secp256r1 -noout -out secp256r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=secp256r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecp256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecp256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecp256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecp256sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecp256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecp256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecp256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecp256sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp256r1-keypair.pem -pubout -out secp256r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp256r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " ECP384" echo "**********************************" # ECP384 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecp384"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name secp384r1 -noout -out secp384r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=secp384r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecp384sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecp384sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecp384sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecp384sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecp384sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecp384sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecp384sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecp384sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp384r1-keypair.pem -pubout -out secp384r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp384r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " ECP512" echo "**********************************" # ECP512 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecp521"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl ecparam -genkey -name secp521r1 -noout -out secp521r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=secp521r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecp521sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecp521sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecp521sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecp521sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecp521sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecp521sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecp521sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecp521sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp521r1-keypair.pem -pubout -out secp521r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp521r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " ECK256" echo "**********************************" # ECK256 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "eck256"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name secp256k1 -noout -out secp256k1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=secp256k1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.eck256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.eck256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.eck256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.eck256sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.eck256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.eck256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.eck256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.eck256sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp256k1-keypair.pem -pubout -out secp256k1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp256k1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " Brainpool256" echo "**********************************" # Brainpool256 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecbp256"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name brainpoolP256r1 -noout -out brainpool256r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=brainpool256r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecbp256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecbp256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecbp256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecbp256sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecbp256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecbp256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecbp256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecbp256sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in brainpool256r1-keypair.pem -pubout -out brainpool256r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in brainpool256r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " Brainpool384" echo "**********************************" # Brainpool384 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecbp384"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name brainpoolP384r1 -noout -out brainpool384r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=brainpool384r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecbp384sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecbp384sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecbp384sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecbp384sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecbp384sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecbp384sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecbp384sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecbp384sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in brainpool384r1-keypair.pem -pubout -out brainpool384r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in brainpool384r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " Brainpool512" echo "**********************************" # Brainpool512 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecbp512"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name brainpoolP512r1 -noout -out brainpool512r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=brainpool512r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecbp512sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecbp512sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecbp512sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecbp512sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecbp512sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecbp512sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecbp512sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecbp512sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in brainpool512r1-keypair.pem -pubout -out brainpool512r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in brainpool512r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.7.3/resources/tests/ps1/test_otpaeadkey.ps10000644000175000017500000001242415167357110022770 0ustar aveenaveen$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } $keyid=100 echo "---------------------- HAMC keys --------------------- " echo "**********************************" echo " AEAD Key 128" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-otp-aead-key -i $keyid -l "aeadkey" -d "1,2,3" -c "randomize-otp-aead" -A "aes128-yubico-otp" --nonce 0x01020304; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t otp-aead-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: otp-aead-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: aes128-yubico-otp"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "aeadkey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1:2:3"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: randomize-otp-aead"; CheckExitStatus -ECode $? echo "=== Randomize OTP AEAD" yubihsm-shell.exe -p password -a randomize-otp-aead -i $keyid; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t otp-aead-key; CheckExitStatus -ECode $? echo "**********************************" echo " AEAD Key 192" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-otp-aead-key -i $keyid -l "aeadkey" -d "1,2,3" -c "randomize-otp-aead" -A "aes192-yubico-otp" --nonce 0x01020304; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t otp-aead-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: otp-aead-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: aes192-yubico-otp"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "aeadkey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1:2:3"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: randomize-otp-aead"; CheckExitStatus -ECode $? echo "=== Randomize OTP AEAD" yubihsm-shell.exe -p password -a randomize-otp-aead -i $keyid; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t otp-aead-key; CheckExitStatus -ECode $? echo "**********************************" echo " AEAD Key 256" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-otp-aead-key -i $keyid -l "aeadkey" -d "1,2,3" -c "randomize-otp-aead" -A "aes256-yubico-otp" --nonce 0x01020304; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t otp-aead-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: otp-aead-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: aes256-yubico-otp"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "aeadkey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1:2:3"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: randomize-otp-aead"; CheckExitStatus -ECode $? echo "=== Randomize OTP AEAD" yubihsm-shell.exe -p password -a randomize-otp-aead -i $keyid; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t otp-aead-key; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.7.3/resources/tests/ps1/test_hmackey.ps10000644000175000017500000001050615167357110022262 0ustar aveenaveen$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } $keyid=100 echo "---------------------- HAMC keys --------------------- " echo "**********************************" echo " hmac-sha1" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-hmac-key -i $keyid -l "hmackey" -d "1,2,3" -c "sign-hmac" -A "hmac-sha1"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t hmac-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: hmac-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: hmac-sha1"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "hmackey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1:2:3"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: sign-hmac"; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t hmac-key; CheckExitStatus -ECode $? echo "**********************************" echo " hmac-sha256" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-hmac-key -i $keyid -l "hmackey" -d "1,2,3" -c "sign-hmac" -A "hmac-sha256"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t hmac-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: hmac-sha256"; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t hmac-key; CheckExitStatus -ECode $? echo "**********************************" echo " hmac-sha384" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-hmac-key -i $keyid -l "hmackey" -d "1,2,3" -c "sign-hmac" -A "hmac-sha384"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t hmac-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: hmac-sha384"; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t hmac-key; CheckExitStatus -ECode $? echo "**********************************" echo " hmac-sha512" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-hmac-key -i $keyid -l "hmackey" -d "1,2,3" -c "sign-hmac" -A "hmac-sha512"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t hmac-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: hmac-sha512"; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t hmac-key; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.7.3/resources/tests/ps1/test_edkey.ps10000644000175000017500000000435015167357110021742 0ustar aveenaveen$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } echo "---------------------- ED keys --------------------- " # Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i 100 -l "edKey" -d "1,2,3" -c "sign-eddsa" -A "ed25519"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i 100 -t asymmetric-key; CheckExitStatus -ECode $? # Get public key yubihsm-shell.exe -p password -a get-public-key -i 100 > edkey1.pub; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i 100 --out edkey2.pub; CheckExitStatus -ECode $? # Signing yubihsm-shell.exe -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt > data.ed1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt --out data.ed2.sig; CheckExitStatus -ECode $? # Delete yubihsm-shell.exe -p password -a delete-object -i 100 -t asymmetric-key; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.7.3/resources/tests/ps1/test_rsakey.ps10000644000175000017500000005311415167357110022141 0ustar aveenaveen$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } $keyid=100 $import_keyid=200 echo "---------------------- RSA keys --------------------- " echo "**********************************" echo " RSA2048" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "rsaKey" -d "1" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" -A "rsa2048"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t asymmetric-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: asymmetric-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: rsa2048"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "rsaKey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss"; CheckExitStatus -ECode $? rm info.txt echo "=== Get public key of generated key" yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM --out pubkey.pem; CheckExitStatus -ECode $? echo "=== Import into YubiHSM" openssl.exe genrsa -out rsa2048-keypair.pem 2048; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "rsaKeyImport" -d "2" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" --in=rsa2048-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $import_keyid -t asymmetric-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x00c8"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: asymmetric-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: rsa2048"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "rsaKeyImport"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 2"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: imported"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss"; CheckExitStatus -ECode $? echo "=== Get public key of imported key" yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM --out pubkey_imported.pem; CheckExitStatus -ECode $? echo "=== Signing with generated key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha1 --in data.txt --out data.2048pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha256 --in data.txt --out data.2048pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha384 --in data.txt --out data.2048pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha512 --in data.txt --out data.2048pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha1 --in data.txt --out data.2048psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha256 --in data.txt --out data.2048psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha384 --in data.txt --out data.2048psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha512 --in data.txt --out data.2048psssha512.sig; CheckExitStatus -ECode $? echo "=== Signing with imported key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha1 --in data.txt --out data.2048pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha256 --in data.txt --out data.2048pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha384 --in data.txt --out data.2048pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha512 --in data.txt --out data.2048pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha1 --in data.txt --out data.2048psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha256 --in data.txt --out data.2048psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha384 --in data.txt --out data.2048psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha512 --in data.txt --out data.2048psssha512.sig; CheckExitStatus -ECode $? echo "=== Make self signed certificate" yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? echo "=== Sign attestation certificate" yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? echo "=== Decrypt with generated key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey.pem -pubin -in data.txt -out data.enc; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $keyid --in data.enc --out data.dec; CheckExitStatus -ECode $? if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec echo "=== Decrypt with imported key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey_imported.pem -pubin -in data.txt -out data.enc; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $import_keyid --in data.enc --out data.dec; CheckExitStatus -ECode $? if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "**********************************" echo " RSA3072" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "rsaKey" -d "1" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" -A "rsa3072"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "=== Get public key of generated key" yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM --out pubkey.pem; CheckExitStatus -ECode $? echo "=== Import into YubiHSM" openssl.exe genrsa -out rsa3072-keypair.pem 3072; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "rsaKeyImport" -d "2" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" --in=rsa3072-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "=== Get public key of imported key" yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM --out pubkey_imported.pem; CheckExitStatus -ECode $? echo "=== Signing with generated key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha1 --in data.txt --out data.3072pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha256 --in data.txt --out data.3072pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha384 --in data.txt --out data.3072pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha512 --in data.txt --out data.3072pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha1 --in data.txt --out data.3072psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha256 --in data.txt --out data.3072psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha384 --in data.txt --out data.3072psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha512 --in data.txt --out data.3072psssha512.sig; CheckExitStatus -ECode $? echo "=== Signing with imported key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha1 --in data.txt --out data.3072pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha256 --in data.txt --out data.3072pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha384 --in data.txt --out data.3072pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha512 --in data.txt --out data.3072pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha1 --in data.txt --out data.3072psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha256 --in data.txt --out data.3072psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha384 --in data.txt --out data.3072psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha512 --in data.txt --out data.3072psssha512.sig; CheckExitStatus -ECode $? echo "=== Make self signed certificate" yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? #yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? echo "=== Sign attestation certificate" yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? <# echo "=== Decrypt with generated key and PKCS1v15" openssl rsautl -encrypt -inkey pubkey.pem -pubin -in data.txt -out data.enc yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $keyid --in data.enc --out data.dec if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec echo "=== Decrypt with imported key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey_imported.pem -pubin -in data.txt -out data.enc yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $import_keyid --in data.enc --out data.dec <# if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec #> echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? # RSA 4096 echo "**********************************" echo " RSA4096" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "rsaKey" -d "1" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" -A "rsa4096"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "=== Get public key of generated key" yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM --out pubkey.pem; CheckExitStatus -ECode $? echo "=== Import into YubiHSM" openssl.exe genrsa -out rsa4096-keypair.pem 4096; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "rsaKeyImport" -d "2" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" --in=rsa4096-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "=== Get public key of imported key" yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM --out pubkey_imported.pem; CheckExitStatus -ECode $? echo "=== Signing with generated key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha1 --in data.txt --out data.4096pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha256 --in data.txt --out data.4096pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha384 --in data.txt --out data.4096pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha512 --in data.txt --out data.4096pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha1 --in data.txt --out data.4096psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha256 --in data.txt --out data.4096psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha384 --in data.txt --out data.4096psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha512 --in data.txt --out data.4096psssha512.sig; CheckExitStatus -ECode $? echo "=== Signing with imported key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha1 --in data.txt --out data.4096pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha256 --in data.txt --out data.4096pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha384 --in data.txt --out data.4096pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha512 --in data.txt --out data.4096pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha1 --in data.txt --out data.4096psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha256 --in data.txt --out data.4096psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha384 --in data.txt --out data.4096psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha512 --in data.txt --out data.4096psssha512.sig; CheckExitStatus -ECode $? echo "=== Make self signed certificate" #yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? #yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? echo "=== Sign attestation certificate" yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? <# echo "=== Decrypt with generated key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey.pem -pubin -in data.txt -out data.enc yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $keyid --in data.enc --out data.dec if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec echo "=== Decrypt with imported key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey_imported.pem -pubin -in data.txt -out data.enc yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $import_keyid --in data.enc --out data.dec if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec #> echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.7.3/resources/tests/ps1/cmdline_test.ps10000644000175000017500000001021315167357110022247 0ustar aveenaveen$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different com mands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } yubihsm-shell.exe --version; CheckExitStatus -ECode $? yubihsm-shell.exe --help; CheckExitStatus -ECode $? yubihsm-shell.exe -a get-device-info; CheckExitStatus -ECode $? echo "********************** Reset YubiHSM ********************* " yubihsm-shell.exe -p password -a reset; CheckExitStatus -ECode $? Start-Sleep -s 10 echo "********************** Blink ********************* " yubihsm-shell.exe -p password -a blink; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a blink --duration=5; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a blink-device; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a blink-device --duration=5; CheckExitStatus -ECode $? echo "********************** Get Pseudo-random ********************* " yubihsm-shell.exe -p password -a get-pseudo-random; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-pseudo-random --count=10; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-pseudo-random --count=10 --out=random.txt; CheckExitStatus -ECode $? rm random.txt echo "********************** Asym keys ********************* " & "$PSScriptRoot\test_edkey.ps1" "$ARCH" & "$PSScriptRoot\test_eckey.ps1" "$ARCH" & "$PSScriptRoot\test_rsakey.ps1" "$ARCH" echo "********************** HMAC keys ********************* " & "$PSScriptRoot\test_hmackey.ps1" "$ARCH" echo "********************** AEAD keys ********************* " & "$PSScriptRoot\test_otpaeadkey.ps1" "$ARCH" Set-PSDebug -Trace 1 #echo "********************** Template ********************* " #echo "=== Import template" #$id=100 #yubihsm-shell.exe -p password -a get-pseudo-random --count=512 --out=template.txt; CheckExitStatus -ECode $? #yubihsm-shell.exe -p password -a put-template -i $id -l template -d 1 -A template-ssh --in template.txt; CheckExitStatus -ECode $? #yubihsm-shell.exe -p password -a get-object-info -i $id -t template; CheckExitStatus -ECode $? #echo "=== Get template" #yubihsm-shell.exe -p password -a get-template -i $id; CheckExitStatus -ECode $? #echo "=== Delete template" #yubihsm-shell.exe -p password -a delete-object -i $id -t template; CheckExitStatus -ECode $? #rm template.txt #echo "********************** Wrap keys ********************* " echo "********************** Authentication keys ********************* " echo "=== Create new authentication key" $id=200 yubihsm-shell.exe -p password -a put-authentication-key -i $id -l authkey -d 1,2,3 -c all --new-password foo123; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $id -t authentication-key; CheckExitStatus -ECode $? echo "=== Login using new authetication key" yubihsm-shell.exe --authkey $id -p foo123 -a get-object-info -i 1 -t authentication-key; CheckExitStatus -ECode $? echo "=== Delete new authentication key" yubihsm-shell.exe -p password -a delete-object -i $id -t authentication-key; CheckExitStatus -ECode $? Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.7.3/ykhsmauth/0000755000175000017500000000000015167357110015311 5ustar aveenaveenyubihsm-shell-2.7.3/ykhsmauth/ykhsmauth.c0000644000175000017500000005316115167357110017500 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "internal.h" #include "ykhsmauth.h" #ifdef _WIN32 #define strncasecmp _strnicmp #endif static uint16_t encode_len(uint8_t *buf, uint16_t len) { if (len > 0xff) { *buf++ = 0x82; *buf++ = len >> 8; *buf++ = len; return 3; } if (len > 0x7f) { *buf++ = 0x81; *buf++ = len; return 2; } *buf++ = len; return 1; } static void add_tag(APDU *apdu, uint8_t tag, const void *data, uint16_t len, uint16_t pad) { uint8_t *ptr = apdu->st.data + apdu->st.lc; *ptr++ = tag; ptr += encode_len(ptr, len + pad); memcpy(ptr, data, len); ptr += len; memset(ptr, 0, pad); ptr += pad; apdu->st.lc = ptr - apdu->st.data; } static ykhsmauth_rc translate_error(uint16_t sw, uint8_t *retries) { if ((sw & 0xfff0) == SW_AUTHENTICATION_FAILED) { if (retries != NULL) { *retries = sw & ~0xfff0; } return YKHSMAUTHR_WRONG_PW; } else if (sw == SW_FILE_FULL) { return YKHSMAUTHR_STORAGE_FULL; } else if (sw == SW_FILE_NOT_FOUND) { return YKHSMAUTHR_ENTRY_NOT_FOUND; } else if (sw == SW_WRONG_DATA) { return YKHSMAUTHR_INVALID_PARAMS; } else if (sw == SW_MEMORY_ERROR) { return YKHSMAUTHR_MEMORY_ERROR; } else if (sw == SW_SECURITY_STATUS_NOT_SATISFIED) { return YKHSMAUTHR_TOUCH_ERROR; } else if (sw == SW_FILE_INVALID) { return YKHSMAUTHR_ENTRY_INVALID; } else if (sw == SW_DATA_INVALID) { return YKHSMAUTHR_DATA_INVALID; } else if (sw == SW_INS_NOT_SUPPORTED) { return YKHSMAUTHR_NOT_SUPPORTED; } else { return YKHSMAUTHR_GENERIC_ERROR; } } ykhsmauth_rc ykhsmauth_init(ykhsmauth_state **state, int verbose) { if (state == NULL) { if (verbose) { fprintf(stderr, "Unable to initialize: %s\n", ykhsmauth_strerror(YKHSMAUTHR_INVALID_PARAMS)); } return YKHSMAUTHR_INVALID_PARAMS; } ykhsmauth_state *s = calloc(1, sizeof(ykhsmauth_state)); if (s == NULL) { if (verbose) { fprintf(stderr, "Unable to initialize: %s\n", ykhsmauth_strerror(YKHSMAUTHR_MEMORY_ERROR)); } return YKHSMAUTHR_MEMORY_ERROR; } s->verbose = verbose; *state = s; return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_done(ykhsmauth_state *state) { ykhsmauth_disconnect(state); if (state == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } SCardReleaseContext(state->context); state->context = 0; free(state); return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_disconnect(ykhsmauth_state *state) { if (state == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } if (state->card) { SCardDisconnect(state->card, SCARD_RESET_CARD); state->card = 0; } return YKHSMAUTHR_SUCCESS; } static void dump_hex(const unsigned char *buf, DWORD len) { for (DWORD i = 0; i < len; i++) { fprintf(stderr, "%02x ", buf[i]); } } static ykhsmauth_rc send_data(ykhsmauth_state *state, const APDU *apdu, unsigned char *data, LPDWORD recv_len, uint16_t *sw) { DWORD send_len = apdu->st.lc + 5; *sw = 0; if (state->verbose > 1) { fprintf(stderr, "> "); dump_hex(apdu->raw, send_len); fprintf(stderr, "\n"); } int32_t rc = SCardTransmit(state->card, SCARD_PCI_T1, apdu->raw, send_len, NULL, data, recv_len); if (rc != SCARD_S_SUCCESS) { if (state->verbose) { fprintf(stderr, "SCardTransmit failed, rc=%08x\n", rc); } return YKHSMAUTHR_PCSC_ERROR; } if (state->verbose > 1) { fprintf(stderr, "< "); dump_hex(data, *recv_len); fprintf(stderr, "\n"); } if (*recv_len >= 2) { *sw = (data[*recv_len - 2] << 8) | data[*recv_len - 1]; *recv_len -= 2; } return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_connect(ykhsmauth_state *state, const char *wanted) { if (state == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } char readers[2048] = {0}; size_t readers_len = sizeof(readers); ykhsmauth_rc ret = ykhsmauth_list_readers(state, readers, &readers_len); if (ret != YKHSMAUTHR_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to list_readers: %s\n", ykhsmauth_strerror(ret)); } return ret; } for (char *reader_ptr = readers; *reader_ptr != '\0'; reader_ptr += strlen(reader_ptr) + 1) { if (wanted) { bool found = false; char *ptr = reader_ptr; while (strlen(ptr) >= strlen(wanted)) { if (strncasecmp(ptr, wanted, strlen(wanted)) == 0) { found = true; break; } ptr++; } if (found == false) { if (state->verbose) { fprintf(stderr, "Skipping reader '%s' since it doesn't match '%s'\n", reader_ptr, wanted); } continue; } } if (state->verbose) { fprintf(stderr, "Trying to connect to reader '%s'\n", reader_ptr); } DWORD active_protocol = 0; int32_t rc = SCardConnect(state->context, reader_ptr, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &state->card, &active_protocol); if (rc != SCARD_S_SUCCESS) { if (state->verbose) { fprintf(stderr, "SCardConnect failed, rc=%08x\n", rc); } continue; } APDU apdu = { {0, 0xa4, 0x04, 0, 8, {0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x07, 0x01}}}; unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; if ((ret = send_data(state, &apdu, data, &recv_len, &sw)) != YKHSMAUTHR_SUCCESS) { if (state->verbose) { fprintf(stderr, "Failed communicating with card: '%s'\n", ykhsmauth_strerror(ret)); } } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Failed selecting application: %04x\n", sw); } } else { return YKHSMAUTHR_SUCCESS; } if (state->verbose) { fprintf(stderr, "Disconnecting reader '%s'\n", reader_ptr); } SCardDisconnect(state->card, SCARD_LEAVE_CARD); state->card = 0; } if (state->verbose) { fprintf(stderr, "No usable reader found\n"); } return YKHSMAUTHR_GENERIC_ERROR; } ykhsmauth_rc ykhsmauth_list_readers(ykhsmauth_state *state, char *readers, size_t *len) { if (state == NULL || readers == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } if (SCardIsValidContext(state->context) != SCARD_S_SUCCESS) { state->card = 0; int32_t rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &state->context); if (rc != SCARD_S_SUCCESS) { if (state->verbose) { fprintf(stderr, "SCardEstablishContext failed, rc=%08x\n", rc); } return YKHSMAUTHR_PCSC_ERROR; } } DWORD readers_len = *len; int32_t rc = SCardListReaders(state->context, NULL, readers, &readers_len); if (rc != SCARD_S_SUCCESS) { if (state->verbose) { fprintf(stderr, "SCardListReaders failed rc=%08x\n", rc); } return YKHSMAUTHR_PCSC_ERROR; } *len = readers_len; return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_get_version_ex(ykhsmauth_state *state, uint8_t *major, uint8_t *minor, uint8_t *patch) { if (state == NULL || major == NULL || minor == NULL || patch == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_GET_VERSION, 0, 0, 0, {0}}}; unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc res; if ((res = send_data(state, &apdu, data, &recv_len, &sw)) != YKHSMAUTHR_SUCCESS) { return res; } else if (sw == SW_SUCCESS && recv_len == 3) { *major = data[0]; *minor = data[1]; *patch = data[2]; return YKHSMAUTHR_SUCCESS; } else { return translate_error(sw, NULL); } } ykhsmauth_rc ykhsmauth_get_version(ykhsmauth_state *state, char *version, size_t len) { if (version == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } uint8_t v[3] = {0}; ykhsmauth_rc res = ykhsmauth_get_version_ex(state, &v[0], &v[1], &v[2]); if(res == YKHSMAUTHR_SUCCESS) { int result = snprintf(version, len, "%d.%d.%d", v[0], v[1], v[2]); if (result < 0) { if (state->verbose) { fprintf(stderr, "Version buffer too small\n"); } return YKHSMAUTHR_GENERIC_ERROR; } } return res; } ykhsmauth_rc ykhsmauth_put(ykhsmauth_state *state, const uint8_t *mgmkey, size_t mgmkey_len, const char *label, uint8_t algo, const uint8_t *key, size_t key_len, const uint8_t *cpw, size_t cpw_len, const uint8_t touch_policy, uint8_t *retries) { if (state == NULL || mgmkey == NULL || mgmkey_len != YKHSMAUTH_PW_LEN || label == NULL || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN || key == NULL || key_len > YKHSMAUTH_YUBICO_ECP256_PRIVKEY_LEN || cpw == NULL || cpw_len > YKHSMAUTH_PW_LEN) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_PUT, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_MGMKEY, mgmkey, mgmkey_len, 0); add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); add_tag(&apdu, YKHSMAUTH_TAG_ALGO, &algo, sizeof(algo), 0); if (algo == YKHSMAUTH_YUBICO_AES128_ALGO) { add_tag(&apdu, YKHSMAUTH_TAG_KEY_ENC, key, key_len / 2, 0); add_tag(&apdu, YKHSMAUTH_TAG_KEY_MAC, key + key_len / 2, key_len / 2, 0); } else if (algo == YKHSMAUTH_YUBICO_ECP256_ALGO) { add_tag(&apdu, YKHSMAUTH_TAG_PRIVKEY, key, key_len, 0); } add_tag(&apdu, YKHSMAUTH_TAG_PW, cpw, cpw_len, YKHSMAUTH_PW_LEN - cpw_len); add_tag(&apdu, YKHSMAUTH_TAG_TOUCH, &touch_policy, sizeof(touch_policy), 0); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to store credential: %04x\n", sw); } return translate_error(sw, retries); } return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_delete(ykhsmauth_state *state, uint8_t *mgmkey, size_t mgmkey_len, char *label, uint8_t *retries) { if (state == NULL || mgmkey == NULL || mgmkey_len != YKHSMAUTH_PW_LEN || label == NULL || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_DELETE, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_MGMKEY, mgmkey, mgmkey_len, 0); add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to delete credential: %04x\n", sw); } return translate_error(sw, retries); } return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_calculate(ykhsmauth_state *state, const char *label, uint8_t *context, size_t context_len, const uint8_t *pw, size_t pw_len, uint8_t *key_s_enc, size_t key_s_enc_len, uint8_t *key_s_mac, size_t key_s_mac_len, uint8_t *key_s_rmac, size_t key_s_rmac_len, uint8_t *retries) { return ykhsmauth_calculate_ex(state, label, context, context_len, NULL, 0, NULL, 0, pw, pw_len, key_s_enc, key_s_enc_len, key_s_mac, key_s_mac_len, key_s_rmac, key_s_rmac_len, retries); } ykhsmauth_rc ykhsmauth_calculate_ex( ykhsmauth_state *state, const char *label, uint8_t *context, size_t context_len, uint8_t *card_pubkey, size_t card_pubkey_len, uint8_t *card_crypto, size_t card_crypto_len, const uint8_t *pw, size_t pw_len, uint8_t *key_s_enc, size_t key_s_enc_len, uint8_t *key_s_mac, size_t key_s_mac_len, uint8_t *key_s_rmac, size_t key_s_rmac_len, uint8_t *retries) { if (state == NULL || label == NULL || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN || context == NULL || context_len > 2 * YKHSMAUTH_YUBICO_ECP256_PUBKEY_LEN || card_pubkey_len > YKHSMAUTH_YUBICO_ECP256_PUBKEY_LEN || card_crypto_len > YKHSMAUTH_SESSION_KEY_LEN || pw == NULL || pw_len > YKHSMAUTH_PW_LEN || key_s_enc == NULL || key_s_enc_len != YKHSMAUTH_SESSION_KEY_LEN || key_s_mac == NULL || key_s_mac_len != YKHSMAUTH_SESSION_KEY_LEN || key_s_rmac == NULL || key_s_rmac_len != YKHSMAUTH_SESSION_KEY_LEN) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_CALCULATE, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); add_tag(&apdu, YKHSMAUTH_TAG_CONTEXT, context, context_len, 0); if (card_pubkey && card_pubkey_len) { add_tag(&apdu, YKHSMAUTH_TAG_PUBKEY, card_pubkey, card_pubkey_len, 0); } // Only send card_crypto for asym auth if (card_crypto && card_crypto_len > YKHSMAUTH_CARD_CRYPTO_LEN) { add_tag(&apdu, YKHSMAUTH_TAG_RESPONSE, card_crypto, card_crypto_len, 0); } add_tag(&apdu, YKHSMAUTH_TAG_PW, pw, pw_len, YKHSMAUTH_PW_LEN - pw_len); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to derive keys: %04x\n", sw); } return translate_error(sw, retries); } if (recv_len != 3 * YKHSMAUTH_SESSION_KEY_LEN) { if (state->verbose) { fprintf(stderr, "Wrong length returned: %zu\n", (size_t) recv_len); } return YKHSMAUTHR_GENERIC_ERROR; } uint8_t *ptr = data; memcpy(key_s_enc, ptr, YKHSMAUTH_SESSION_KEY_LEN); ptr += YKHSMAUTH_SESSION_KEY_LEN; memcpy(key_s_mac, ptr, YKHSMAUTH_SESSION_KEY_LEN); ptr += YKHSMAUTH_SESSION_KEY_LEN; memcpy(key_s_rmac, ptr, YKHSMAUTH_SESSION_KEY_LEN); ptr += YKHSMAUTH_SESSION_KEY_LEN; // Ignore host crypto for now return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_reset(ykhsmauth_state *state) { if (state == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = { {0, YKHSMAUTH_INS_RESET, YKHSMAUTH_P1_RESET, YKHSMAUTH_P2_RESET, 0, {0}}}; unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc res = send_data(state, &apdu, data, &recv_len, &sw); if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to reset: %s\n", ykhsmauth_strerror(res)); } return translate_error(sw, NULL); } return res; } ykhsmauth_rc ykhsmauth_list_keys(ykhsmauth_state *state, ykhsmauth_list_entry *list, size_t *list_items) { if (state == NULL || list_items == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_LIST, 0, 0, 0, {0}}}; unsigned char data[1024] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to list keys: %04x\n", sw); } return translate_error(sw, NULL); } size_t element = 0; size_t i = 0; // i + 1 here guarantees we can read tag and len while (i + 1 < recv_len) { if (data[i++] == YKHSMAUTH_TAG_LABEL_LIST) { size_t len = data[i++]; if (list != NULL) { if (element >= *list_items) { return YKHSMAUTHR_MEMORY_ERROR; } else if (i + len > recv_len || len < 3 || len - 3 > sizeof(list[element].label)) { if (state->verbose) { fprintf(stderr, "Length of element doesn't match expectations (%zu)\n", len); } return YKHSMAUTHR_GENERIC_ERROR; } list[element].algo = data[i++]; list[element].touch = data[i++]; memset(list[element].label, 0, sizeof(list[element].label)); memcpy(list[element].label, data + i, len - 3); i += len - 3; list[element].ctr = data[i++]; } else { i += len; } element++; } else { if (state->verbose) { fprintf(stderr, "Unexpected tag returned on list\n"); } return YKHSMAUTHR_GENERIC_ERROR; } } *list_items = element; if (i != recv_len) { return YKHSMAUTHR_GENERIC_ERROR; } return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_get_challenge(ykhsmauth_state *state, const char *label, uint8_t *challenge, size_t *challenge_len) { return ykhsmauth_get_challenge_ex(state, label, NULL, 0, challenge, challenge_len); } ykhsmauth_rc ykhsmauth_get_challenge_ex(ykhsmauth_state *state, const char *label, const uint8_t *cpw, size_t cpw_len, uint8_t *challenge, size_t *challenge_len) { if (state == NULL || label == NULL || cpw_len > YKHSMAUTH_PW_LEN || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN || challenge == NULL || challenge_len == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_GET_CHALLENGE, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); if(cpw && cpw_len) { add_tag(&apdu, YKHSMAUTH_TAG_PW, cpw, cpw_len, YKHSMAUTH_PW_LEN - cpw_len); } unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to get challenge: %04x\n", sw); } return translate_error(sw, NULL); } if (*challenge_len < recv_len) { return YKHSMAUTHR_INVALID_PARAMS; } *challenge_len = recv_len; memcpy(challenge, data, recv_len); return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_get_pubkey(ykhsmauth_state *state, const char *label, uint8_t *pubkey, size_t *pubkey_len) { if (state == NULL || label == NULL || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN || pubkey == NULL || pubkey_len == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_GET_PUBKEY, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to get pubkey: %04x\n", sw); } return translate_error(sw, NULL); } if (*pubkey_len < recv_len) { return YKHSMAUTHR_INVALID_PARAMS; } *pubkey_len = recv_len; memcpy(pubkey, data, recv_len); return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_get_mgmkey_retries(ykhsmauth_state *state, uint8_t *retries) { if (state == NULL || retries == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_GET_MGMKEY_RETRIES, 0, 0, 0, {0}}}; unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to get Management key retries: %04x\n", sw); } return translate_error(sw, NULL); } *retries = data[0]; return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_put_mgmkey(ykhsmauth_state *state, uint8_t *mgmkey, size_t mgmkey_len, uint8_t *new_mgmkey, size_t new_mgmkey_len, uint8_t *retries) { if (state == NULL || mgmkey == NULL || mgmkey_len != YKHSMAUTH_PW_LEN || new_mgmkey == NULL || new_mgmkey_len != YKHSMAUTH_PW_LEN) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_PUT_MGMKEY, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_MGMKEY, mgmkey, mgmkey_len, 0); add_tag(&apdu, YKHSMAUTH_TAG_MGMKEY, new_mgmkey, new_mgmkey_len, 0); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to store Management key: %04x\n", sw); } return translate_error(sw, retries); } return YKHSMAUTHR_SUCCESS; } yubihsm-shell-2.7.3/ykhsmauth/internal.h0000644000175000017500000000232515167357110017300 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YKHSMAUTH_INTERNAL_H #define YKHSMAUTH_INTERNAL_H #include #if defined(_WIN32) #include #elif defined(__FreeBSD__) #include #include #else #include #include #endif #define READER_LEN 32 #define MAX_READERS 16 struct ykhsmauth_state { SCARDCONTEXT context; SCARDHANDLE card; int verbose; }; union u_APDU { struct { unsigned char cla; unsigned char ins; unsigned char p1; unsigned char p2; unsigned char lc; unsigned char data[0xff]; } st; unsigned char raw[0xff + 5]; }; typedef union u_APDU APDU; #endif yubihsm-shell-2.7.3/ykhsmauth/ykhsmauth.pc.in0000644000175000017500000000041315167357110020255 0ustar aveenaveenlibdir=-L@YUBIHSM_INSTALL_LIB_DIR@ includedir=@YUBIHSM_INSTALL_INC_DIR@ Name: ykhsmauth Description: Yubico YubiHSM application for YubiKey C Library URL: https://www.yubico.com/ Version: @VERSION@ Requires.private: libcrypto libpcsclite Libs: ${libdir} -lykhsmauth yubihsm-shell-2.7.3/ykhsmauth/version.rc.in0000644000175000017500000000210715167357110017731 0ustar aveenaveen #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiAuth Interface Library" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "ykhsmauth.dll" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "ykhsmauth.dll" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.7.3/ykhsmauth/ykhsmauth.h0000644000175000017500000001614015167357110017501 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YKHSMAUTH_H #define YKHSMAUTH_H #include #include //#include #ifdef __cplusplus extern "C" { #endif // INS codes #define YKHSMAUTH_INS_PUT 0x01 #define YKHSMAUTH_INS_DELETE 0x02 #define YKHSMAUTH_INS_CALCULATE 0x03 #define YKHSMAUTH_INS_GET_CHALLENGE 0x04 #define YKHSMAUTH_INS_LIST 0x05 #define YKHSMAUTH_INS_RESET 0x06 #define YKHSMAUTH_INS_GET_VERSION 0x07 #define YKHSMAUTH_INS_PUT_MGMKEY 0x08 #define YKHSMAUTH_INS_GET_MGMKEY_RETRIES 0x09 #define YKHSMAUTH_INS_GET_PUBKEY 0x0a // P1 bytes #define YKHSMAUTH_P1_RESET 0xde // P2 bytes #define YKHSMAUTH_P2_RESET 0xad // Tag codes #define YKHSMAUTH_TAG_LABEL 0x71 #define YKHSMAUTH_TAG_LABEL_LIST 0x72 #define YKHSMAUTH_TAG_PW 0x73 #define YKHSMAUTH_TAG_ALGO 0x74 #define YKHSMAUTH_TAG_KEY_ENC 0x75 #define YKHSMAUTH_TAG_KEY_MAC 0x76 #define YKHSMAUTH_TAG_CONTEXT 0x77 #define YKHSMAUTH_TAG_RESPONSE 0x78 #define YKHSMAUTH_TAG_VERSION 0x79 #define YKHSMAUTH_TAG_TOUCH 0x7a #define YKHSMAUTH_TAG_MGMKEY 0x7b #define YKHSMAUTH_TAG_PUBKEY 0x7c #define YKHSMAUTH_TAG_PRIVKEY 0x7d // Algos #define YKHSMAUTH_YUBICO_AES128_ALGO 38 #define YKHSMAUTH_YUBICO_ECP256_ALGO 39 #define SW_SUCCESS 0x9000 #define SW_BYTES_REMAINING_00 0x6100 #define SW_WRONG_LENGTH 0x6700 #define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 #define SW_FILE_INVALID 0x6983 #define SW_DATA_INVALID 0x6984 #define SW_CONDITIONS_NOT_SATISFIED 0x6985 #define SW_COMMAND_NOT_ALLOWED 0x6986 #define SW_APPLET_SELECT_FAILED 0x6999 #define SW_WRONG_DATA 0x6A80 #define SW_FUNC_NOT_SUPPORTED 0x6A81 #define SW_FILE_NOT_FOUND 0x6A82 #define SW_RECORD_NOT_FOUND 0x6A83 #define SW_INCORRECT_P1P2 0x6A86 #define SW_WRONG_P1P2 0x6B00 #define SW_CORRECT_LENGTH_00 0x6C00 #define SW_INS_NOT_SUPPORTED 0x6D00 #define SW_CLA_NOT_SUPPORTED 0x6E00 #define SW_UNKNOWN 0x6F00 #define SW_FILE_FULL 0x6A84 #define SW_LOGICAL_CHANNEL_NOT_SUPPORTED 0x6881 #define SW_SECURE_MESSAGING_NOT_SUPPORTED 0x6882 #define SW_WARNING_STATE_UNCHANGED 0x6200 #define SW_LAST_COMMAND_EXPECTED 0x6883 #define SW_COMMAND_CHAINING_NOT_SUPPORTED 0x6884 #define SW_AUTHENTICATION_BLOCKED 0x6983 #define SW_AUTHENTICATION_FAILED 0x63C0 #define SW_MEMORY_ERROR 0x6581 // Lengths #define YKHSMAUTH_MIN_LABEL_LEN 1 #define YKHSMAUTH_MAX_LABEL_LEN 64 #define YKHSMAUTH_SESSION_KEY_LEN 16 #define YKHSMAUTH_CARD_CRYPTO_LEN 8 #define YKHSMAUTH_HOST_CRYPTO_LEN 8 #define YKHSMAUTH_YUBICO_AES128_KEY_LEN 32 #define YKHSMAUTH_PW_LEN 16 #define YKHSMAUTH_CONTEXT_LEN 16 #define YKHSMAUTH_YUBICO_ECP256_PUBKEY_LEN 65 #define YKHSMAUTH_YUBICO_ECP256_PRIVKEY_LEN 32 // PBKDF2 derivation parameters #define YKHSMAUTH_DEFAULT_SALT "Yubico" #define YKHSMAUTH_DEFAULT_ITERS 10000 typedef struct ykhsmauth_state ykhsmauth_state; typedef enum { YKHSMAUTHR_SUCCESS = 0, YKHSMAUTHR_MEMORY_ERROR = -1, YKHSMAUTHR_PCSC_ERROR = -2, YKHSMAUTHR_GENERIC_ERROR = -3, YKHSMAUTHR_WRONG_PW = -4, YKHSMAUTHR_INVALID_PARAMS = -5, YKHSMAUTHR_ENTRY_NOT_FOUND = -6, YKHSMAUTHR_STORAGE_FULL = -7, YKHSMAUTHR_TOUCH_ERROR = -8, YKHSMAUTHR_ENTRY_INVALID = -9, YKHSMAUTHR_DATA_INVALID = -10, YKHSMAUTHR_NOT_SUPPORTED = -11, } ykhsmauth_rc; typedef struct { uint8_t algo; uint8_t touch; char label[YKHSMAUTH_MAX_LABEL_LEN + 1]; uint8_t ctr; } ykhsmauth_list_entry; const char *ykhsmauth_strerror(ykhsmauth_rc err); const char *ykhsmauth_strerror_name(ykhsmauth_rc err); ykhsmauth_rc ykhsmauth_init(ykhsmauth_state **state, int verbose); ykhsmauth_rc ykhsmauth_done(ykhsmauth_state *state); ykhsmauth_rc ykhsmauth_connect(ykhsmauth_state *state, const char *wanted); ykhsmauth_rc ykhsmauth_list_readers(ykhsmauth_state *state, char *readers, size_t *len); ykhsmauth_rc ykhsmauth_disconnect(ykhsmauth_state *state); ykhsmauth_rc ykhsmauth_get_version_ex(ykhsmauth_state *state, uint8_t *major, uint8_t *minor, uint8_t *patch); ykhsmauth_rc ykhsmauth_get_version(ykhsmauth_state *state, char *version, size_t len); ykhsmauth_rc ykhsmauth_put(ykhsmauth_state *state, const uint8_t *mgmkey, size_t mgmkey_len, const char *label, uint8_t algo, const uint8_t *key, size_t key_len, const uint8_t *pw, size_t pw_len, const uint8_t touch_policy, uint8_t *retries); ykhsmauth_rc ykhsmauth_delete(ykhsmauth_state *state, uint8_t *mgmkey, size_t mgmkey_len, char *label, uint8_t *retries); ykhsmauth_rc ykhsmauth_calculate(ykhsmauth_state *state, const char *label, uint8_t *context, size_t context_len, const uint8_t *pw, size_t pw_len, uint8_t *key_s_enc, size_t key_s_enc_len, uint8_t *key_s_mac, size_t key_s_mac_len, uint8_t *key_s_rmac, size_t key_s_rmac_len, uint8_t *retries); ykhsmauth_rc ykhsmauth_calculate_ex( ykhsmauth_state *state, const char *label, uint8_t *context, size_t context_len, uint8_t *card_pubkey, size_t card_pubkey_len, uint8_t *card_crypto, size_t card_crypto_len, const uint8_t *pw, size_t pw_len, uint8_t *key_s_enc, size_t key_s_enc_len, uint8_t *key_s_mac, size_t key_s_mac_len, uint8_t *key_s_rmac, size_t key_s_rmac_len, uint8_t *retries); ykhsmauth_rc ykhsmauth_reset(ykhsmauth_state *state); ykhsmauth_rc ykhsmauth_list_keys(ykhsmauth_state *state, ykhsmauth_list_entry *list, size_t *list_items); ykhsmauth_rc ykhsmauth_get_challenge(ykhsmauth_state *state, const char *label, uint8_t *challenge, size_t *challenge_len); ykhsmauth_rc ykhsmauth_get_challenge_ex(ykhsmauth_state *state, const char *label, const uint8_t *cpw, size_t cpw_len, uint8_t *challenge, size_t *challenge_len); ykhsmauth_rc ykhsmauth_get_pubkey(ykhsmauth_state *state, const char *label, uint8_t *pubkey, size_t *pubkey_len); ykhsmauth_rc ykhsmauth_get_mgmkey_retries(ykhsmauth_state *state, uint8_t *retries); ykhsmauth_rc ykhsmauth_put_mgmkey(ykhsmauth_state *state, uint8_t *mgmkey, size_t mgmkey_len, uint8_t *new_mgmkey, size_t new_mgmkey_len, uint8_t *retries); #ifdef __cplusplus } #endif #ifdef _MSC_VER #pragma strict_gs_check(on) #endif #endif yubihsm-shell-2.7.3/ykhsmauth/CMakeLists.txt0000644000175000017500000000460115167357110020052 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set ( SOURCE error.c ykhsmauth.c ) if(WIN32) set(SOURCE ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/version.rc) endif(WIN32) add_library (ykhsmauth SHARED ${SOURCE}) #add_definitions (-DVERSION="${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") target_include_directories (ykhsmauth PRIVATE ${LIBPCSC_INCLUDE_DIRS}) target_compile_options (ykhsmauth PRIVATE ${LIBPCSC_CFLAGS_OTHER}) target_link_libraries (ykhsmauth ${LIBPCSC_LDFLAGS}) set_target_properties (ykhsmauth PROPERTIES VERSION "${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}" SOVERSION ${yubihsm_shell_VERSION_MAJOR}) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_target_properties(ykhsmauth PROPERTIES INSTALL_RPATH "${YUBIHSM_INSTALL_LIB_DIR}") endif() add_library (ykhsmauth_static STATIC ${SOURCE}) target_include_directories (ykhsmauth_static PRIVATE ${LIBPCSC_INCLUDE_DIRS}) target_compile_options (ykhsmauth_static PRIVATE ${LIBPCSC_CFLAGS_OTHER}) set_target_properties (ykhsmauth_static PROPERTIES POSITION_INDEPENDENT_CODE on OUTPUT_NAME ykhsmauth) set_target_properties (ykhsmauth_static PROPERTIES COMPILE_FLAGS "-DSTATIC") target_link_libraries (ykhsmauth_static ${LIBPCSC_LDFLAGS}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ykhsmauth.pc.in ${CMAKE_CURRENT_BINARY_DIR}/ykhsmauth.pc @ONLY) if(WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) endif(WIN32) install( TARGETS ykhsmauth ARCHIVE DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" LIBRARY DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" RUNTIME DESTINATION "${YUBIHSM_INSTALL_BIN_DIR}") install(FILES ykhsmauth.h DESTINATION ${YUBIHSM_INSTALL_INC_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ykhsmauth.pc DESTINATION ${YUBIHSM_INSTALL_PKGCONFIG_DIR}) yubihsm-shell-2.7.3/ykhsmauth/error.c0000644000175000017500000000400315167357110016603 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ykhsmauth.h" #include #define ERR(name, desc) \ { name, #name, desc } typedef struct { ykhsmauth_rc rc; const char *name; const char *description; } err_t; static const err_t errors[] = { ERR(YKHSMAUTHR_SUCCESS, "Successful return"), ERR(YKHSMAUTHR_MEMORY_ERROR, "Device memory error"), ERR(YKHSMAUTHR_PCSC_ERROR, "Error in PCSC call"), ERR(YKHSMAUTHR_GENERIC_ERROR, "General device error"), ERR(YKHSMAUTHR_WRONG_PW, "Wrong Password/Authentication key"), ERR(YKHSMAUTHR_INVALID_PARAMS, "Invalid argument to a device command"), ERR(YKHSMAUTHR_ENTRY_NOT_FOUND, "Entry not found"), ERR(YKHSMAUTHR_STORAGE_FULL, "Device storage full"), ERR(YKHSMAUTHR_TOUCH_ERROR, "Device not touched"), ERR(YKHSMAUTHR_ENTRY_INVALID, "Entry invalid"), ERR(YKHSMAUTHR_DATA_INVALID, "Invalid authentication data"), ERR(YKHSMAUTHR_NOT_SUPPORTED, "Device command not supported"), }; const char *ykhsmauth_strerror(ykhsmauth_rc err) { static const char *unknown = "Unknown ykhsmauth error"; const char *p; if (-err < 0 || -err >= (int) (sizeof(errors) / sizeof(errors[0]))) { return unknown; } p = errors[-err].description; if (!p) { p = unknown; } return p; } const char *ykhsmauth_strerror_name(ykhsmauth_rc err) { if (-err < 0 || -err >= (int) (sizeof(errors) / sizeof(errors[0]))) { return NULL; } return errors[-err].name; } yubihsm-shell-2.7.3/ykhsmauth/README.adoc0000644000175000017500000000063015167357110017075 0ustar aveenaveen== YkHSMAuth Library The YkHSMAuth C Library `libykhsmauth` is a native library to interact with the HSM auth application on a YubiKey. This application is meant to be used for having the HSM authentication keys on a YubiKey. The library exposes functions in the `ykhsmauth_` namespace. These all interact with the HSM auth application over PCSC and are meant for management and usage for the application. yubihsm-shell-2.7.3/doc/0000755000175000017500000000000015167357110014041 5ustar aveenaveenyubihsm-shell-2.7.3/doc/API_Changes.adoc0000644000175000017500000003263415167357110016742 0ustar aveenaveen== 1.0.4 -> 2.0.0 === Definitions ==== Return Codes [options="header"] |======================= |1.0.4 | 2.0.0 | Numeric value |`YHR_MEMORY` | `YHR_MEMORY_ERROR` | `-1` |`YHR_NET_ERROR` | `YHR_CONNECTION_ERROR` | `-3` |`YHR_INVALID_PARAMS` | `YHR_INVALID_PARAMETERS` | `-5` |`YHR_AUTH_SESSION_ERROR` | `YHR_SESSION_AUTHENTICATION_FAILED` | `-9` |`YHR_DEVICE_INV_COMMAND` | `YHR_DEVICE_INVALID_COMMAND` | `-12` |`YHR_DEVICE_INV_DATA` | `YHR_DEVICE_INVALID_DATA` | `-13` |`YHR_DEVICE_INV_SESSION` | `YHR_DEVICE_INVALID_SESSION` | `-14` |`YHR_DEVICE_AUTH_FAIL` | `YHR_DEVICE_AUTHENTICATION_FAILED` | `-15` |`YHR_DEVICE_INV_PERMISSION` | `YHR_DEVICE_INSUFFICIENT_PERMISSIONS` | `-20` |`YHR_DEVICE_OBJ_NOT_FOUND` | `YHR_DEVICE_OBJECT_NOT_FOUND` | `-22` |`YHR_DEVICE_ID_ILLEGAL` | `YHR_DEVICE_INVALID_ID` | `-23` |`YHR_DEVICE_CMD_UNEXECUTED` | `YHR_DEVICE_COMMAND_UNEXECUTED` | `-26` | - | `YHR_DEVICE_SSH_CA_CONSTRAINT_VIOLATION` | `-30` |======================= ==== Object Types [options="header"] |======================= |1.0.4 | 2.0.0 | Hex value |`YH_AUTHKEY` | `YH_AUTHENTICATION_KEY` | `0x02` |`YH_ASYMMETRIC` | `YH_ASYMMETRIC_KEY` | `0x03` |`YH_WRAPKEY` | `YH_WRAP_KEY` | `0x04` |`YH_HMACKEY` | `YH_HMAC_KEY` | `0x05` |`YH_PUBLIC` | `YH_PUBLIC_KEY` | `0x83` |======================= ==== Algorithms [options="header"] |======================= |1.0.4 | 2.0.0 | Numeric value |`YH_ALGO_OPAQUE_X509_CERT` | `YH_ALGO_OPAQUE_X509_CERTIFICATE` | `31` |`YH_ALGO_TEMPL_SSH` | `YH_ALGO_TEMPLATE_SSH` | `36` |`YH_ALGO_YUBICO_OTP_AES128` | `YH_ALGO_AES128_YUBICO_OTP` | `37` |`YH_ALGO_YUBICO_AES_AUTH` | `YH_ALGO_AES128_YUBICO_AUTHENTICATION` | `38` |`YH_ALGO_YUBICO_OTP_AES192` | `YH_ALGO_AES192_YUBICO_OTP` | `39` |`YH_ALGO_YUBICO_OTP_AES256` | `YH_ALGO_AES256_YUBICO_OTP` | `40` |======================= ==== Commands [options="header"] |======================= |1.0.4 | 2.0.0 | Hex value |`YHC_CREATE_SES` | `YHC_CREATE_SESSION` | `0x03` |`YHC_AUTH_SES` | `YHC_AUTHENTICATE_SESSION` | `0x04` |`YHC_SES_MSG` | `YHC_SESSION_MESSAGE` | `0x05` |`YHC_RESET` | `YHC_RESET_DEVICE` | `0x08` |`YHC_CLOSE_SES` | `YHC_CLOSE_SESSION` | `0x40` |`YHC_STATS` | `YHC_GET_STORAGE_INFO` | `0x41` |`YHC_PUT_AUTHKEY` | `YHC_PUT_AUTHENTICATION_KEY` | `0x44` |`YHC_GEN_ASYMMETRIC_KEY` | `YHC_GENERATE_ASYMMETRIC_KEY` | `0x46` |`YHC_SIGN_DATA_PKCS1` | `YHC_SIGN_PKCS1` | `0x47` |`YHC_LIST` | `YHC_LIST_OBJECTS` | `0x48` |`YHC_GET_LOGS` | `YHC_GET_LOG_ENTRIES` | `0x4d` |`YHC_PUT_OPTION` | `YHC_SET_OPTION` | `0x4f` |`YHC_HMAC_DATA` | `YHC_SIGN_HMAC` | `0x53` |`YHC_GET_PUBKEY` | `YHC_GET_PUBLIC_KEY` | `0x54` |`YHC_SIGN_DATA_PSS` | `YHC_SIGN_PSS` | `0x55` |`YHC_SIGN_DATA_ECDSA` | `YHC_SIGN_ECDSA` | `0x56` |`YHC_DECRYPT_ECDH` | `YHC_DERIVE_ECDH` | `0x57` |`YHC_SSH_CERTIFY` | `YHC_SIGN_SSH_CERTIFICATE` | `0x5d` |`YHC_OTP_DECRYPT` | `YHC_DECRYPT_OTP` | `0x60` |`YHC_OTP_AEAD_CREATE` | `YHC_CREATE_OTP_AEAD` | `0x61` |`YHC_OTP_AEAD_RANDOM` | `YHC_RANDOMIZE_OTP_AEAD` | `0x62` |`YHC_OTP_AEAD_REWRAP` | `YHC_REWRAP_OTP_AEAD` | `0x63` |`YHC_ATTEST_ASYMMETRIC` | `YHC_SIGN_ATTESTATION_CERTIFICATE` | `0x64` |`YHC_SIGN_DATA_EDDSA` | `YHC_SIGN_EDDSA` | `0x6a` |`YHC_BLINK` | `YHC_BLINK_DEVICE` | `0x6b` | - | `YHC_CHANGE_AUTHENTICATION_KEY` | `0x6c` |======================= === Object Types [options="header"] |======================= |1.0.4 | 2.0.0 | Hex value |`authkey` | `authentication-key` | `0x02 |`asymmetric` | `asymmetric-key` | `0x03 |`hmackey` | `hmac-key` | `0x05 |`otpaeadkey` | `otp-aead-key` | `0x07 |`wrapkey` | `wrap-key` | `0x04` |======================= === Capabilities [options="header"] |======================= |1.0.4 | 2.0.0 | Hex value |`asymmetric_decrypt_ecdh` | `derive-ecdh` | `0x0b` |`asymmetric_decrypt_oaep` | `decrypt-oaep` | `0x0a` |`asymmetric_decrypt_pkcs` | `decrypt-pkcs` | `0x09` |`asymmetric_gen` | `generate-asymmetric-key` | `0x04` |`asymmetric_sign_ecdsa` | `sign-ecdsa` | `0x07` |`asymmetric_sign_eddsa` | `sign-eddsa` | `0x08` |`asymmetric_sign_pkcs` | `sign-pkcs` | `0x05` |`asymmetric_sign_pss` | `sign-pss` | `0x06` |`attest` | `sign-attestation-certificate` | `0x22` |`audit` | `get-log-entries` | `0x18` |`export_ under_wrap` | `exportable-under-wrap` | `0x10` |`export_wrapped` | `export-wrapped` | `0x0c` |`delete_asymmetric` | `delete-asymmetric-key` | `0x29` |`delete_authkey` | `delete-authentication-key` | `0x28` |`delete_hmackey` | `delete-hmac-key` | `0x2b` |`delete_opaque` | `delete-opaque` | `0x27` |`delete_otp_aead_key` | `delete-otp-aead-key` | `0x2d` |`delete_template` | `delete-template` | `0x2c` |`delete_wrapkey` | `delete-wrap-key` | `0x2a` |`generate_otp_aead_key` | `generate-otp-aead-key` | `0x24` |`generate_wrapkey` | `generate-wrap-key` | `0x0f` |`get_opaque` | `get-opaque` | `0x00` |`get_option` | `get-option` | `0x12` |`get_randomness` | `get-pseudo-random` | `0x13` |`get_template` | `get-template` | `0x1a` |`hmackey_generate` | `generate-hmac-key` | `0x15` |`hmac_data` | `sign-hmac` | `0x16` |`hmac_verify` | `verify-hmac` | `0x17` |`import_wrapped` | `import-wrapped` | `0x0d` |`otp_aead_create` | `create-otp-aead` | `0x1e` |`otp_aead_random` | `randomize-otp-aead` | `0x1f` |`otp_aead_rewrap_from` | `rewrap-from-otp-aead-key` | `0x20` |`otp_aead_rewrap_to` | `rewrap-to-otp-aead-key` | `0x21` |`otp_decrypt` | `decrypt-otp` | `0x1d` |`put_asymmetric` | `put-asymmetric-key` | `0x03` |`put_authkey` | `put-authentication-key` | `0x02` |`put_hmackey` | `put-mac-key` | `0x14` |`put_opaque` | `put-opaque` | `0x01` |`put_option` | `set-option` | `0x11` |`put_otp_aead_key` | `put-otp-aead-key` | `0x23` |`put_template` | `put-template` | `0x1b` |`put_wrapkey` | `put-wrap-key` | `0x0e` |`reset` | `reset-device` | `0x1c` |`ssh_certify` | `sign-ssh-certificate` | `0x19` |`unwrap_data` | `unwrap-data` | `0x26` |`wrap_data` | `wrap-data` | `0x25` | - | `change-authentication-key` | `0x2e` |======================= === Algorithms [options="header"] |======================= |1.0.4 | 2.0.0 | Numeric value |`yubico-aes-auth` | `aes128-yubico-authentication` | `38` |`yubico-otp-aes128` | `aes128-yubico-otp` | `37` |`yubico-otp-aes192` | `aes192-yubico-otp` | `39` |`yubico-otp-aes256` | `aes256-yubico-otp` | `40` |`opaque` | `opaque-data` | `30` |`x509-cert` | `opaque-x509-certificate` | `31` |======================= === Device Options [options="header"] |======================= |1.0.4 | 2.0.0 | Numeric value |`command_audit` | `command-audit` | `3` |`force_audit` | `force-audit` | `1` |======================= === Function Calls [options="header"] |======================= |1.0.4 | 2.0.0 |`yh_rc yh_set_verbosity(uint8_t verbosity)` | `yh_rc yh_set_verbosity(yh_connector *connector, uint8_t verbosity)` |`void yh_set_debug_output(FILE *output)` | `void yh_set_debug_output(yh_connector *connector, FILE *output)` |`yh_rc yh_connect_all(yh_connector **connectors, size_t *n_connectors, int timeout), yh_rc yh_connect_best(yh_connector **connectors, size_t n_connectors, int *idx` | `yh_rc yh_connect(yh_connector *connector, int timeout)` |`yh_rc yh_create_session_derived(yh_connector *connector, uint16_t auth_keyset_id, const uint8_t *password, size_t password_len, bool recreate_session, uint8_t *context, size_t context_len, yh_session **session)` | `yh_rc yh_create_session_derived(yh_connector *connector, uint16_t authkey_id, const uint8_t *password, size_t password_len, bool recreate_session, yh_session **session)` |`yh_rc yh_create_session(yh_connector *connector, uint16_t auth_keyset_id, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len, bool recreate_session, uint8_t *context, size_t context_len, yh_session **session)` | `yh_rc yh_create_session(yh_connector *connector, uint16_t authkey_id, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len, bool recreate_session, yh_session **session)` |`yh_rc yh_begin_create_session_ext(yh_connector *connector, uint16_t auth_keyset_id, uint8_t *context, size_t context_len, uint8_t *card_cryptogram, size_t card_cryptogram_len, yh_session **session)` | `yh_rc yh_begin_create_session_ext(yh_connector *connector, uint16_t authkey_id, uint8_t **context, uint8_t *card_cryptogram, size_t card_cryptogram_len, yh_session **session)` |`yh_rc yh_finish_create_session_ext(yh_connector *connector, yh_session *session, const uint8_t *key_senc, size_t key_senc_len, const uint8_t *key_smac, size_t key_smac_len, const uint8_t *key_srmac, size_t key_srmac_len, uint8_t *context, size_t context_len, uint8_t *card_cryptogram, size_t card_cryptogram_len)` | `yh_rc yh_finish_create_session_ext(yh_connector *connector, yh_session *session, const uint8_t *key_senc, size_t key_senc_len, const uint8_t *key_smac, size_t key_smac_len, const uint8_t *key_srmac, size_t key_srmac_len, uint8_t *card_cryptogram, size_t card_cryptogram_len)` |`yh_rc yh_authenticate_session(yh_session *session, uint8_t *context, size_t context_len)` | `yh_rc yh_authenticate_session(yh_session *session)` |`yh_rc yh_util_get_pubkey()` | `yh_rc yh_util_get_public_key()` |`yh_rc yh_util_hmac()` | `yh_rc yh_util_sign_hmac()` |`yh_rc yh_util_get_random()` | `yh_rc yh_util_get_pseudo_random()` |`yh_rc yh_util_import_key_rsa()` | `yh_rc yh_util_import_rsa_key()` |`yh_rc yh_util_import_key_ec()` | `yh_rc yh_util_import_ec_key()` |`yh_rc yh_util_import_key_ed()` | `yh_rc yh_util_import_ed_key()` |`yh_rc yh_util_import_key_hmac()` | `yh_rc yh_util_import_hmac_key()` |`yh_rc yh_util_generate_key_rsa()` | `yh_rc yh_util_generate_rsa_key()` |`yh_rc yh_util_generate_key_ec()` | `yh_rc yh_util_generate_ec_key()` |`yh_rc yh_util_generate_key_ed()` | `yh_rc yh_util_generate_ed_key()` |`yh_rc yh_util_hmac_verify()` | `yh_rc yh_util_verify_hmac()` |`yh_rc yh_util_generate_key_hmac()` | `yh_rc yh_util_generate_hmac_key()` |`yh_rc yh_util_decrypt_ecdh()` | `yh_rc yh_util_derive_ecdh()` |`yh_rc yh_util_import_key_wrap()` | `yh_rc yh_util_import_wrap_key()` |`yh_rc yh_util_generate_key_wrap()` | `yh_rc yh_util_generate_wrap_key()` |`yh_rc yh_util_get_logs()` | `yh_rc yh_util_get_log_entries()` |`yh_rc yh_util_ssh_certify()` | `yh_rc yh_util_sign_ssh_certificate()` |`yh_rc yh_util_import_authkey()` | `yh_rc yh_util_import_authentication_key_derived()` | - | `yh_rc yh_util_import_authentication_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, const yh_capabilities *delegated_capabilities, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len)` | - | `yh_rc yh_util_change_authentication_key(yh_session *session, uint16_t *key_id, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len)` | - | `yh_rc yh_util_change_authentication_key_derived(yh_session *session, uint16_t *key_id, const uint8_t *password, size_t password_len)` |`yh_rc yh_util_otp_aead_create()` | `yh_rc yh_util_create_otp_aead()` |`yh_rc yh_util_otp_aead_random()` | `yh_rc yh_util_randomize_otp_aead()` |`yh_rc yh_util_otp_decrypt()` | `yh_rc yh_util_decrypt_otp()` |`yh_rc yh_util_put_otp_aead_key()` | `yh_rc yh_util_import_otp_aead_key()` |`yh_rc yh_util_attest_asymmetric()` | `yh_rc yh_util_sign_attestation_certificate()` |`yh_rc yh_util_put_option()` | `yh_rc yh_util_set_option()` |`yh_rc yh_util_get_storage_stats()` | `yh_rc yh_util_get_storage_info()` |`yh_rc yh_util_blink()` | `yh_rc yh_util_blink_device()` |`yh_rc yh_util_reset()` | `yh_rc yh_util_reset_device()` |`yh_rc yh_capabilities_to_num()` | `yh_rc yh_string_to_capabilities()` |`yh_rc yh_num_to_capabilities()` | `yh_rc yh_capabilities_to_strings()` |`yh_rc yh_parse_domains()` | `yh_rc yh_string_to_domains()` |======================= yubihsm-shell-2.7.3/README.adoc0000644000175000017500000001054115167357110015062 0ustar aveenaveen== YubiHSM Shell This repository contains most of the components used to interact with the YubiHSM 2 at both a user-facing and programmatic level. The available components are: - link:lib/README.adoc[libyubihsm] -- C library to expose low- and high-level functions to interact with a YubiHSM - link:src/README.adoc[yubihsm-shell] -- thin wrapper around `libyubihsm` providing both an interactive and command-line interface to a YubiHSM - link:pkcs11/README.adoc[yubihsm-pkcs11] -- PKCS#11 module using `libyubihsm` - link:yhwrap/README.adoc[yubihsm-wrap] -- command-line tool to create encrypted objects (wraps) that can be imported in the YubiHSM - link:ykhsmauth/README.adoc[libykhsmauth] -- C library for using the YubiKey HSM Auth application - link:yubihsm-auth/README.adoc[yubihsm-auth] -- command-line tool to use the YubiKey HSM Auth application === Dependencies - cmake - cppcheck (optional) - gcov and lcov (optional) - gengetopt - help2man (optional) - libcrypto - libcurl - libedit - libusb - libpcsclite-dev - llvm/clang and friends - pkg-config - pre-commit === Documentation Documentation for this project and the YubiHSM2 in general can be found on Yubico's https://developers.yubico.com/YubiHSM2/[developers website]. === pre-commit This repository uses https://pre-commit.com/[pre-commit]. $ pre-commit install === Building $ mkdir build && cd build $ cmake .. $ make Note that `ninja` builds are available as well: $ mkdir build && cd build $ cmake -GNinja .. $ ninja The binaries will be located in `build` directory. To install them on the system, run the following command. Note that this step may require admin privileges on some systems (e.g. `sudo` on Linux) $ make install IMPORTANT: Building from source on Windows should be made with the source from the source release package and not directly from the cloned repository. This is due to the `gengetopt` library not being available for Windows. Manpages are built by default using `help2man`. It is possible to skip this step with: $ mkdir build && cd build $ cmake -DWITHOUT_MANPAGES=1 .. $ make It is possible to build the libraries and binaries with static linking, this can be enabled with: $ mkdir build && cd build $ cmake -DENABLE_STATIC=1 .. $ make === Linting There is a `cppcheck` target that runs the source through `cppcheck` $ make cppcheck === Testing PKCS#11 tests can be run using https://github.com/Yubico/pkcs11test[pkcs11test]. The tool must be already built, and the path to the resulting binary must be in your `PATH`, or `PKCS11TEST_PATH` must be set. The programs found in the `/examples` directory are also used as tests. The tests can be run via $ make test Or using ctest directly $ ctest By default the tests expect a local connector running at `http://localhost:12345`. A different connector for the tests can be specified by setting the `DEFAULT_CONNECTOR_URL` environment variable. For example, to run tests using direct USB (i.e., without a connector) use $ DEFAULT_CONNECTOR_URL="yhusb://" ctest If you are building `yubihsm-shell` with `ninja`, the following is available: $ ninja test The test output can be found in `.../yubihsm-shell/build/Testing/Temporary/LastTest{,sFailed}.log`. Direct command-line output can be obtained with $ ctest -V ==== Coverage Code coverage is provided courtesy of lcov and https://github.com/RWTH-HPC/CMake-codecov[CMake-codecov]. This currently only works with `make` and not with `ninja`. Enable coverage with $ cmake -DENABLE_COVERAGE=1 .. You can then build the project normally and run some executables (for example running the tests with `make test`). At this point coverage evaluation can be generated with gcov/lcov related targets. For example $ make lcov will generate a single HTML report in `./lcov/html/all_targets/index.html` === License .... Copyright 2015-2018 Yubico AB Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .... yubihsm-shell-2.7.3/lib/0000755000175000017500000000000015167357110014042 5ustar aveenaveenyubihsm-shell-2.7.3/lib/internal.h0000644000175000017500000000510215167357110016025 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YUBIHSM_INTERNAL_H #define YUBIHSM_INTERNAL_H #include "../common/platform-config.h" #include "scp.h" #include #include struct yh_session { uint16_t authkey_id; uint8_t key_enc[SCP_KEY_LEN]; uint8_t key_mac[SCP_KEY_LEN]; Scp_ctx s; uint8_t context[2 * YH_EC_P256_PUBKEY_LEN]; }; typedef struct state yh_backend; struct yh_connector { void *backend; struct backend_functions *bf; yh_backend *connection; char status_url[256]; char api_url[256]; bool has_device; uint8_t version_major; uint8_t version_minor; uint8_t version_patch; char address[32]; uint32_t port; uint32_t pid; yh_device_info device_info; }; #ifndef __WIN32 #define YH_INTERNAL __attribute__((visibility("hidden"))) #else #define YH_INTERNAL #endif void YH_INTERNAL dump_hex(FILE *file, const uint8_t *ptr, uint16_t len); void YH_INTERNAL dump_msg(FILE *file, const Msg *msg); void YH_INTERNAL dump_response(FILE *file, const Msg *msg); void YH_INTERNAL parse_status_data(char *data, yh_connector *connector); bool YH_INTERNAL parse_usb_url(const char *url, unsigned long *serial); struct backend_functions { yh_rc (*backend_init)(uint8_t verbosity, FILE *output); yh_backend *(*backend_create)(void); yh_rc (*backend_connect)(yh_connector *connector, int timeout); void (*backend_disconnect)(yh_backend *connection); yh_rc (*backend_send_msg)(yh_backend *connection, Msg *msg, Msg *response, const char *identifier); void (*backend_cleanup)(void); yh_rc (*backend_option)(yh_backend *connection, yh_connector_option opt, const void *val); void (*backend_set_verbosity)(uint8_t verbosity, FILE *output); }; #ifdef STATIC struct backend_functions YH_INTERNAL *usb_backend_functions(void); struct backend_functions YH_INTERNAL *http_backend_functions(void); #ifdef FUZZING struct backend_functions YH_INTERNAL *fuzz_backend_functions(void); #endif #else struct backend_functions *backend_functions(void); #endif #endif yubihsm-shell-2.7.3/lib/yubihsm_winhttp.c0000644000175000017500000002305015167357110017443 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include "yubihsm.h" #include "internal.h" #include "debug_lib.h" #define MAX_STR_LEN 128 #define UNUSED(x) (void) (x) struct urlComponents { bool https; wchar_t hostname[MAX_STR_LEN + 1]; int port; wchar_t path[MAX_STR_LEN + 1]; }; struct state { HINTERNET session; HINTERNET connection; yh_connector *connector; struct urlComponents status_url; struct urlComponents api_url; }; uint8_t YH_INTERNAL _yh_verbosity; FILE YH_INTERNAL *_yh_output; static bool parseUrl(const char *url, struct urlComponents *components) { wchar_t wUrl[MAX_STR_LEN * 2]; size_t len = mbstowcs(wUrl, url, _countof(wUrl)); if (len == _countof(wUrl)) { return false; } URL_COMPONENTS c = {sizeof(c)}; c.lpszHostName = components->hostname; c.dwHostNameLength = _countof(components->hostname); c.lpszUrlPath = components->path; c.dwUrlPathLength = _countof(components->path); if (!WinHttpCrackUrl(wUrl, (DWORD) len, 0, &c)) { return false; } components->https = c.nScheme == INTERNET_SCHEME_HTTPS; components->port = c.nPort; return true; } static void backend_set_verbosity(uint8_t verbosity, FILE *output) { _yh_verbosity = verbosity; _yh_output = output; } static yh_rc backend_init(uint8_t verbosity, FILE *output) { DBG_INFO("backend_init"); backend_set_verbosity(verbosity, output); return YHR_SUCCESS; } static void backend_cleanup(void) { DBG_INFO("backend_cleanup"); } static yh_backend *backend_create(void) { DBG_INFO("backend_create"); yh_backend *backend = calloc(1, sizeof(yh_backend)); if (backend) { backend->session = WinHttpOpen(L"YubiHSM WinHttp/" VERSION, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); } return backend; } static void backend_disconnect(yh_backend *connection) { DBG_INFO("backend_disconnect"); WinHttpCloseHandle(connection->connection); WinHttpCloseHandle(connection->session); free(connection); } static yh_rc backend_connect(yh_connector *connector, int timeout) { DBG_INFO("backend_connect"); if (timeout == 0) { // TODO: what does winhttp do if it gets timeout 0? timeout = 300; } yh_backend *backend = connector->connection; backend->connector = connector; if (!parseUrl(connector->status_url, &backend->status_url)) { DBG_ERR("Status URL parsing failed."); return YHR_INVALID_PARAMETERS; } if (!parseUrl(connector->api_url, &backend->api_url)) { DBG_ERR("Api URL parsing failed."); return YHR_INVALID_PARAMETERS; } DBG_INFO("Connecting to %s", connector->status_url); backend->connection = WinHttpConnect(backend->session, backend->status_url.hostname, backend->status_url.port, 0); if (!backend->connection) { DBG_ERR("Failed connecting to %s", connector->status_url); return YHR_CONNECTOR_ERROR; } HINTERNET request = WinHttpOpenRequest(backend->connection, L"GET", backend->status_url.path, NULL, NULL, WINHTTP_DEFAULT_ACCEPT_TYPES, backend->status_url.https ? WINHTTP_FLAG_SECURE : 0); if (!request) { DBG_ERR("Failed opening request to %s", connector->status_url); return YHR_CONNECTOR_ERROR; } if (timeout > 0) { if (!WinHttpSetTimeouts(request, timeout * 1000, timeout * 1000, timeout * 1000, timeout * 1000)) { DBG_ERR("Failed setting timeouts."); } } DBG_INFO("Sending request to %s", connector->status_url); if (!WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) { DBG_ERR("Failed sending request to %s", connector->status_url); WinHttpCloseHandle(request); return YHR_CONNECTOR_ERROR; } if (!WinHttpReceiveResponse(request, 0)) { DBG_ERR("Failed receiving response from %s", connector->status_url); WinHttpCloseHandle(request); return YHR_CONNECTOR_ERROR; } DWORD dwStatusCode, dwSize = sizeof(dwStatusCode); if (!WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &dwStatusCode, &dwSize, WINHTTP_NO_HEADER_INDEX)) { DBG_ERR("Failed retrieveing status code from %s", backend->connector->status_url); WinHttpCloseHandle(request); return YHR_CONNECTOR_ERROR; } if (dwStatusCode != 200) { DBG_ERR("Invalid status code %u received from %s", dwStatusCode, backend->connector->status_url); WinHttpCloseHandle(request); return YHR_CONNECTOR_ERROR; } char buf[256]; DWORD offs = 0, bytes; while (WinHttpReadData(request, buf + offs, sizeof(buf) - offs, &bytes)) { if (bytes == 0) break; offs += bytes; if (offs >= sizeof(buf)) break; } DBG_INFO("Read %u bytes from %s", offs, connector->status_url); WinHttpCloseHandle(request); parse_status_data(buf, connector); if (!connector->has_device) { DBG_ERR("Response from %s indicates no device is present", connector->status_url); return YHR_CONNECTOR_NOT_FOUND; } return YHR_SUCCESS; } static yh_rc backend_send_msg(yh_backend *backend, Msg *msg, Msg *response, const char *identifier) { uint16_t raw_len = ntohs(msg->st.len) + 3; wchar_t hsm_identifier[64]; wchar_t *headers = WINHTTP_NO_ADDITIONAL_HEADERS; DWORD headers_len = 0; if (identifier != NULL && strlen(identifier) > 0 && strlen(identifier) < 32) { headers_len = swprintf(hsm_identifier, 64, L"YubiHSM-Session: %hs", identifier); headers = hsm_identifier; } HINTERNET request = WinHttpOpenRequest(backend->connection, L"POST", backend->api_url.path, NULL, NULL, WINHTTP_DEFAULT_ACCEPT_TYPES, backend->api_url.https ? WINHTTP_FLAG_SECURE : 0); if (!request) { DBG_ERR("Failed opening request to %s", backend->connector->api_url); return YHR_CONNECTOR_ERROR; } // TODO: replace these magic numbers with something better. // of note here is the 250s timeout on receive, generating rsa4096 might take // some time.. if (!WinHttpSetTimeouts(request, 30 * 1000, 30 * 1000, 250 * 1000, 250 * 1000)) { DBG_ERR("Failed setting timeouts."); } DBG_INFO("Sending %u bytes to %s", raw_len, backend->connector->api_url); if (!WinHttpSendRequest(request, headers, headers_len, msg->raw, raw_len, raw_len, 0)) { DBG_ERR("Failed sending request to %s", backend->connector->api_url); WinHttpCloseHandle(request); return YHR_CONNECTOR_ERROR; } if (!WinHttpReceiveResponse(request, 0)) { DBG_ERR("Failed receiving response from %s", backend->connector->api_url); WinHttpCloseHandle(request); return YHR_CONNECTOR_ERROR; } DWORD dwStatusCode, dwSize = sizeof(dwStatusCode); if (!WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &dwStatusCode, &dwSize, WINHTTP_NO_HEADER_INDEX)) { DBG_ERR("Failed retrieveing status code from %s", backend->connector->api_url); WinHttpCloseHandle(request); return YHR_CONNECTOR_ERROR; } if (dwStatusCode != 200) { DBG_ERR("Invalid status code %u received from %s", dwStatusCode, backend->connector->api_url); WinHttpCloseHandle(request); return YHR_CONNECTOR_ERROR; } DWORD offs = 0, bytes; while (WinHttpReadData(request, response->raw + offs, sizeof(response->raw) - offs, &bytes)) { if (bytes == 0) break; offs += bytes; if (offs >= sizeof(response->raw)) break; } DBG_INFO("Read %u bytes from %s", offs, backend->connector->api_url); WinHttpCloseHandle(request); if (offs < 3) { DBG_ERR("Not enough data received; %lu", offs); return YHR_WRONG_LENGTH; } if (ntohs(response->st.len) != offs - 3) { DBG_ERR("Wrong length received, %d vs %lu", ntohs(response->st.len), offs); return YHR_WRONG_LENGTH; } return YHR_SUCCESS; } static yh_rc backend_option(yh_backend *connection, yh_connector_option opt, const void *val) { UNUSED(connection); UNUSED(opt); UNUSED(val); DBG_ERR("Backend options not (yet?) supported with winhttp"); return YHR_CONNECTOR_ERROR; } static struct backend_functions f = {backend_init, backend_create, backend_connect, backend_disconnect, backend_send_msg, backend_cleanup, backend_option, backend_set_verbosity}; #ifdef STATIC struct backend_functions *http_backend_functions(void) { #else struct backend_functions *backend_functions(void) { #endif return &f; } yubihsm-shell-2.7.3/lib/lib_util.c0000644000175000017500000001162215167357110016013 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include "yubihsm.h" #include "internal.h" #include "debug_lib.h" #ifdef __WIN32 #include #else #include #endif #define STATUS_STR "status=" #define VERSION_STR "version=" #define PID_STR "pid=" #define ADDRESS_STR "address=" #define PORT_STR "port=" #ifdef _MSVC #define strtok_r strtok_s #endif void dump_hex(FILE *file, const uint8_t *ptr, uint16_t len) { uint32_t i; for (i = 0; i < len; i++) { if (i && !(i % 8)) { fprintf(file, " "); } fprintf(file, "%02x", ptr[i]); } } void dump_msg(FILE *file, const Msg *msg) { fprintf(file, "SEND >> (03 + %04d) %02x %04x ", ntohs(msg->st.len), msg->st.cmd, ntohs(msg->st.len)); dump_hex(file, msg->st.data, ntohs(msg->st.len)); fprintf(file, "\n"); } void dump_response(FILE *file, const Msg *msg) { fprintf(file, "RECV << (03 + %04d) %02x %04x ", ntohs(msg->st.len), msg->st.cmd, ntohs(msg->st.len)); dump_hex(file, msg->st.data, ntohs(msg->st.len)); fprintf(file, " \n"); } void parse_status_data(char *data, yh_connector *connector) { char *saveptr = NULL; char *str = NULL; while ((str = strtok_r(str ? NULL : data, "\n", &saveptr))) { if (strncmp(str, STATUS_STR, strlen(STATUS_STR)) == 0) { if (strcmp(str + strlen(STATUS_STR), "OK") == 0) { connector->has_device = true; } else { connector->has_device = false; } } else if (strncmp(str, VERSION_STR, strlen(VERSION_STR)) == 0) { unsigned long v_maj = 0; unsigned long v_min = 0; unsigned long v_pat = 0; str = str + strlen(VERSION_STR); if (sscanf(str, "%lu.%lu.%lu", &v_maj, &v_min, &v_pat) <= 3) { DBG_ERR("Unable to parse version string"); continue; } connector->version_major = v_maj; connector->version_minor = v_min; connector->version_patch = v_pat; } else if (strncmp(str, PID_STR, strlen(PID_STR)) == 0) { char *endptr; unsigned long pid; str = str + strlen(PID_STR); errno = 0; pid = strtoul(str, &endptr, 0); if ((errno == ERANGE && pid == ULONG_MAX) || (errno != 0 && pid == 0)) { continue; } if (endptr == str || pid == 0) { continue; } connector->pid = pid; } else if (strncmp(str, ADDRESS_STR, strlen(ADDRESS_STR)) == 0) { strncpy(connector->address, str + strlen(ADDRESS_STR), sizeof(connector->address) - 1); } else if (strncmp(str, PORT_STR, strlen(PORT_STR)) == 0) { char *endptr; unsigned long port; str = str + strlen(PORT_STR); errno = 0; port = strtoul(str, &endptr, 0); if ((errno == ERANGE && port == ULONG_MAX) || (errno != 0 && port == 0)) { continue; } if (endptr == str || port == 0) { continue; } connector->port = port; } } DBG_INFO("response from connector"); DBG_INFO("has device: %s", connector->has_device == true ? "yes" : "no"); DBG_INFO("version: %d.%d.%d", connector->version_major, connector->version_minor, connector->version_patch); DBG_INFO("pid: %u", connector->pid); DBG_INFO("address: %s", connector->address); DBG_INFO("port: %u", connector->port); return; } bool parse_usb_url(const char *url, unsigned long *serial) { if (strncmp(url, YH_USB_URL_SCHEME, strlen(YH_USB_URL_SCHEME)) == 0) { url += strlen(YH_USB_URL_SCHEME); char *copy = strdup(url); char *str = NULL; char *saveptr = NULL; // if we don't find a serial we still want to return serial 0 *serial = 0; while ((str = strtok_r(str ? NULL : copy, "&", &saveptr))) { if (strncmp(str, "serial=", strlen("serial=")) == 0) { char *endptr; str += strlen("serial="); errno = 0; *serial = strtoul(str, &endptr, 10); if ((errno == ERANGE && *serial == ULONG_MAX) || endptr == str || *endptr != '\0' || (errno != 0 && *serial == 0)) { *serial = 0; DBG_ERR("Failed to parse serial argument: '%s'.", str); free(copy); return false; } } else { DBG_INFO("Unknown USB option '%s'.", str); } } DBG_INFO("USB url parsed with serial decimal %lu.", *serial); free(copy); return true; } return false; } yubihsm-shell-2.7.3/lib/yubihsm_usb.c0000644000175000017500000000770215167357110016545 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "../common/platform-config.h" #ifdef __WIN32 #include #else #include #endif #include "yubihsm.h" #include "internal.h" #include "yubihsm_usb.h" #include "debug_lib.h" #define UNUSED(x) (void) (x) #ifndef STATIC uint8_t YH_INTERNAL _yh_verbosity; FILE YH_INTERNAL *_yh_output; #endif static void backend_set_verbosity(uint8_t verbosity, FILE *output) { _yh_verbosity = verbosity; _yh_output = output; } static yh_rc backend_init(uint8_t verbosity, FILE *output) { DBG_INFO("backend_init"); backend_set_verbosity(verbosity, output); return YHR_SUCCESS; } static yh_rc backend_connect(yh_connector *connector, int timeout) { DBG_INFO("backend_connect"); unsigned long serial = 0; yh_rc ret = YHR_CONNECTOR_ERROR; yh_backend *backend = NULL; UNUSED(timeout); if (parse_usb_url(connector->api_url, &serial) == false) { DBG_ERR("Failed to parse URL: '%s'", connector->api_url); goto out; } backend = connector->connection; usb_set_serial(backend, serial); if (usb_open_device(backend) == false) { DBG_ERR("No device returned"); goto out; } ret = YHR_SUCCESS; connector->has_device = 1; out: return ret; } static void backend_disconnect(yh_backend *connection) { DBG_INFO("backend_disconnect"); usb_destroy(&connection); } static yh_rc backend_send_msg(yh_backend *connection, Msg *msg, Msg *response, const char *identifier) { int32_t trf_len = ntohs(msg->st.len) + 3; yh_rc ret = YHR_GENERIC_ERROR; unsigned long read_len = 0; UNUSED(identifier); for (int i = 0; i <= 1; i++) { if (ret != YHR_GENERIC_ERROR) { DBG_INFO("Reconnecting device"); usb_close(connection); if (usb_open_device(connection) == false) { DBG_ERR("Failed reconnecting device"); return YHR_CONNECTOR_ERROR; } } if (usb_write(connection, msg->raw, trf_len) == 0) { ret = YHR_CONNECTOR_ERROR; DBG_ERR("USB write failed"); continue; } read_len = sizeof(response->raw); if (usb_read(connection, response->raw, &read_len) == 0) { ret = YHR_CONNECTOR_ERROR; DBG_ERR("USB read failed"); continue; } ret = YHR_SUCCESS; break; } if (ret != YHR_SUCCESS) { return ret; } if (read_len < 3) { DBG_ERR("Not enough data received; %lu", read_len); return YHR_WRONG_LENGTH; } if (ntohs(response->st.len) != read_len - 3) { DBG_ERR("Wrong length received, %d vs %lu", ntohs(response->st.len), read_len); return YHR_WRONG_LENGTH; } return YHR_SUCCESS; } static void backend_cleanup(void) { DBG_INFO("backend_cleanup"); } static yh_rc backend_option(yh_backend *connection, yh_connector_option opt, const void *val) { UNUSED(connection); UNUSED(opt); UNUSED(val); DBG_ERR("Backend options not (yet?) supported for USB"); return YHR_CONNECTOR_ERROR; } static struct backend_functions f = {backend_init, backend_create, backend_connect, backend_disconnect, backend_send_msg, backend_cleanup, backend_option, backend_set_verbosity}; #ifdef STATIC struct backend_functions *usb_backend_functions(void) { #else struct backend_functions *backend_functions(void) { #endif return &f; } yubihsm-shell-2.7.3/lib/fuzz/0000755000175000017500000000000015167357110015040 5ustar aveenaveenyubihsm-shell-2.7.3/lib/fuzz/fuzz_send_plain_msg.cc0000644000175000017500000000167615167357110021421 0ustar aveenaveen#include #include "debug_lib.h" extern "C" { #include "yubihsm.h" uint8_t *backend_data; size_t backend_data_len; } #include "yubihsm_fuzz.h" yh_connector *connector; static bool initialize() { yh_rc rc = yh_init_connector("yhfuzz://yubihsm_fuzz", &connector); assert(rc == YHR_SUCCESS); rc = yh_connect(connector, 0); assert(rc == YHR_SUCCESS); return true; } extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { static bool is_initialized = initialize(); if (size < 2) { return 0; } size_t data_len = data[0]; size_t response_len = data[1]; backend_data = data + 2; backend_data_len = size - 2; uint8_t *hsm_data = new uint8_t[data_len]; uint8_t *response = new uint8_t[response_len]; yh_cmd response_cmd; yh_send_plain_msg(connector, YHC_ECHO, hsm_data, data_len, &response_cmd, response, &response_len); delete[] hsm_data; delete[] response; return 0; } yubihsm-shell-2.7.3/lib/fuzz/yubihsm_fuzz.h0000644000175000017500000000044515167357110017752 0ustar aveenaveen#ifndef _FUZZER_H #define _FUZZER_H #ifdef __cplusplus extern "C" { #endif #include #include extern yh_session *fuzz_session; #define FUZZ_BACKEND_PASSWORD "fuzzfuzz" extern uint8_t *backend_data; extern size_t backend_data_len; #ifdef __cplusplus } #endif #endif yubihsm-shell-2.7.3/lib/fuzz/yubihsm_fuzz.cc0000644000175000017500000003130215167357110020104 0ustar aveenaveen/* * Copyright 2015-2021 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "scp.h" #include #include #include using namespace std; extern "C" { #include "yubihsm.h" #include "internal.h" #include "debug_lib.h" #include "../common/platform-config.h" #include "../common/pkcs5.h" #include "../common/hash.h" #include "../aes_cmac/aes.h" #include "../aes_cmac/aes_cmac.h" } #include "yubihsm_fuzz.h" static void process_msg(Msg *msg, Msg *response); static bool compute_mac(Scp_ctx *s, uint8_t *key, Msg *msg, size_t raw_msg_len, int host_order_len, uint8_t *mac); struct state {}; static uint8_t key_enc[SCP_KEY_LEN]; static uint8_t key_mac[SCP_KEY_LEN]; #define FUZZ_MAX_SESSIONS 10 static Scp_ctx sessions[FUZZ_MAX_SESSIONS]; static uint8_t init_sessions[FUZZ_MAX_SESSIONS]; static int current_session_id = -1; static int get_free_session_slot() { for (int i = 0; i < FUZZ_MAX_SESSIONS; i++) { if (init_sessions[i] == 0) { return i; } } return -1; } static int is_session_slot_initialized(int slot) { if (slot < 0 || slot >= FUZZ_MAX_SESSIONS) { return 0; } return init_sessions[slot]; } static bool compute_mac(Scp_ctx *s, uint8_t *key, Msg *msg, size_t raw_msg_len, int host_order_len, uint8_t *mac) { aes_context aes_ctx = {0}; aes_cmac_context_t cmac_ctx = {0}; #pragma pack(push, 1) struct { uint8_t mac_chaining_value[SCP_PRF_LEN]; Msg msg; } mac_msg = {0}; #pragma pack(pop) if (raw_msg_len > sizeof(Msg)) { return false; } memcpy(mac_msg.mac_chaining_value, s->mac_chaining_value, SCP_PRF_LEN); memcpy(&mac_msg.msg, msg, raw_msg_len); if (host_order_len) { // macced len field is in network byte order mac_msg.msg.st.len = htons(mac_msg.msg.st.len); } // this is the size of the raw package with everything to be macced size_t macced_data_len = SCP_PRF_LEN + raw_msg_len; memset(&aes_ctx, 0, sizeof(aes_ctx)); aes_set_key(key, SCP_KEY_LEN, &aes_ctx); aes_cmac_init(&aes_ctx, &cmac_ctx); aes_cmac_encrypt(&cmac_ctx, (uint8_t *) &mac_msg, macced_data_len, mac); aes_cmac_destroy(&cmac_ctx); aes_destroy(&aes_ctx); return true; } static void process_msg(Msg *msg, Msg *response) { aes_context aes_ctx = {0}; msg->st.len = ntohs(msg->st.len); switch (msg->st.cmd) { case YHC_CREATE_SESSION: { /* The data (i.e. msg->st.data) associated with a create session request * is authentication key ID -> first SCP_AUTHKEY_ID_LEN bytes host * challenge -> the rest of the msg->st.len bytes See also * yh_begin_create_session(). */ if (msg->st.len < SCP_AUTHKEY_ID_LEN) { response->st.cmd = YHC_ERROR; break; } // Check if a new session can be created or we reached the max number of // open sessions. int session_id = get_free_session_slot(); if (session_id < 0) { response->st.cmd = YHC_ERROR; break; } memset(&sessions[session_id], 0, sizeof(Scp_ctx)); uint16_t host_challenge_len = msg->st.len - SCP_AUTHKEY_ID_LEN; /* Setting up the session context used later on to calculate the card * cryptogram. See also yh_begin_create_session(). The session context * contains the host challenge the card challenge (assumed 0s here) */ uint8_t session_context[2 * YH_EC_P256_PUBKEY_LEN] = {0}; if (host_challenge_len > sizeof(session_context)) { response->st.cmd = YHC_ERROR; break; } memcpy(session_context, msg->st.data + SCP_AUTHKEY_ID_LEN, host_challenge_len); // Derive the SCP context s_env, s_mac and s_rmac keys. compute_cryptogram(key_enc, SCP_KEY_LEN, SCP_S_ENC_DERIVATION, session_context, SCP_KEY_LEN * 8, sessions[session_id].s_enc); compute_cryptogram(key_mac, SCP_KEY_LEN, SCP_S_MAC_DERIVATION, session_context, SCP_KEY_LEN * 8, sessions[session_id].s_mac); compute_cryptogram(key_mac, SCP_KEY_LEN, SCP_S_RMAC_DERIVATION, session_context, SCP_KEY_LEN * 8, sessions[session_id].s_rmac); /* Calculation of the card cryptogram. * type = SCP_CARD_CRYPTOGRAM * L = SCP_CARD_CRYPTO_LEN * 8 * context = the session context */ uint8_t calculated_card_cryptogram[SCP_PRF_LEN] = {0}; compute_cryptogram(sessions[session_id].s_mac, SCP_KEY_LEN, SCP_CARD_CRYPTOGRAM, session_context, SCP_CARD_CRYPTO_LEN * 8, calculated_card_cryptogram); /* The expected response is * session id - 1 byte * the card challenge - SCP_CARD_CHAL_LEN * the resulting cryptogram - SCP_CARD_CRYPTO_LEN */ response->st.cmd = YHC_CREATE_SESSION_R; response->st.len = 1 + SCP_CARD_CHAL_LEN + SCP_CARD_CRYPTO_LEN; response->st.data[0] = session_id; memcpy(response->st.data + 1 + SCP_CARD_CHAL_LEN, calculated_card_cryptogram, SCP_CARD_CRYPTO_LEN); init_sessions[session_id] = 1; break; } case YHC_AUTHENTICATE_SESSION: { int session_id = msg->st.data[0]; uint8_t mac[SCP_PRF_LEN] = {0}; if (is_session_slot_initialized(session_id) == 0) { response->st.cmd = YHC_ERROR; break; } Scp_ctx *s = &sessions[session_id]; if (!compute_mac(s, s->s_mac, msg, 3 + msg->st.len - SCP_MAC_LEN, 1, mac)) { response->st.cmd = YHC_ERROR; break; } // update the session mac chaining value memcpy(s->mac_chaining_value, mac, SCP_PRF_LEN); if (memcmp(mac, &msg->st.data[msg->st.len - SCP_MAC_LEN], SCP_MAC_LEN)) { DBG_ERR("invalid mac during YHC_AUTHENTICATE_SESSION"); } response->st.cmd = YHC_AUTHENTICATE_SESSION_R; response->st.len = SCP_MAC_LEN; compute_mac(s, s->s_rmac, response, 3, 1, mac); // copy the mac into the response struct and update the length memcpy(response->st.data, mac, SCP_MAC_LEN); increment_ctr(s->ctr, SCP_PRF_LEN); break; } case YHC_CLOSE_SESSION: { if (current_session_id != -1 && is_session_slot_initialized(current_session_id) == 0) { response->st.cmd = YHC_ERROR; break; } memset(&sessions[current_session_id], 0, sizeof(Scp_ctx)); init_sessions[current_session_id] = 0; response->st.cmd = YHC_CLOSE_SESSION_R; break; } case YHC_SESSION_MESSAGE: { uint8_t encrypted_ctr[AES_BLOCK_SIZE] = {0}; Msg inner_msg = {0}, inner_response = {0}; uint8_t mac[SCP_PRF_LEN] = {0}; uint16_t inner_response_padded_len = {0}; current_session_id = msg->st.data[0]; if (is_session_slot_initialized(current_session_id) == 0) { response->st.cmd = YHC_ERROR; break; } Scp_ctx *s = &sessions[current_session_id]; if (compute_mac(s, s->s_mac, msg, 3 + msg->st.len - SCP_MAC_LEN, 1, mac) == false) { response->st.cmd = YHC_ERROR; break; } // update the session mac chaining value memcpy(s->mac_chaining_value, mac, SCP_PRF_LEN); if (memcmp(mac, &msg->st.data[msg->st.len - SCP_MAC_LEN], SCP_MAC_LEN)) { DBG_ERR("invalid mac during YHC_AUTHENTICATE_SESSION"); } aes_set_key(s->s_enc, SCP_KEY_LEN, &aes_ctx); aes_encrypt(s->ctr, encrypted_ctr, &aes_ctx); increment_ctr(s->ctr, SCP_PRF_LEN); // decrypt the message aes_cbc_decrypt(msg->st.data + 1, inner_msg.raw, msg->st.len - SCP_MAC_LEN - 1, encrypted_ctr, &aes_ctx); /* recursive call to process the inner message * * if the inner_msg has command YHC_CLOSE_SESSION, then the * session object will be zeroed and we will lose access to * the associated key material, and the call to compute_mac * will fail. * * for that situation, we should cache the session object before * processing the YHC_CLOSE_SESSION command. */ process_msg(&inner_msg, &inner_response); // set the response type response->st.cmd = YHC_SESSION_MESSAGE_R; // copy over the session id to the expected value response->st.data[0] = msg->st.data[0]; // encrypt the inner response inner_response_padded_len = ntohs(inner_response.st.len) + 3; aes_add_padding(inner_response.raw, sizeof(inner_response.raw), &inner_response_padded_len); aes_cbc_encrypt(inner_response.raw, response->st.data + 1, inner_response_padded_len, encrypted_ctr, &aes_ctx); response->st.len = 1 + inner_response_padded_len; aes_destroy(&aes_ctx); // authenticate the response response->st.len += SCP_MAC_LEN; if (response->st.len + 3 > sizeof(Msg)) { // there is no place to add the mac at the end of the message response->st.cmd = YHC_ERROR; break; } if (compute_mac(s, s->s_rmac, response, 3 + response->st.len - SCP_MAC_LEN, 1, mac) == false) { response->st.cmd = YHC_ERROR; break; } // copy the mac into the response struct and update the length memcpy(response->st.data + response->st.len - SCP_MAC_LEN, mac, SCP_MAC_LEN); current_session_id = -1; break; } default: /* inner messages such as YHC_GENERATE_ASYMMETRIC_KEY * here put some fuzzer data which gets decrypted and processed on the * host side */ uint8_t size_byte = 0; if (backend_data_len > 0) { size_byte = backend_data[0]; backend_data += 1; backend_data_len -= 1; } // limit size_byte artificially if (size_byte > SCP_MSG_BUF_SIZE - 32) { size_byte %= SCP_MSG_BUF_SIZE - 32; } response->st.len = size_byte; if (size_byte > backend_data_len) { size_byte = backend_data_len; } memcpy(response->st.data, backend_data, size_byte); backend_data += size_byte; backend_data_len -= size_byte; break; } response->st.len = htons(response->st.len); } static void fuzz_backend_set_verbosity(uint8_t verbosity, FILE *output) { _yh_verbosity = verbosity; _yh_output = output; } static yh_rc fuzz_backend_init(uint8_t verbosity, FILE *output) { fuzz_backend_set_verbosity(verbosity, output); uint8_t keys[2 * SCP_KEY_LEN] = {0}; pkcs5_pbkdf2_hmac((const uint8_t *) FUZZ_BACKEND_PASSWORD, strlen(FUZZ_BACKEND_PASSWORD), (const uint8_t *) YH_DEFAULT_SALT, strlen(YH_DEFAULT_SALT), YH_DEFAULT_ITERS, _SHA256, keys, sizeof(keys)); memcpy(key_enc, keys, SCP_KEY_LEN); memcpy(key_mac, keys + SCP_KEY_LEN, SCP_KEY_LEN); return YHR_SUCCESS; } static yh_backend *fuzz_backend_create(void) { yh_backend *backend = (yh_backend *) calloc(1, sizeof(yh_backend)); return backend; } static yh_rc fuzz_backend_connect(yh_connector *connector, int timeout) { (void) connector; (void) timeout; connector->has_device = 1; return YHR_SUCCESS; } static void fuzz_backend_disconnect(yh_backend *connection) { free(connection); } static yh_rc fuzz_backend_send_msg(yh_backend *connection, Msg *msg, Msg *response, const char *identifier) { (void) connection; (void) identifier; memset(response->raw, 0, sizeof(response->raw)); process_msg(msg, response); return YHR_SUCCESS; } static void fuzz_backend_cleanup(void) {} static yh_rc fuzz_backend_option(yh_backend *connection, yh_connector_option opt, const void *val) { (void) connection; (void) opt; (void) val; return YHR_CONNECTOR_ERROR; } static struct backend_functions f = {fuzz_backend_init, fuzz_backend_create, fuzz_backend_connect, fuzz_backend_disconnect, fuzz_backend_send_msg, fuzz_backend_cleanup, fuzz_backend_option, fuzz_backend_set_verbosity}; #ifdef STATIC extern "C" struct backend_functions *fuzz_backend_functions(void) { #else extern "C" struct backend_functions *backend_functions(void) { #endif return &f; } yubihsm-shell-2.7.3/lib/fuzz/fuzz_send_secure_msg.cc0000644000175000017500000000267515167357110021604 0ustar aveenaveen#include #include #include "debug_lib.h" extern "C" { #include "yubihsm.h" uint8_t *backend_data; size_t backend_data_len; yh_session *fuzz_session; } #include "yubihsm_fuzz.h" yh_connector *connector; static bool initialize() { yh_rc rc = yh_init_connector("yhfuzz://yubihsm_fuzz", &connector); assert(rc == YHR_SUCCESS); rc = yh_connect(connector, 0); assert(rc == YHR_SUCCESS); return true; } extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { static bool is_initialized = initialize(); yh_rc yrc = YHR_GENERIC_ERROR; if (size < 2) { return 0; } yrc = yh_create_session_derived(connector, 1, (const uint8_t *) FUZZ_BACKEND_PASSWORD, strlen(FUZZ_BACKEND_PASSWORD), false, &fuzz_session); assert(yrc == YHR_SUCCESS); size_t data_len = data[0]; size_t response_len = data[1]; backend_data = data + 2; backend_data_len = size - 2; uint8_t *hsm_data = new uint8_t[data_len]; uint8_t *response = new uint8_t[response_len]; yh_cmd response_cmd; yh_send_secure_msg(fuzz_session, YHC_ECHO, hsm_data, data_len, &response_cmd, response, &response_len); yrc = yh_util_close_session(fuzz_session); assert(yrc == YHR_SUCCESS); yrc = yh_destroy_session(&fuzz_session); assert(yrc == YHR_SUCCESS); delete[] hsm_data; delete[] response; return 0; } yubihsm-shell-2.7.3/lib/yubihsm_libusb.c0000644000175000017500000001234315167357110017231 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "yubihsm.h" #include "internal.h" #include "yubihsm_usb.h" #include "debug_lib.h" #ifdef NO_LIBUSB_STRERROR #define libusb_strerror(x) libusb_error_name(x) #endif struct state { libusb_context *ctx; libusb_device_handle *handle; unsigned long serial; }; void usb_set_serial(yh_backend *state, unsigned long serial) { state->serial = serial; } void usb_close(yh_backend *state) { if (state && state->handle) { libusb_release_interface(state->handle, 0); libusb_close(state->handle); state->handle = NULL; } } void usb_destroy(yh_backend **state) { if (state && *state) { usb_close(*state); if ((*state)->ctx) { libusb_exit((*state)->ctx); (*state)->ctx = NULL; } free(*state); *state = NULL; } } yh_backend *backend_create(void) { DBG_INFO("backend_create"); yh_backend *backend = calloc(1, sizeof(yh_backend)); if (backend) { if (libusb_init(&backend->ctx) != 0) { free(backend); backend = NULL; } } return backend; } bool usb_open_device(yh_backend *backend) { libusb_device **list; libusb_device_handle *h = NULL; ssize_t cnt = libusb_get_device_list(backend->ctx, &list); if (backend->handle) { usb_close(backend); } if (cnt < 0) { DBG_ERR("Failed to get device list: %s", libusb_strerror(cnt)); return NULL; } for (ssize_t i = 0; i < cnt; i++) { struct libusb_device_descriptor desc; int ret = libusb_get_device_descriptor(list[i], &desc); if (ret != 0) { DBG_INFO("Failed to get descriptor for device %zd: %s", i, libusb_strerror(ret)); continue; } if (desc.idVendor == YH_VID && desc.idProduct == YH_PID) { ret = libusb_open(list[i], &h); if (ret != 0 || h == NULL) { DBG_INFO("Failed to open device for index %zd: %s", i, libusb_strerror(ret)); continue; } if (backend->serial != 0) { unsigned char data[16] = {0}; ret = libusb_get_string_descriptor_ascii(h, desc.iSerialNumber, data, sizeof(data)); unsigned long devSerial = strtoul((char *) data, NULL, 10); if (devSerial != backend->serial) { DBG_INFO("Device %zd has serial %lu, not matching searched %lu", i, devSerial, backend->serial); goto next; } } ret = libusb_claim_interface(h, 0); if (ret != 0) { DBG_ERR("Failed to claim interface: %s of device %zd", libusb_strerror(ret), i); goto next; } break; next: libusb_close(h); h = NULL; } } libusb_free_device_list(list, 1); backend->handle = h; if (h) { // we set up a dummy read with a 1ms timeout here. The reason for doing this // is that there might be data left in th e device buffers from earlier // transactions, this should flush it. unsigned char buf[YH_MSG_BUF_SIZE]; int transferred = 0; if (libusb_bulk_transfer(h, 0x81, buf, sizeof(buf), &transferred, 1) == 0) { DBG_INFO("%d bytes of stale data read from device", transferred); } return true; } else { return false; } } int usb_write(yh_backend *state, unsigned char *buf, long unsigned len) { int transferred = 0; if (state->handle == NULL) { DBG_ERR("Handle is not connected"); return 0; } /* TODO: does this need to loop and transmit several times? */ int ret = libusb_bulk_transfer(state->handle, 0x01, buf, len, &transferred, 0); DBG_INFO("Write of %lu %d, ret %d", len, transferred, ret); if (ret != 0) { DBG_ERR("Failed usb_write with ret: %d (%s)", ret, libusb_strerror(ret)); return 0; } else if (transferred != (int) len) { DBG_ERR("Transferred did not match len of write %d-%lu", transferred, len); return 0; } if (len % 64 == 0) { transferred = 0; /* this writes the ZLP */ ret = libusb_bulk_transfer(state->handle, 0x01, buf, 0, &transferred, 0); if (ret != 0) { DBG_ERR("Failed usb_write ZLP with ret: %d (%s)", ret, libusb_strerror(ret)); return 0; } } return 1; } int usb_read(yh_backend *state, unsigned char *buf, unsigned long *len) { int transferred = 0; int ret; if (state->handle == NULL) { DBG_ERR("Handle is not connected"); return 0; } DBG_INFO("Doing usb read"); /* TODO: does this need to loop for all data?*/ ret = libusb_bulk_transfer(state->handle, 0x81, buf, *len, &transferred, 0); if (ret != 0) { DBG_ERR("Failed usb_read with ret: %d (%s)", ret, libusb_strerror(ret)); return 0; } DBG_INFO("Read, transfer %d", transferred); *len = transferred; return 1; } yubihsm-shell-2.7.3/lib/version.rc.in0000644000175000017500000000215615167357110016466 0ustar aveenaveen #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM Interface Library" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "libyubihsm.dll" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "libyubihsm.dll" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.7.3/lib/version_winusb.rc.in0000644000175000017500000000217015167357110020051 0ustar aveenaveen #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM USB backend Library" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "libyubihsm_usb.dll" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "libyubihsm_usb.dll" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.7.3/lib/yubihsm_usb.h0000644000175000017500000000234115167357110016544 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YUBIHSM_USB_H #define YUBIHSM_USB_H #ifndef __WIN32 #define YH_INTERNAL __attribute__((visibility("hidden"))) #else #define YH_INTERNAL #endif void YH_INTERNAL usb_close(yh_backend *state); void YH_INTERNAL usb_destroy(yh_backend **state); yh_backend YH_INTERNAL *backend_create(void); bool YH_INTERNAL usb_open_device(yh_backend *backend); int YH_INTERNAL usb_write(yh_backend *state, unsigned char *buf, long unsigned len); int YH_INTERNAL usb_read(yh_backend *state, unsigned char *buf, long unsigned *len); void YH_INTERNAL usb_set_serial(yh_backend *state, unsigned long serial); #endif yubihsm-shell-2.7.3/lib/data_compress.c0000644000175000017500000000527515167357110017043 0ustar aveenaveen/* * Copyright 2024 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "data_compress.h" #include "debug_lib.h" int compress_data(const uint8_t *data, size_t data_len, uint8_t *compressed_data, size_t *compressed_data_len) { z_stream zs = {0}; zs.zalloc = Z_NULL; zs.zfree = Z_NULL; zs.opaque = Z_NULL; zs.avail_in = (uInt) data_len; zs.next_in = (Bytef *) data; zs.avail_out = (uInt) *compressed_data_len; zs.next_out = (Bytef *) compressed_data; int res = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS | 16, 8, Z_DEFAULT_STRATEGY); if (res != Z_OK) { DBG_ERR("Failed to initialize data compression. ZLIB error code: %d (%s)", res, zError(res)); return -1; } res = deflate(&zs, Z_FINISH); if (res != Z_STREAM_END) { DBG_ERR("Failed to compress data. ZLIB error code: %d (%s)", res, zError(res)); return -1; } res = deflateEnd(&zs); if (res != Z_OK) { DBG_ERR("Failed to finish data compression. ZLIB error code: %d (%s)", res, zError(res)); return -1; } *compressed_data_len = zs.total_out; return 0; } int decompress_data(uint8_t *compressed_data, size_t compressed_data_len, uint8_t *data, size_t *data_len) { uint8_t *dataptr = compressed_data; z_stream zs = {0}; zs.zalloc = Z_NULL; zs.zfree = Z_NULL; zs.opaque = Z_NULL; zs.avail_in = (uInt) compressed_data_len; zs.next_in = (Bytef *) dataptr; zs.avail_out = (uInt) *data_len; zs.next_out = (Bytef *) data; int res = inflateInit2(&zs, MAX_WBITS | 16); if (res != Z_OK) { DBG_ERR("Failed to initialize data decompression. ZLIB error code: %d (%s)", res, zError(res)); return -1; } res = inflate(&zs, Z_FINISH); if (res != Z_STREAM_END) { DBG_ERR("Failed to decompress data. ZLIB error code: %d (%s)", res, zError(res)); return -1; } res = inflateEnd(&zs); if (res != Z_OK) { DBG_ERR("Failed to finish data decompression. ZLIB error code: %d (%s)", res, zError(res)); return -1; } *data_len = zs.total_out; return 0; } yubihsm-shell-2.7.3/lib/data_compress.h0000644000175000017500000000254115167357110017041 0ustar aveenaveen/* * Copyright 2024 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* ** Implements platform specific operations to compress and uncompress X509Cert */ #ifndef YUBIHSM_SHELL_DATA_COMPRESS_H #define YUBIHSM_SHELL_DATA_COMPRESS_H #include "../common/platform-config.h" #include #include #ifdef __cplusplus extern "C" { #endif #ifndef __WIN32 #define YH_INTERNAL __attribute__((visibility("hidden"))) #else #define YH_INTERNAL #endif int YH_INTERNAL compress_data(const uint8_t *data, size_t data_len, uint8_t *compressed_data, size_t *compressed_data_len); int YH_INTERNAL decompress_data(uint8_t *compressed_data, size_t compressed_data_len, uint8_t *data, size_t *data_len); #endif // YUBIHSM_SHELL_DATA_COMPRESS_H yubihsm-shell-2.7.3/lib/CMakeLists.txt0000644000175000017500000002204015167357110016600 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if(${WIN32_BCRYPT}) else(${WIN32_BCRYPT}) include(${CMAKE_SOURCE_DIR}/cmake/openssl.cmake) find_libcrypto() endif(${WIN32_BCRYPT}) if(MSVC) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) endif() set ( SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../aes_cmac/aes.c ${CMAKE_CURRENT_SOURCE_DIR}/../aes_cmac/aes_cmac.c ${CMAKE_CURRENT_SOURCE_DIR}/../common/hash.c ${CMAKE_CURRENT_SOURCE_DIR}/../common/pkcs5.c ${CMAKE_CURRENT_SOURCE_DIR}/../common/rand.c ${CMAKE_CURRENT_SOURCE_DIR}/../common/ecdh.c error.c lib_util.c yubihsm.c ) if (ENABLE_CERT_COMPRESS) set(SOURCE ${SOURCE} data_compress.c) include(${CMAKE_SOURCE_DIR}/cmake/zlib.cmake) find_zlib() endif() if(MSVC) set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/../common/time_win.c) endif(MSVC) set(STATIC_SOURCE ${SOURCE}) if(NOT ${WIN32_BCRYPT}) set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/../common/openssl-compat.c) endif(NOT ${WIN32_BCRYPT}) set (STATIC_SOURCE ${SOURCE}) if(WIN32) set(ADDITIONAL_LIBRARY ws2_32) set ( HTTP_SOURCE yubihsm_winhttp.c lib_util.c ${CMAKE_CURRENT_BINARY_DIR}/version_winhttp.rc ${CMAKE_CURRENT_SOURCE_DIR}/../common/time_win.c ) set ( USB_SOURCE yubihsm_usb.c yubihsm_winusb.c lib_util.c ${CMAKE_CURRENT_BINARY_DIR}/version_winusb.rc ${CMAKE_CURRENT_SOURCE_DIR}/../common/time_win.c ) set(HTTP_LIBRARY winhttp ws2_32) set(USB_LIBRARY winusb ws2_32 setupapi) if(${WIN32_BCRYPT}) set (CRYPT_LIBRARY bcrypt) add_definitions (-D_WIN32_BCRYPT) else(${WIN32_BCRYPT}) set(CRYPT_LIBRARY ${LIBCRYPTO_LDFLAGS}) endif(${WIN32_BCRYPT}) list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) list(APPEND STATIC_SOURCE yubihsm_winusb.c yubihsm_usb.c yubihsm_winhttp.c) else(WIN32) set(ADDITIONAL_LIBRARY -ldl) set ( USB_SOURCE yubihsm_usb.c yubihsm_libusb.c lib_util.c ) set ( HTTP_SOURCE yubihsm_curl.c lib_util.c ) set(HTTP_LIBRARY ${LIBCURL_LDFLAGS}) set(USB_LIBRARY ${LIBUSB_LDFLAGS}) set(CRYPT_LIBRARY ${LIBCRYPTO_LDFLAGS}) list(APPEND STATIC_SOURCE yubihsm_libusb.c yubihsm_usb.c yubihsm_curl.c) if(FUZZING) add_executable(fuzz_send_plain_msg ${SOURCE} fuzz/fuzz_send_plain_msg.cc fuzz/yubihsm_fuzz.cc) set_target_properties (fuzz_send_plain_msg PROPERTIES COMPILE_FLAGS "-DSTATIC -fsanitize=fuzzer ") set_target_properties (fuzz_send_plain_msg PROPERTIES LINK_FLAGS "-fsanitize=fuzzer ") target_link_libraries (fuzz_send_plain_msg ${LIBCRYPTO_LDFLAGS}) add_executable(fuzz_send_secure_msg ${SOURCE} fuzz/fuzz_send_secure_msg.cc fuzz/yubihsm_fuzz.cc) set_target_properties (fuzz_send_secure_msg PROPERTIES COMPILE_FLAGS "-DSTATIC -fsanitize=fuzzer ") set_target_properties (fuzz_send_secure_msg PROPERTIES LINK_FLAGS "-fsanitize=fuzzer ") target_link_libraries (fuzz_send_secure_msg ${LIBCRYPTO_LDFLAGS}) endif(FUZZING) endif(WIN32) include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ${LIBCRYPTO_INCLUDEDIR} ${LIBCURL_INCLUDEDIR} ) add_library (yubihsm SHARED ${SOURCE}) add_library (yubihsm_usb SHARED ${USB_SOURCE}) add_library (yubihsm_http SHARED ${HTTP_SOURCE}) set_target_properties(yubihsm PROPERTIES BUILD_RPATH "${CMAKE_BINARY_DIR}/lib") set_target_properties (yubihsm PROPERTIES VERSION "${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}" SOVERSION ${yubihsm_shell_VERSION_MAJOR}) set_target_properties (yubihsm_usb PROPERTIES VERSION "${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}" SOVERSION ${yubihsm_shell_VERSION_MAJOR}) set_target_properties (yubihsm_http PROPERTIES VERSION "${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}" SOVERSION ${yubihsm_shell_VERSION_MAJOR}) if(MSVC) set_target_properties(yubihsm PROPERTIES OUTPUT_NAME libyubihsm) set_target_properties(yubihsm_usb PROPERTIES OUTPUT_NAME libyubihsm_usb) set_target_properties(yubihsm_http PROPERTIES OUTPUT_NAME libyubihsm_http) else(MSVC) set_target_properties(yubihsm PROPERTIES OUTPUT_NAME yubihsm) set_target_properties(yubihsm_usb PROPERTIES OUTPUT_NAME yubihsm_usb) set_target_properties(yubihsm_http PROPERTIES OUTPUT_NAME yubihsm_http) endif(MSVC) if (ENABLE_STATIC) add_library (yubihsm_static STATIC ${STATIC_SOURCE}) set_target_properties (yubihsm_static PROPERTIES POSITION_INDEPENDENT_CODE on OUTPUT_NAME yubihsm) set_target_properties (yubihsm_static PROPERTIES COMPILE_FLAGS "-DSTATIC " ) if(MSVC) set_property(TARGET yubihsm_static PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif(MSVC) add_coverage (yubihsm_static) endif() if(${WIN32}) else(${WIN32}) if(${LIBUSB_VERSION} VERSION_LESS 1.0.16) set(LIBUSB_CFLAGS "${LIBUSB_CFLAGS} -DNO_LIBUSB_STRERROR") endif() set_target_properties (yubihsm_usb PROPERTIES COMPILE_FLAGS ${LIBUSB_CFLAGS}) if(ENABLE_STATIC) set_property(TARGET yubihsm_static APPEND_STRING PROPERTY COMPILE_FLAGS ${LIBUSB_CFLAGS}) endif(ENABLE_STATIC) endif(${WIN32}) add_coverage (yubihsm) add_coverage (yubihsm_usb) 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} ${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} ${ZLIB_LIBS}) endif(ENABLE_STATIC) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yubihsm.pc.in ${CMAKE_CURRENT_BINARY_DIR}/yubihsm.pc @ONLY) configure_file(${CMAKE_SOURCE_DIR}/common/platform-config.h.in ${CMAKE_SOURCE_DIR}/common/platform-config.h @ONLY) if(WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version_winhttp.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version_winhttp.rc @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version_winusb.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version_winusb.rc @ONLY) endif(WIN32) install( TARGETS yubihsm ARCHIVE DESTINATION ${YUBIHSM_INSTALL_LIB_DIR} LIBRARY DESTINATION ${YUBIHSM_INSTALL_LIB_DIR} RUNTIME DESTINATION ${YUBIHSM_INSTALL_BIN_DIR}) install( TARGETS yubihsm_usb ARCHIVE DESTINATION ${YUBIHSM_INSTALL_LIB_DIR} LIBRARY DESTINATION ${YUBIHSM_INSTALL_LIB_DIR} RUNTIME DESTINATION ${YUBIHSM_INSTALL_BIN_DIR}) install( TARGETS yubihsm_http ARCHIVE DESTINATION ${YUBIHSM_INSTALL_LIB_DIR} LIBRARY DESTINATION ${YUBIHSM_INSTALL_LIB_DIR} RUNTIME DESTINATION ${YUBIHSM_INSTALL_BIN_DIR}) install(FILES yubihsm.h DESTINATION ${YUBIHSM_INSTALL_INC_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/yubihsm.pc DESTINATION ${YUBIHSM_INSTALL_PKGCONFIG_DIR}) add_subdirectory (tests) add_test( NAME parsing COMMAND test_parsing WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/lib/tests/ ) add_test( NAME pbkdf2 COMMAND test_pbkdf2 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/lib/tests/ ) add_test( NAME attest COMMAND attest WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/examples/ ) add_test( NAME generate_ec COMMAND generate_ec ) add_test( NAME generate_hmac COMMAND generate_hmac ) add_test( NAME import_authkey COMMAND import_authkey ) add_test( NAME import_rsa COMMAND import_rsa WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/examples/ ) add_test( NAME info COMMAND info ) add_test( NAME wrap COMMAND wrap ) add_test( NAME wrap_data COMMAND wrap_data ) add_test( NAME yubico_otp COMMAND yubico_otp ) add_test( NAME echo COMMAND echo ) add_test( NAME asym_auth COMMAND asym_auth ) add_test( NAME import_ec COMMAND import_ec WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/examples/ ) add_test( NAME generate_rsa COMMAND generate_rsa ) add_test( NAME logs COMMAND logs ) add_test( NAME ssh COMMAND ssh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/examples/ ) add_test( NAME decrypt_rsa COMMAND decrypt_rsa WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/examples/ ) add_test( NAME decrypt_ec COMMAND decrypt_ec ) add_test( NAME import_ed COMMAND import_ed WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/examples/ ) add_test( NAME change_authkey COMMAND change_authkey ) add_test( NAME encrypt_aes COMMAND encrypt_aes WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/examples" ) set_tests_properties(encrypt_aes PROPERTIES SKIP_RETURN_CODE 64) yubihsm-shell-2.7.3/lib/debug_lib.h0000644000175000017500000001033715167357110016133 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef DEBUG_LIB_H #define DEBUG_LIB_H #ifdef _MSVC #include #include #else #include #endif #include #include #include "yubihsm.h" #include "../common/debug.h" extern uint8_t _yh_verbosity; extern FILE *_yh_output; #define DUMPIF(var, len, lev) \ do { \ if (_yh_verbosity & lev) { \ dump_hex(_yh_output, var, len); \ fprintf(_yh_output, "\n"); \ } \ } while (0) #define DBG_INT(var, len, ...) \ do { \ D(_yh_verbosity &YH_VERB_INTERMEDIATE, _yh_output, ANSI_YELLOW, "LIB", \ "INT", __VA_ARGS__); \ DUMPIF(var, len, YH_VERB_INTERMEDIATE); \ } while (0) #define DBG_CRYPTO(var, len, ...) \ do { \ D(_yh_verbosity &YH_VERB_CRYPTO, _yh_output, ANSI_GREEN, "LIB", "CRY", \ __VA_ARGS__); \ DUMPIF(var, len, YH_VERB_CRYPTO); \ } while (0) #define DBG_NET(var, dump) \ do { \ D(_yh_verbosity &YH_VERB_RAW, _yh_output, ANSI_MAGENTA, "LIB", "NET", \ " "); \ if (_yh_verbosity & YH_VERB_RAW) { \ dump(_yh_output, (var)); \ } \ } while (0) #define DBG_INFO(...) \ do { \ DLN(_yh_verbosity &YH_VERB_INFO, _yh_output, ANSI_BLUE, "LIB", "INF", \ __VA_ARGS__); \ } while (0) #define DBG_DUMPINFO(var, len, ...) \ do { \ D(_yh_verbosity &YH_VERB_INFO, _yh_output, ANSI_BLUE, "LIB", "INF", \ __VA_ARGS__); \ DUMPIF(var, len, YH_VERB_INFO); \ } while (0) #define DBG_ERR(...) \ do { \ DLN(_yh_verbosity &YH_VERB_ERR, _yh_output, ANSI_RED, "LIB", "ERR", \ __VA_ARGS__); \ } while (0) #endif #define DBG_DUMPERR(var, len, ...) \ do { \ D(_yh_verbosity &YH_VERB_ERR, _yh_output, ANSI_RED, "LIB", "ERR", \ __VA_ARGS__); \ DUMPIF(var, len, YH_VERB_ERR); \ } while (0) yubihsm-shell-2.7.3/lib/scp.h0000644000175000017500000000357515167357110015012 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SCP_H #define SCP_H #include #include // Data derivation constants #define SCP_CARD_CRYPTOGRAM 0x00 #define SCP_HOST_CRYPTOGRAM 0x01 #define SCP_CARD_CHALLENGE 0x02 #define SCP_S_ENC_DERIVATION 0x04 #define SCP_S_MAC_DERIVATION 0x06 #define SCP_S_RMAC_DERIVATION 0x07 // Lengths #define AES_128_KEY_LEN 16 #define AES_192_KEY_LEN 24 #define AES_256_KEY_LEN 32 #define SCP_KEY_LEN (AES_128_KEY_LEN) #define SCP_PRF_LEN 16 // One AES block #define SCP_CARD_CHAL_LEN 8 #define SCP_HOST_CHAL_LEN 8 #define SCP_CARD_CRYPTO_LEN 8 #define SCP_HOST_CRYPTO_LEN 8 #define SCP_MAC_LEN 8 #define SCP_CONTEXT_LEN 16 #define SCP_AUTHKEY_ID_LEN 2 #ifndef FUZZING #define SCP_MSG_BUF_SIZE 3136 #else // in fuzzing builds make the data buffers smaller #define SCP_MSG_BUF_SIZE 100 #endif // Message #pragma pack(push, 1) union _Msg { struct { uint8_t cmd; uint16_t len; uint8_t data[SCP_MSG_BUF_SIZE]; } st; uint8_t raw[SCP_MSG_BUF_SIZE + 3]; }; #pragma pack(pop) typedef union _Msg Msg; struct yh_connector; typedef struct { uint8_t sid; uint8_t s_enc[SCP_KEY_LEN]; uint8_t s_mac[SCP_KEY_LEN]; uint8_t s_rmac[SCP_KEY_LEN]; uint8_t mac_chaining_value[SCP_PRF_LEN]; uint8_t ctr[SCP_PRF_LEN]; char identifier[17]; struct yh_connector *parent; } Scp_ctx; #endif yubihsm-shell-2.7.3/lib/yubihsm.h0000644000175000017500000036031715167357110015705 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** @mainpage @section Introduction Libyubihsm is a library for communicating with a YubiHSM 2 device. @section Usage To use the library, include in the C code and pass the -lyubihsm flag to the linker. Debug output is controlled with the function #yh_set_verbosity(). First step of using a YubiHSM 2 is to initialize the library with #yh_init(), initialize a connector with #yh_init_connector() and then connect it to the YubiHSM 2 with #yh_connect(). After this, a session must be established with #yh_create_session_derived(), #yh_create_session(), #yh_begin_create_session() + yh_finish_create_session(). When a session is established, commands can be exchanged over it. The functions in the namespace yh_util are high-level convenience functions that do specific tasks with the device. @section api API Reference All public functions and definitions can be found in yubihsm.h @section example Code example Here is a small example of establishing a session with a YubiHSM 2 and fetching some pseudo random bytes before closing the session. \code{.c} int main(void) { yh_connector *connector = NULL; yh_session *session = NULL; uint8_t data[128] = {0}; size_t data_len = sizeof(data); assert(yh_init() == YHR_SUCCESS); assert(yh_init_connector("http://localhost:12345", &connector)==YHR_SUCCESS); assert(yh_connect(connector, 0) == YHR_SUCCESS); assert(yh_create_session_derived(connector, 1, YH_DEFAULT_PASSWORD, strlen(YH_DEFAULT_PASSWORD), false, &session) == YHR_SUCCESS); assert(yh_util_get_pseudo_random(session, sizeof(data), data, &data_len)==YHR_SUCCESS); assert(data_len == sizeof(data)); assert(yh_util_close_session(session) == YHR_SUCCESS); assert(yh_destroy_session(&session) == YHR_SUCCESS); assert(yh_disconnect(connector) == YHR_SUCCESS); } \endcode */ /** @file yubihsm.h * * Everything you need to establish a connection to the YubiHSM 2 and use its * functions. */ #ifndef YUBIHSM_H #define YUBIHSM_H #include #include #include #include /// Length of context array for authentication #define YH_CONTEXT_LEN 16 /// Length of host challenge for authentication #define YH_HOST_CHAL_LEN 8 /// Maximum length of message buffer #ifndef FUZZING #define YH_MSG_BUF_SIZE 3136 #else // in fuzzing builds make the data buffers smaller #define YH_MSG_BUF_SIZE 100 #endif /// Length of authentication keys #define YH_KEY_LEN 16 /// Device vendor ID #define YH_VID 0x1050 /// Device product ID #define YH_PID 0x0030 /// Response flag for commands #define YH_CMD_RESP_FLAG 0x80 /// Max items the device may hold #define YH_MAX_ITEMS_COUNT 256 /// Max sessions the device may hold #define YH_MAX_SESSIONS 16 /// Default encryption key #define YH_DEFAULT_ENC_KEY \ "\x09\x0b\x47\xdb\xed\x59\x56\x54\x90\x1d\xee\x1c\xc6\x55\xe4\x20" /// Default MAC key #define YH_DEFAULT_MAC_KEY \ "\x59\x2f\xd4\x83\xf7\x59\xe2\x99\x09\xa0\x4c\x45\x05\xd2\xce\x0a" /// Default authentication key password #define YH_DEFAULT_PASSWORD "password" /// Salt to be used for PBKDF2 key derivation #define YH_DEFAULT_SALT "Yubico" /// Number of iterations for PBKDF2 key derivation #define YH_DEFAULT_ITERS 10000 /// Length of capabilities array #define YH_CAPABILITIES_LEN 8 /// Max log entries the device may hold #define YH_MAX_LOG_ENTRIES 64 /// Max length of object labels #define YH_OBJ_LABEL_LEN 40 /// Max number of domains #define YH_MAX_DOMAINS 16 /// Size that the log digest is truncated to #define YH_LOG_DIGEST_SIZE 16 /// URL scheme used for direct USB access #define YH_USB_URL_SCHEME "yhusb://" /// URL scheme used for fuzzing builds #define YH_FUZZ_URL_SCHEME "yhfuzz://" // Debug levels /// Debug level quiet. No messages printed out #define YH_VERB_QUIET 0x00 /// Debug level intermediate. Intermediate results printed out #define YH_VERB_INTERMEDIATE 0x01 /// Debug level crypto. Crypto results printed out #define YH_VERB_CRYPTO 0x02 /// Debug level raw. Raw messages printed out #define YH_VERB_RAW 0x04 /// Debug level info. General information messages printed out #define YH_VERB_INFO 0x08 /// Debug level error. Error messages printed out #define YH_VERB_ERR 0x10 /// Debug level all. All previous options enabled #define YH_VERB_ALL 0xff /// This is the overhead when doing aes-ccm wrapping: 1 byte identifier, 13 /// bytes nonce and 16 bytes mac #define YH_CCM_WRAP_OVERHEAD (1 + 13 + 16) #define YH_EC_P256_PRIVKEY_LEN 32 #define YH_EC_P256_PUBKEY_LEN 65 #ifdef __cplusplus extern "C" { #endif /// Reference to a connector typedef struct yh_connector yh_connector; /// Reference to a session typedef struct yh_session yh_session; /// Capabilities representation typedef struct { /// Capabilities is represented as an 8 byte uint8_t array uint8_t capabilities[YH_CAPABILITIES_LEN]; } yh_capabilities; /** * Return codes. **/ typedef enum { /// Returned value when function was successful YHR_SUCCESS = 0, /// Returned value when unable to allocate memory YHR_MEMORY_ERROR = -1, /// Returned value when failing to initialize libyubihsm YHR_INIT_ERROR = -2, /// Returned value when a connection error was encountered YHR_CONNECTION_ERROR = -3, /// Returned value when failing to find a suitable connector YHR_CONNECTOR_NOT_FOUND = -4, /// Returned value when an argument to a function is invalid YHR_INVALID_PARAMETERS = -5, /// Returned value when there is a mismatch between expected and received /// length of an argument to a function YHR_WRONG_LENGTH = -6, /// Returned value when there is not enough space to store data YHR_BUFFER_TOO_SMALL = -7, /// Returned value when failing to verify cryptogram YHR_CRYPTOGRAM_MISMATCH = -8, /// Returned value when failing to authenticate the session YHR_SESSION_AUTHENTICATION_FAILED = -9, /// Returned value when failing to verify MAC YHR_MAC_MISMATCH = -10, /// Returned value when the device returned no error YHR_DEVICE_OK = -11, /// Returned value when the device receives and invalid command YHR_DEVICE_INVALID_COMMAND = -12, /// Returned value when the device receives a malformed command invalid data YHR_DEVICE_INVALID_DATA = -13, /// Returned value when the device session is invalid YHR_DEVICE_INVALID_SESSION = -14, /// Return value when the device fails to encrypt or verify the message YHR_DEVICE_AUTHENTICATION_FAILED = -15, /// Return value when no more sessions can be opened on the device YHR_DEVICE_SESSIONS_FULL = -16, /// Return value when failing to create a device session YHR_DEVICE_SESSION_FAILED = -17, /// Return value when encountering a storage failure on the device YHR_DEVICE_STORAGE_FAILED = -18, /// Return value when there is a mismatch between expected and received /// length of an argument to a function on the device YHR_DEVICE_WRONG_LENGTH = -19, /// Return value when the permissions to perform the operation are wrong YHR_DEVICE_INSUFFICIENT_PERMISSIONS = -20, /// Return value when the log buffer is full and forced audit is set YHR_DEVICE_LOG_FULL = -21, /// Return value when the object not found on the device YHR_DEVICE_OBJECT_NOT_FOUND = -22, /// Return value when an invalid Object ID is used YHR_DEVICE_INVALID_ID = -23, /// Return value when an invalid OTP is submitted YHR_DEVICE_INVALID_OTP = -24, /// Return value when the device is in demo mode and has to be power cycled YHR_DEVICE_DEMO_MODE = -25, /// Return value when the command execution has not terminated YHR_DEVICE_COMMAND_UNEXECUTED = -26, /// Return value when encountering an unknown error YHR_GENERIC_ERROR = -27, /// Return value when trying to add an object with an ID that already exists YHR_DEVICE_OBJECT_EXISTS = -28, /// Return value when connector operation failed YHR_CONNECTOR_ERROR = -29, /// Return value when encountering SSH CA constraint violation YHR_DEVICE_SSH_CA_CONSTRAINT_VIOLATION = -30, /// Return value when an algorithm is disabled YHR_DEVICE_ALGORITHM_DISABLED = -31, } yh_rc; /// Macro to define command and response command #define ADD_COMMAND(c, v) c = v, c##_R = v | YH_CMD_RESP_FLAG /** * Command definitions */ typedef enum { /// Echo data back from the device. ADD_COMMAND(YHC_ECHO, 0x01), /// Create a session with the device. ADD_COMMAND(YHC_CREATE_SESSION, 0x03), /// Authenticate the session to the device ADD_COMMAND(YHC_AUTHENTICATE_SESSION, 0x04), /// Send a command over an established session ADD_COMMAND(YHC_SESSION_MESSAGE, 0x05), /// Get device metadata ADD_COMMAND(YHC_GET_DEVICE_INFO, 0x06), /// Factory reset a device ADD_COMMAND(YHC_RESET_DEVICE, 0x08), /// Get the device pubkey for asym auth ADD_COMMAND(YHC_GET_DEVICE_PUBKEY, 0x0a), /// Close session ADD_COMMAND(YHC_CLOSE_SESSION, 0x40), /// Get storage information ADD_COMMAND(YHC_GET_STORAGE_INFO, 0x041), /// Import an Opaque Object into the device ADD_COMMAND(YHC_PUT_OPAQUE, 0x42), /// Get an Opaque Object from device ADD_COMMAND(YHC_GET_OPAQUE, 0x43), /// Import an Authentication Key into the device ADD_COMMAND(YHC_PUT_AUTHENTICATION_KEY, 0x44), /// Import an Asymmetric Key into the device ADD_COMMAND(YHC_PUT_ASYMMETRIC_KEY, 0x45), /// Generate an Asymmetric Key in the device ADD_COMMAND(YHC_GENERATE_ASYMMETRIC_KEY, 0x46), /// Sign data using RSA-PKCS#1v1.5 ADD_COMMAND(YHC_SIGN_PKCS1, 0x47), /// List objects in the device ADD_COMMAND(YHC_LIST_OBJECTS, 0x48), /// Decrypt data that was encrypted using RSA-PKCS#1v1.5 ADD_COMMAND(YHC_DECRYPT_PKCS1, 0x49), /// Get an Object under wrap from the device. ADD_COMMAND(YHC_EXPORT_WRAPPED, 0x4a), /// Import a wrapped Object into the device ADD_COMMAND(YHC_IMPORT_WRAPPED, 0x4b), /// Import a Wrap Key into the device ADD_COMMAND(YHC_PUT_WRAP_KEY, 0x4c), /// Get all current audit log entries from the device Log Store ADD_COMMAND(YHC_GET_LOG_ENTRIES, 0x4d), /// Get all metadata about an Object ADD_COMMAND(YHC_GET_OBJECT_INFO, 0x4e), /// Set a device-global options that affect general behavior ADD_COMMAND(YHC_SET_OPTION, 0x4f), /// Get a device-global option ADD_COMMAND(YHC_GET_OPTION, 0x50), /// Get a fixed number of pseudo-random bytes from the device ADD_COMMAND(YHC_GET_PSEUDO_RANDOM, 0x51), /// Import a HMAC key into the device ADD_COMMAND(YHC_PUT_HMAC_KEY, 0x52), /// Perform an HMAC operation in the device ADD_COMMAND(YHC_SIGN_HMAC, 0x53), /// Get the public key of an Asymmetric Key in the device ADD_COMMAND(YHC_GET_PUBLIC_KEY, 0x54), /// Sign data using RSA-PSS ADD_COMMAND(YHC_SIGN_PSS, 0x55), /// Sign data using ECDSA ADD_COMMAND(YHC_SIGN_ECDSA, 0x56), /// Perform an ECDH key exchange operation with a private key in the device ADD_COMMAND(YHC_DERIVE_ECDH, 0x57), /// Delete object in the device ADD_COMMAND(YHC_DELETE_OBJECT, 0x58), /// Decrypt data using RSA-OAEP ADD_COMMAND(YHC_DECRYPT_OAEP, 0x59), /// Generate an HMAC Key in the device ADD_COMMAND(YHC_GENERATE_HMAC_KEY, 0x5a), /// Generate a Wrap Key in the device ADD_COMMAND(YHC_GENERATE_WRAP_KEY, 0x5b), /// Verify a generated HMAC ADD_COMMAND(YHC_VERIFY_HMAC, 0x5c), /// Sign SSH certificate request ADD_COMMAND(YHC_SIGN_SSH_CERTIFICATE, 0x5d), /// Import a template into the device ADD_COMMAND(YHC_PUT_TEMPLATE, 0x5e), /// Get a template from the device ADD_COMMAND(YHC_GET_TEMPLATE, 0x5f), /// Decrypt a Yubico OTP ADD_COMMAND(YHC_DECRYPT_OTP, 0x60), /// Create a Yubico OTP AEAD ADD_COMMAND(YHC_CREATE_OTP_AEAD, 0x61), /// Generate an OTP AEAD from random data ADD_COMMAND(YHC_RANDOMIZE_OTP_AEAD, 0x62), /// Re-encrypt a Yubico OTP AEAD from one OTP AEAD Key to another OTP AEAD Key ADD_COMMAND(YHC_REWRAP_OTP_AEAD, 0x63), /// Get attestation of an Asymmetric Key ADD_COMMAND(YHC_SIGN_ATTESTATION_CERTIFICATE, 0x64), /// Import an OTP AEAD Key into the device ADD_COMMAND(YHC_PUT_OTP_AEAD_KEY, 0x65), /// Generate an OTP AEAD Key in the device ADD_COMMAND(YHC_GENERATE_OTP_AEAD_KEY, 0x66), /// Set the last extracted audit log entry ADD_COMMAND(YHC_SET_LOG_INDEX, 0x67), /// Encrypt (wrap) data using a Wrap Key ADD_COMMAND(YHC_WRAP_DATA, 0x68), /// Decrypt (unwrap) data using a Wrap Key ADD_COMMAND(YHC_UNWRAP_DATA, 0x69), /// Sign data using EdDSA ADD_COMMAND(YHC_SIGN_EDDSA, 0x6a), /// Blink the LED of the device ADD_COMMAND(YHC_BLINK_DEVICE, 0x6b), /// Replace the Authentication Key used to establish the current Session. ADD_COMMAND(YHC_CHANGE_AUTHENTICATION_KEY, 0x6c), /// Import a Symmetric Key into the device ADD_COMMAND(YHC_PUT_SYMMETRIC_KEY, 0x6d), /// Generate a Symmetric Key in the device ADD_COMMAND(YHC_GENERATE_SYMMETRIC_KEY, 0x6e), /// Decrypt data using a Symmetric Key with ECB ADD_COMMAND(YHC_DECRYPT_ECB, 0x6f), /// Encrypt data using a Symmetric Key with ECB ADD_COMMAND(YHC_ENCRYPT_ECB, 0x70), /// Decrypt data using a Symmetric Key with CBC ADD_COMMAND(YHC_DECRYPT_CBC, 0x71), /// Encrypt data using a Symmetric Key with CBC ADD_COMMAND(YHC_ENCRYPT_CBC, 0x72), /// Import public RSA key as a Public Wrap Key ADD_COMMAND(YHC_PUT_PUBLIC_WRAPKEY, 0x73), /// Export (a)symmetric key using a Public Wrap Key ADD_COMMAND(YHC_GET_RSA_WRAPPED_KEY, 0x74), /// Import (a)symmetric key after unwrapping in using and RSA wrap key ADD_COMMAND(YHC_PUT_RSA_WRAPPED_KEY, 0x75), /// Wrap an object using an RSA Wrap Key ADD_COMMAND(YHC_EXPORT_RSA_WRAPPED, 0x76), /// Import an object after unwrapping in using and RSA Wrap Key ADD_COMMAND(YHC_IMPORT_RSA_WRAPPED, 0x77), /// The response byte returned from the device if the command resulted in an /// error YHC_ERROR = 0x7f, } yh_cmd; #undef ADD_COMMAND /** * Object types * * @see Objects */ typedef enum { /// Opaque Object is an unchecked kind of Object, normally used to store /// raw data in the device YH_OPAQUE = 0x01, /// Authentication Key is used to establish Sessions with a device YH_AUTHENTICATION_KEY = 0x02, /// Asymmetric Key is the private key of an asymmetric key-pair YH_ASYMMETRIC_KEY = 0x03, /// Wrap Key is a secret key used to wrap and unwrap Objects during the /// export and import process YH_WRAP_KEY = 0x04, /// HMAC Key is a secret key used when computing and verifying HMAC signatures YH_HMAC_KEY = 0x05, /// Template is a binary object used for example to validate SSH certificate /// requests YH_TEMPLATE = 0x06, /// OTP AEAD Key is a secret key used to decrypt Yubico OTP values YH_OTP_AEAD_KEY = 0x07, /// Symmetric Key is a secret key used for encryption and decryption. YH_SYMMETRIC_KEY = 0x08, /// Public Wrap Key is a public key used to wrap Objects during the /// export process YH_PUBLIC_WRAP_KEY = 0x09, /// Public Key is the public key of an asymmetric key-pair. The public key /// never exists in device and is mostly here for PKCS#11. YH_PUBLIC_KEY = YH_ASYMMETRIC_KEY | 0x80, /// Wrap Key public is the public key of an asymmetric wrap key. The public key /// never exists in device and is mostly here for PKCS#11. YH_WRAP_KEY_PUBLIC = YH_WRAP_KEY | 0x80, } yh_object_type; /// Max number of algorithms defined here #define YH_MAX_ALGORITHM_COUNT 0xff /** * Algorithms * * @see Objects */ typedef enum { /// rsa-pkcs1-sha1 YH_ALGO_RSA_PKCS1_SHA1 = 1, /// rsa-pkcs1-sha256 YH_ALGO_RSA_PKCS1_SHA256 = 2, /// rsa-pkcs1-sha384 YH_ALGO_RSA_PKCS1_SHA384 = 3, /// rsa-pkcs1-sha512 YH_ALGO_RSA_PKCS1_SHA512 = 4, /// rsa-pss-sha1 YH_ALGO_RSA_PSS_SHA1 = 5, /// rsa-pss-sha256 YH_ALGO_RSA_PSS_SHA256 = 6, /// rsa-pss-sha384 YH_ALGO_RSA_PSS_SHA384 = 7, /// rsa-pss-sha512 YH_ALGO_RSA_PSS_SHA512 = 8, /// rsa2048 YH_ALGO_RSA_2048 = 9, /// rsa3072 YH_ALGO_RSA_3072 = 10, /// rsa4096 YH_ALGO_RSA_4096 = 11, /// ecp256 YH_ALGO_EC_P256 = 12, /// ecp384 YH_ALGO_EC_P384 = 13, /// ecp521 YH_ALGO_EC_P521 = 14, /// eck256 YH_ALGO_EC_K256 = 15, /// ecbp256 YH_ALGO_EC_BP256 = 16, /// ecbp384 YH_ALGO_EC_BP384 = 17, /// ecbp512 YH_ALGO_EC_BP512 = 18, /// hmac-sha1 YH_ALGO_HMAC_SHA1 = 19, /// hmac-sha256 YH_ALGO_HMAC_SHA256 = 20, /// hmac-sha384 YH_ALGO_HMAC_SHA384 = 21, /// hmac-sha512 YH_ALGO_HMAC_SHA512 = 22, /// ecdsa-sha1 YH_ALGO_EC_ECDSA_SHA1 = 23, /// ecdh YH_ALGO_EC_ECDH = 24, /// rsa-oaep-sha1 YH_ALGO_RSA_OAEP_SHA1 = 25, /// rsa-oaep-sha256 YH_ALGO_RSA_OAEP_SHA256 = 26, /// rsa-oaep-sha384 YH_ALGO_RSA_OAEP_SHA384 = 27, /// rsa-oaep-sha512 YH_ALGO_RSA_OAEP_SHA512 = 28, /// aes128-ccm-wrap YH_ALGO_AES128_CCM_WRAP = 29, /// opaque-data YH_ALGO_OPAQUE_DATA = 30, /// opaque-x509-certificate YH_ALGO_OPAQUE_X509_CERTIFICATE = 31, /// mgf1-sha1 YH_ALGO_MGF1_SHA1 = 32, /// mgf1-sha256 YH_ALGO_MGF1_SHA256 = 33, /// mgf1-sha384 YH_ALGO_MGF1_SHA384 = 34, /// mgf1-sha512 YH_ALGO_MGF1_SHA512 = 35, /// template-ssh YH_ALGO_TEMPLATE_SSH = 36, /// aes128-yubico-otp YH_ALGO_AES128_YUBICO_OTP = 37, /// aes128-yubico-authentication YH_ALGO_AES128_YUBICO_AUTHENTICATION = 38, /// aes192-yubico-otp YH_ALGO_AES192_YUBICO_OTP = 39, /// aes256-yubico-otp YH_ALGO_AES256_YUBICO_OTP = 40, /// aes192-ccm-wrap YH_ALGO_AES192_CCM_WRAP = 41, /// aes256-ccm-wrap YH_ALGO_AES256_CCM_WRAP = 42, /// ecdsa-sha256 YH_ALGO_EC_ECDSA_SHA256 = 43, /// ecdsa-sha384 YH_ALGO_EC_ECDSA_SHA384 = 44, /// ecdsa-sha512 YH_ALGO_EC_ECDSA_SHA512 = 45, /// ed25519 YH_ALGO_EC_ED25519 = 46, /// ecp224 YH_ALGO_EC_P224 = 47, /// rsa-pkcs1-decrypt YH_ALGO_RSA_PKCS1_DECRYPT = 48, /// ec-p256-yubico-authentication YH_ALGO_EC_P256_YUBICO_AUTHENTICATION = 49, /// aes128 YH_ALGO_AES128 = 50, /// aes192 YH_ALGO_AES192 = 51, /// aes256 YH_ALGO_AES256 = 52, /// aes-ecb YH_ALGO_AES_ECB = 53, /// aes-cbc YH_ALGO_AES_CBC = 54, /// aes-kwp YH_ALGO_AES_KWP = 55, } yh_algorithm; /** * Global options */ typedef enum { /// Enable/Disable Forced Audit mode YH_OPTION_FORCE_AUDIT = 1, /// Enable/Disable logging of specific commands YH_OPTION_COMMAND_AUDIT = 3, /// Toggle algorithms on/off YH_OPTION_ALGORITHM_TOGGLE = 4, /// Fips mode on/off YH_OPTION_FIPS_MODE = 5, } yh_option; /** * Options for the connector, set with yh_set_connector_option() */ typedef enum { /// File with CA certificate to validate the connector with (const char *). /// Not implemented on Windows YH_CONNECTOR_HTTPS_CA = 1, /// Proxy server to use for connecting to the connector (const char *). Not /// implemented on Windows YH_CONNECTOR_PROXY_SERVER = 2, /// File with client certificate to authenticate client with (const char *). /// Not implemented on Windows YH_CONNECTOR_HTTPS_CERT = 3, /// File with client certificates key (const char *). /// Not implemented on Windows YH_CONNECTOR_HTTPS_KEY = 4, /// Comma separated list of hosts ignoring proxy, `*` to disable proxy. /// Not implemented on Windows YH_CONNECTOR_NOPROXY = 5, } yh_connector_option; /** * Options for data compression */ typedef enum { /// Do not compress data before importing it NO_COMPRESS = 1, /// Compress data if it's too big COMPRESS_IF_TOO_BIG = 2, /// Compress data before importing it COMPRESS = 3, } yh_compress_option; /** * Device info struct */ typedef struct { /// Firmware version major uint8_t major; /// Firmware version minor uint8_t minor; /// Firmware version patch uint8_t patch; /// Device serial number uint32_t serial; /// Total available logs uint8_t log_total; /// Total used logs uint8_t log_used; /// List of algorithms supported by the device yh_algorithm algorithms[YH_MAX_ALGORITHM_COUNT]; /// Number of algorithms supported by the device size_t n_algorithms; } yh_device_info; #pragma pack(push, 1) /** * Logging struct as returned by device * * @see Objects */ typedef struct { /// Monotonically increasing index uint16_t number; /// What command was executed @see yh_cmd uint8_t command; /// Length of in-data uint16_t length; /// ID of Authentication Key used uint16_t session_key; /// ID of first Object used uint16_t target_key; /// ID of second Object used uint16_t second_key; /// Command result @see yh_cmd uint8_t result; /// Systick at time of execution uint32_t systick; /// Truncated sha256 digest of this last digest + this entry uint8_t digest[YH_LOG_DIGEST_SIZE]; } yh_log_entry; /** * Object descriptor */ typedef struct { /// Object capabilities @see yh_capabilities yh_capabilities capabilities; /// Object ID uint16_t id; /// Object length uint16_t len; /// Object domains uint16_t domains; /// Object type yh_object_type type; /// Object algorithm yh_algorithm algorithm; /// Object sequence uint8_t sequence; /// Object origin uint8_t origin; /// Object label. The label consists of raw bytes and is not restricted to /// printable characters or valid UTF-8 glyphs char label[YH_OBJ_LABEL_LEN + 1]; /// Object delegated capabilities yh_capabilities delegated_capabilities; } yh_object_descriptor; #pragma pack(pop) static const struct { const char *name; int bit; } yh_capability[] = { {"change-authentication-key", 0x2e}, {"create-otp-aead", 0x1e}, {"decrypt-cbc", 0x34}, {"decrypt-ecb", 0x32}, {"decrypt-oaep", 0x0a}, {"decrypt-otp", 0x1d}, {"decrypt-pkcs", 0x09}, {"delete-asymmetric-key", 0x29}, {"delete-authentication-key", 0x28}, {"delete-hmac-key", 0x2b}, {"delete-opaque", 0x27}, {"delete-otp-aead-key", 0x2d}, {"delete-public-wrap-key", 0x37}, {"delete-symmetric-key", 0x31}, {"delete-template", 0x2c}, {"delete-wrap-key", 0x2a}, {"derive-ecdh", 0x0b}, {"encrypt-cbc", 0x35}, {"encrypt-ecb", 0x33}, {"export-wrapped", 0x0c}, {"exportable-under-wrap", 0x10}, {"generate-asymmetric-key", 0x04}, {"generate-hmac-key", 0x15}, {"generate-otp-aead-key", 0x24}, {"generate-symmetric-key", 0x30}, {"generate-wrap-key", 0x0f}, {"get-log-entries", 0x18}, {"get-opaque", 0x00}, {"get-option", 0x12}, {"get-pseudo-random", 0x13}, {"get-template", 0x1a}, {"import-wrapped", 0x0d}, {"put-asymmetric-key", 0x03}, {"put-authentication-key", 0x02}, {"put-mac-key", 0x14}, {"put-opaque", 0x01}, {"put-otp-aead-key", 0x23}, {"put-public-wrap-key", 0x36}, {"put-symmetric-key", 0x2f}, {"put-template", 0x1b}, {"put-wrap-key", 0x0e}, {"randomize-otp-aead", 0x1f}, {"reset-device", 0x1c}, {"rewrap-from-otp-aead-key", 0x20}, {"rewrap-to-otp-aead-key", 0x21}, {"set-option", 0x11}, {"sign-attestation-certificate", 0x22}, {"sign-ecdsa", 0x07}, {"sign-eddsa", 0x08}, {"sign-hmac", 0x16}, {"sign-pkcs", 0x05}, {"sign-pss", 0x06}, {"sign-ssh-certificate", 0x19}, {"unwrap-data", 0x26}, {"verify-hmac", 0x17}, {"wrap-data", 0x25}, }; static const struct { const char *name; yh_algorithm algorithm; } yh_algorithms[] = { {"aes128", YH_ALGO_AES128}, {"aes192", YH_ALGO_AES192}, {"aes256", YH_ALGO_AES256}, {"aes128-ccm-wrap", YH_ALGO_AES128_CCM_WRAP}, {"aes128-yubico-authentication", YH_ALGO_AES128_YUBICO_AUTHENTICATION}, {"aes128-yubico-otp", YH_ALGO_AES128_YUBICO_OTP}, {"aes192-ccm-wrap", YH_ALGO_AES192_CCM_WRAP}, {"aes192-yubico-otp", YH_ALGO_AES192_YUBICO_OTP}, {"aes256-ccm-wrap", YH_ALGO_AES256_CCM_WRAP}, {"aes256-yubico-otp", YH_ALGO_AES256_YUBICO_OTP}, {"aes-cbc", YH_ALGO_AES_CBC}, {"aes-ecb", YH_ALGO_AES_ECB}, {"aes-kwp", YH_ALGO_AES_KWP}, {"ecbp256", YH_ALGO_EC_BP256}, {"ecbp384", YH_ALGO_EC_BP384}, {"ecbp512", YH_ALGO_EC_BP512}, {"ecdh", YH_ALGO_EC_ECDH}, {"ecdsa-sha1", YH_ALGO_EC_ECDSA_SHA1}, {"ecdsa-sha256", YH_ALGO_EC_ECDSA_SHA256}, {"ecdsa-sha384", YH_ALGO_EC_ECDSA_SHA384}, {"ecdsa-sha512", YH_ALGO_EC_ECDSA_SHA512}, {"eck256", YH_ALGO_EC_K256}, {"ecp224", YH_ALGO_EC_P224}, {"ecp256", YH_ALGO_EC_P256}, {"ecp256-yubico-authentication", YH_ALGO_EC_P256_YUBICO_AUTHENTICATION}, {"ecp384", YH_ALGO_EC_P384}, {"ecp521", YH_ALGO_EC_P521}, {"ed25519", YH_ALGO_EC_ED25519}, {"hmac-sha1", YH_ALGO_HMAC_SHA1}, {"hmac-sha256", YH_ALGO_HMAC_SHA256}, {"hmac-sha384", YH_ALGO_HMAC_SHA384}, {"hmac-sha512", YH_ALGO_HMAC_SHA512}, {"mgf1-sha1", YH_ALGO_MGF1_SHA1}, {"mgf1-sha256", YH_ALGO_MGF1_SHA256}, {"mgf1-sha384", YH_ALGO_MGF1_SHA384}, {"mgf1-sha512", YH_ALGO_MGF1_SHA512}, {"opaque-data", YH_ALGO_OPAQUE_DATA}, {"opaque-x509-certificate", YH_ALGO_OPAQUE_X509_CERTIFICATE}, {"rsa-oaep-sha1", YH_ALGO_RSA_OAEP_SHA1}, {"rsa-oaep-sha256", YH_ALGO_RSA_OAEP_SHA256}, {"rsa-oaep-sha384", YH_ALGO_RSA_OAEP_SHA384}, {"rsa-oaep-sha512", YH_ALGO_RSA_OAEP_SHA512}, {"rsa-pkcs1-decrypt", YH_ALGO_RSA_PKCS1_DECRYPT}, {"rsa-pkcs1-sha1", YH_ALGO_RSA_PKCS1_SHA1}, {"rsa-pkcs1-sha256", YH_ALGO_RSA_PKCS1_SHA256}, {"rsa-pkcs1-sha384", YH_ALGO_RSA_PKCS1_SHA384}, {"rsa-pkcs1-sha512", YH_ALGO_RSA_PKCS1_SHA512}, {"rsa-pss-sha1", YH_ALGO_RSA_PSS_SHA1}, {"rsa-pss-sha256", YH_ALGO_RSA_PSS_SHA256}, {"rsa-pss-sha384", YH_ALGO_RSA_PSS_SHA384}, {"rsa-pss-sha512", YH_ALGO_RSA_PSS_SHA512}, {"rsa2048", YH_ALGO_RSA_2048}, {"rsa3072", YH_ALGO_RSA_3072}, {"rsa4096", YH_ALGO_RSA_4096}, {"template-ssh", YH_ALGO_TEMPLATE_SSH}, }; static const struct { const char *name; yh_object_type type; } yh_types[] = { {"authentication-key", YH_AUTHENTICATION_KEY}, {"asymmetric-key", YH_ASYMMETRIC_KEY}, {"hmac-key", YH_HMAC_KEY}, {"opaque", YH_OPAQUE}, {"otp-aead-key", YH_OTP_AEAD_KEY}, {"public-wrap-key", YH_PUBLIC_WRAP_KEY}, {"symmetric-key", YH_SYMMETRIC_KEY}, {"template", YH_TEMPLATE}, {"wrap-key", YH_WRAP_KEY}, }; static const struct { const char *name; yh_option option; } yh_options[] = { {"command-audit", YH_OPTION_COMMAND_AUDIT}, {"force-audit", YH_OPTION_FORCE_AUDIT}, {"algorithm-toggle", YH_OPTION_ALGORITHM_TOGGLE}, {"fips-mode", YH_OPTION_FIPS_MODE}, }; /// The object was generated on the device #define YH_ORIGIN_GENERATED 0x01 /// The object was imported into the device #define YH_ORIGIN_IMPORTED 0x02 /// The object was imported into the device under wrap. This is used in /// combination with objects original 'origin' #define YH_ORIGIN_IMPORTED_WRAPPED 0x10 /** * Return a string describing an error condition * * @param err #yh_rc error code * * @return String with descriptive error **/ const char *yh_strerror(yh_rc err); /** * Set verbosity level when executing commands. Default verbosity is *#YH_VERB_QUIET * * This function may be called prior to global library initialization to set * the debug level * * @param connector If not NULL, the verbosity of the specific connector will * be set * @param verbosity The desired level of debug output * * @return #YHR_SUCCESS * * @see YH_VERB_QUIET, YH_VERB_INTERMEDIATE, YH_VERB_CRYPTO, YH_VERB_RAW, * YH_VERB_INFO, YH_VERB_ERR, YH_VERB_ALL **/ yh_rc yh_set_verbosity(yh_connector *connector, uint8_t verbosity); /** * Get verbosity level when executing commands * * @param verbosity The verbosity level * * @return #YHR_SUCCESS if seccessful. * #YHR_INVALID_PARAMETERS if verbosity is NULL * * @see YH_VERB_QUIET, YH_VERB_INTERMEDIATE, YH_VERB_CRYPTO, YH_VERB_RAW, * YH_VERB_INFO, YH_VERB_ERR, YH_VERB_ALL **/ yh_rc yh_get_verbosity(uint8_t *verbosity); /** * Set file for debug output * * @param connector If not NULL, the debug messages will be written to the *specified output file * @param output The destination of the debug messages * * @return void **/ void yh_set_debug_output(yh_connector *connector, FILE *output); /** * Global library initialization * * @return #YHR_SUCCESS **/ yh_rc yh_init(void); /** * Global library clean up * * @return #YHR_SUCCESS **/ yh_rc yh_exit(void); /** * Instantiate a new connector * * @param url URL associated with this connector * @param connector Connector to the device * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if either the URL or the connector are NULL. * #YHR_GENERIC_ERROR if failed to load the backend. * #YHR_MEMORY_ERROR if failed to allocate memory for the connector. * #YHR_CONNECTION_ERROR if failed to create the connector */ yh_rc yh_init_connector(const char *url, yh_connector **connector); /** * Set connector options. * * Note that backend options are not supported with winhttp or USB connectors * * @param connector Connector to set an option on * @param opt Option to set. See #yh_connector_option * @param val Value of the option. Type of value is specific to the given *option * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the connector or the value are NULL or if *the option is unknown. #YHR_CONNECTOR_ERROR if failed to set the option **/ yh_rc yh_set_connector_option(yh_connector *connector, yh_connector_option opt, const void *val); /** * Connect to the device through the specified connector * * @param connector Connector to the device * @param timeout Connection timeout in seconds * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the connector does not exist. * See #yh_rc for other possible errors **/ yh_rc yh_connect(yh_connector *connector, int timeout); /** * Disconnect from a connector * * @param connector Connector from which to disconnect * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the connector is NULL **/ yh_rc yh_disconnect(yh_connector *connector); /** * Send a plain (unencrypted) message to the device through a connector * * @param connector Connector to the device * @param cmd Command to send. See #yh_cmd * @param data Data to send * @param data_len length of data to send * @param response_cmd Response command * @param response Response data * @param response_len Length of response data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * #YHR_BUFFER_TOO_SMALL if the actual response was longer than *response_len. See #yh_rc for other possible errors **/ yh_rc yh_send_plain_msg(yh_connector *connector, yh_cmd cmd, const uint8_t *data, size_t data_len, yh_cmd *response_cmd, uint8_t *response, size_t *response_len); /** * Send an encrypted message to the device over a session. The session has to be *authenticated * * @param session Session to send the message over * @param cmd Command to send * @param data Data to send * @param data_len Length of data to send * @param response_cmd Response command * @param response Response data * @param response_len Length of response data * * @return #YHR_SUCCESS if successful. See #yh_rc for possible errors **/ yh_rc yh_send_secure_msg(yh_session *session, yh_cmd cmd, const uint8_t *data, size_t data_len, yh_cmd *response_cmd, uint8_t *response, size_t *response_len); /** * Create a session that uses an encryption key and a MAC key derived from a *password * * @param connector Connector to the device * @param authkey_id Object ID of the Authentication Key used to authenticate *the session * @param password Password used to derive the session encryption key and MAC *key * @param password_len Length of the password in bytes * @param recreate_session If true, the session will be recreated if expired. *This caches the password in memory * @param session The created session * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the connector, the password or the session *are NULL. #YHR_GENERIC_ERROR if failed to derive the session encryption key *and/or the MAC key or if PRNG related errors occur. #YHR_MEMORY_ERROR if *failed to allocate memory for the session. See #yh_rc for other possible *errors * * @see Session **/ yh_rc yh_create_session_derived(yh_connector *connector, uint16_t authkey_id, const uint8_t *password, size_t password_len, bool recreate_session, yh_session **session); /** * Create a session that uses the specified encryption key and MAC key to derive *session-specific keys * * @param connector Connector to the device * @param authkey_id Object ID of the Authentication Key used to authenticate *the session * @param key_enc Key used to derive the session encryption key * @param key_enc_len Length of key_enc * @param key_mac Key used to derive the session MAC keys * @param key_mac_len Length of key_mac * @param recreate_session If true, the session will be recreated if expired. *This caches the password in memory * @param session created session * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or incorrect. * See #yh_rc for other possible errors * * @see Session, * Authentication *Key **/ yh_rc yh_create_session(yh_connector *connector, uint16_t authkey_id, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len, bool recreate_session, yh_session **session); /** * Create a session that uses named encryption keys from a platform-specific key *store to derive session-specific keys * * @param connector Connector to the device * @param authkey_id Object ID of the Authentication Key used to authenticate *the session * @param key_enc_name Name of key used to derive the session encryption key * @param key_mac_name Name of key used to derive the session MAC keys * @param session created session * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or incorrect. * See #yh_rc for other possible errors * * @see Session, * Authentication *Key **/ yh_rc yh_create_session_ex(yh_connector *connector, uint16_t authkey_id, const char *key_enc_name, const char *key_mac_name, yh_session **session); /** * Begin creating a session where the session keys are calculated outside the *library. * * This function must be followed by yh_finish_create_session() to set the * session keys. * * If host_challenge_len is 0 when calling this function an 8 byte random *challenge is generated, and symmetric authentication is assumed. * * For asymmetric authentication the host challenge must be provided. * * @param connector Connector to the device * @param authkey_id Object ID of the Authentication Key used to authenticate *the session * @param context pointer to where context data is saved * @param host_challenge Host challenge * @param host_challenge_len Length of host challenge * @param card_cryptogram Card cryptogram from the device * @param card_cryptogram_len Length of card cryptogram * @param session created session * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * #YHR_MEMORY_ERROR if failed to allocate memory for the session. * See #yh_rc for other possible errors * * @see Session **/ yh_rc yh_begin_create_session(yh_connector *connector, uint16_t authkey_id, uint8_t **context, uint8_t *host_challenge, size_t *host_challenge_len, uint8_t *card_cryptogram, size_t *card_cryptogram_len, yh_session **session); /** * Finish creating a session. * * This function must be called after yh_begin_create_session(). * * For symmetric authentication this function will authenticate the session * with the device using the provided sesion keys and card cryptogram. * * For asymmetric authentication the card cryptogram must be validated *externally. * * @param session The session created with yh_begin_create_session() * @param key_senc Session encryption key used to encrypt the messages exchanged *with the device * @param key_senc_len Lenght of the encryption key. Must be #YH_KEY_LEN * @param key_smac Session MAC key used for creating the authentication tag for *each message * @param key_smac_len Length of the MAC key. Must be #YH_KEY_LEN * @param key_srmac Session return MAC key used for creating the authentication *tag for each response message * @param key_srmac_len Length of the return MAC key. Must be #YH_KEY_LEN * @param card_cryptogram Card cryptogram * @param card_cryptogram_len Length of card cryptogram * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or any of the *key lengths are not #YH_KEY_LEN. * See #yh_rc for other possible errors * * @see Session **/ yh_rc yh_finish_create_session(yh_session *session, const uint8_t *key_senc, size_t key_senc_len, const uint8_t *key_smac, size_t key_smac_len, const uint8_t *key_srmac, size_t key_srmac_len, uint8_t *card_cryptogram, size_t card_cryptogram_len); /** * Utility function that gets the value and algorithm of the device public key * * @param connector Connector to the device * @param device_pubkey Value of the public key * @param device_pubkey_len Length of the public key in bytes * @param algorithm Algorithm of the key. * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * #YHR_BUFFER_TOO_SMALL if the actual key length was bigger than *device_pubkey_len. See #yh_rc for other possible errors **/ yh_rc yh_util_get_device_pubkey(yh_connector *connector, uint8_t *device_pubkey, size_t *device_pubkey_len, yh_algorithm *algorithm); /** * Utility function that derives an ec-p256 key pair from a password using the *following algorithm * * 1. Apply pkcs5_pbkdf2_hmac-sha256 on the password to derive a pseudo-random *private ec-p256 key * 2. Check that the derived key is a valid ec-p256 private key * 3. If not valid append a byte with the value 1 (2, 3, 4 etc for additional *failures) to the password and go to step 1 * 4. Calculate the corresponding public key from the private key and the *ec-p256 curve paramaters * * @param password The password bytes * @param password_len The password length * @param privkey Value of the private key * @param privkey_len Length of the private key in bytes * @param pubkey Value of the public key * @param pubkey_len Length of the public key in bytes * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. See #yh_rc for *other possible errors **/ yh_rc yh_util_derive_ec_p256_key(const uint8_t *password, size_t password_len, uint8_t *privkey, size_t privkey_len, uint8_t *pubkey, size_t pubkey_len); /** * Utility function that generates a random ec-p256 key pair * * @param privkey Value of the private key * @param privkey_len Length of the private key in bytes * @param pubkey Value of the public key * @param pubkey_len Length of the public key in bytes * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. See #yh_rc for *other possible errors **/ yh_rc yh_util_generate_ec_p256_key(uint8_t *privkey, size_t privkey_len, uint8_t *pubkey, size_t pubkey_len); /** * Create a session that uses the specified asymmetric key to derive *session-specific keys. * * @param connector Connector to the device * @param authkey_id Object ID of the Asymmetric Authentication Key used to *authenticate the session * @param privkey Private key of the client, used to derive the session *encryption key and authenticate the client * @param privkey_len Length of the private key. * @param device_pubkey Public key of the device, used to derive the session *encryption key and authenticate the device * @param device_pubkey_len Length of the device public key. * @param session created session * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or incorrect. * See #yh_rc for other possible errors * * @see Session, * Authentication *Key **/ yh_rc yh_create_session_asym(yh_connector *connector, uint16_t authkey_id, const uint8_t *privkey, size_t privkey_len, const uint8_t *device_pubkey, size_t device_pubkey_len, yh_session **session); /** * Free data associated with the session * * @param session Pointer to the session to destroy * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the session is NULL. * * @see Session **/ yh_rc yh_destroy_session(yh_session **session); /** * Deprecated, use yh_begin_create_session instead. **/ yh_rc yh_begin_create_session_ext(yh_connector *connector, uint16_t authkey_id, uint8_t **context, uint8_t *card_cryptogram, size_t card_cryptogram_len, yh_session **session); /** * Deprecated, use yh_finish_create_session instead. **/ yh_rc yh_finish_create_session_ext(yh_connector *connector, yh_session *session, const uint8_t *key_senc, size_t key_senc_len, const uint8_t *key_smac, size_t key_smac_len, const uint8_t *key_srmac, size_t key_srmac_len, uint8_t *card_cryptogram, size_t card_cryptogram_len); /** * Deprecated, calling this function has no effect. **/ yh_rc yh_authenticate_session(yh_session *session); // Utility and convenience functions below /** * Get device info in a struct * * @param connector Connector to the device * @param device_info Device info * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the connector or device_info is NULL. * #YHR_BUFFER_TOO_SMALL if n_algorithms is smaller than the number of *actually supported algorithms. See #yh_rc for other possible errors. * * @see Algorithms **/ yh_rc yh_util_get_device_info_ex(yh_connector *connector, yh_device_info *device_info); /** * Get device version, device serial number, supported algorithms and available *log entries. * * @param connector Connector to the device * @param major Device major version number * @param minor Device minor version number * @param patch Device build version number * @param serial Device serial number * @param log_total Total number of log entries * @param log_used Number of written log entries * @param algorithms List of supported algorithms * @param n_algorithms Number of supported algorithms * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the connector is NULL. * #YHR_BUFFER_TOO_SMALL if n_algorithms is smaller than the number of *actually supported algorithms. See #yh_rc for other possible errors. * * @see Algorithms **/ yh_rc yh_util_get_device_info(yh_connector *connector, uint8_t *major, uint8_t *minor, uint8_t *patch, uint32_t *serial, uint8_t *log_total, uint8_t *log_used, yh_algorithm *algorithms, size_t *n_algorithms); /** * Get device version, part number (chip designator) as required ny FIPS * * @param connector Connector to the device * @param part_number Part number (chip designator) * @param part_number_len Size of part_number * * @return #YHR_SUCCESS if successful or of part_number is NULL * #YHR_DEVICE_INVALID_COMMAND if firmware version does not support the *command * #YHR_INVALID_PARAMETER if the connector is NULL. * #YH_INVALID_DEVICE_INVALID_DATA If returned part_number is less than *12 bytes * #YHR_BUFFER_TOO_SMALL if part_number is smaller than 13 bytes **/ yh_rc yh_util_get_partnumber(yh_connector *connector, char *part_number, size_t *part_number_len); /** * List objects accessible from the session * * @param session Authenticated session to use * @param id Object ID to filter by (0 to not filter by ID) * @param type Object type to filter by (0 to not filter by type). See *#yh_object_type * @param domains Domains to filter by (0 to not filter by domain) * @param capabilities Capabilities to filter by (0 to not filter by *capabilities). See #yh_capabilities * @param algorithm Algorithm to filter by (0 to not filter by algorithm) * @param label Label to filter by * @param objects Array of objects returned * @param n_objects Max number of objects (will be set to number found on *return) * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * #YHR_BUFFER_TOO_SMALL if n_objects is smaller than the number of *objects found. See #yh_rc for other possible errors. * * @see Objects, * Domains, * Capabilities, * Algorithms, * Labels **/ yh_rc yh_util_list_objects(yh_session *session, uint16_t id, yh_object_type type, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const char *label, yh_object_descriptor *objects, size_t *n_objects); /** * Get metadata of the object with the specified Object ID and Type * * @param session Authenticated session to use * @param id Object ID of the object to get * @param type Object type. See #yh_object_type * @param object Object information * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the session is NULL. * See #yh_rc for other possible errors. * * @see Objects **/ yh_rc yh_util_get_object_info(yh_session *session, uint16_t id, yh_object_type type, yh_object_descriptor *object); /** * Get the value of the public key with the specified Object ID * * @param session Authenticated session to use * @param id Object ID of the public key * @param data Value of the public key * @param data_len Length of the public key in bytes * @param algorithm Algorithm of the key * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * #YHR_BUFFER_TOO_SMALL if the actual key length was bigger than *data_len. See #yh_rc for other possible errors **/ yh_rc yh_util_get_public_key(yh_session *session, uint16_t id, uint8_t *data, size_t *data_len, yh_algorithm *algorithm); /** * Get the value of the public key with the specified Object ID and type * * @param session Authenticated session to use * @param id Object ID of the public key * @param type Object type of the public key * @param data Value of the public key * @param data_len Length of the public key in bytes * @param algorithm Algorithm of the key * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * #YHR_BUFFER_TOO_SMALL if the actual key length was bigger than *data_len. See #yh_rc for other possible errors **/ yh_rc yh_util_get_public_key_ex(yh_session *session, yh_object_type type, uint16_t id, uint8_t *data, size_t *data_len, yh_algorithm *algorithm); /** * Close a session * * @param session Session to close * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the session is NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_close_session(yh_session *session); /** * Sign data using RSA-PKCS#1v1.5 * * in is either a raw hashed message (sha1, sha256, sha384 or sha512) *or that with correct digestinfo pre-pended * * @param session Authenticated session to use * @param key_id Object ID of the signing key * @param hashed true if data is only hashed * @param in data to sign * @param in_len length of data to sign * @param out signed data * @param out_len length of signed data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or if *in_len is not 20, 32, 48 or 64. See #yh_rc for other possible errors **/ yh_rc yh_util_sign_pkcs1v1_5(yh_session *session, uint16_t key_id, bool hashed, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Sign data using RSA-PSS * * in is a raw hashed message (sha1, sha256, sha384 or sha512) * * @param session Authenticated session to use * @param key_id Object ID of the signing key * @param in Data to sign * @param in_len Length of data to sign * @param out Signed data * @param out_len Length of signed data * @param salt_len Length of salt * @param mgf1Algo Algorithm for mgf1 (mask generation function for PSS) * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or if *in_len is not 20, 32, 48 or 64. See #yh_rc for other possible errors * * @see PSS *specifications **/ yh_rc yh_util_sign_pss(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len, size_t salt_len, yh_algorithm mgf1Algo); /** * Sign data using ECDSA * * in is a raw hashed message, a truncated hash to the curve length or *a padded hash to the curve length * * @param session Authenticated session to use * @param key_id Object ID of the signing key * @param in Data to sign * @param in_len Length of data to sign * @param out Signed data * @param out_len Length of signed data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or if *in_len is not 20, 28, 34, 48, 64 or 66. See #yh_rc for other possible *errors **/ yh_rc yh_util_sign_ecdsa(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Sign data using EdDSA * * @param session Authenticated session to use * @param key_id Object ID of the signing key * @param in Data to sign * @param in_len Length of data to sign * @param out Signed data * @param out_len Length of signed data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or if *in_len is bigger than YH_MSG_BUF_SIZE-2. See #yh_rc for other *possible errors **/ yh_rc yh_util_sign_eddsa(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Sign data using HMAC * * @param session Authenticated session to use * @param key_id Object ID of the signing key * @param in Data to HMAC * @param in_len Length of data to hmac * @param out HMAC * @param out_len Length of HMAC * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or if *in_len is bigger than YH_MSG_BUF_SIZE-2. See #yh_rc for other *possible errors **/ yh_rc yh_util_sign_hmac(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Get a fixed number of pseudo-random bytes from the device * * @param session Authenticated session to use * @param len Length of pseudo-random data to get * @param out Pseudo-random data out * @param out_len Length of pseudo-random data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_get_pseudo_random(yh_session *session, size_t len, uint8_t *out, size_t *out_len); /** * Import an AES key into the device * * @param session Authenticated session to use * @param key_id Object ID the key. 0 if Object ID should be generated by *the device * @param label Label of the key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs specified as an unsigned int. *See #yh_string_to_domains() * @param capabilities Capabilities of the key. See *#yh_string_to_capabilities() * @param algorithm Algorithm of the key to import. Must be one of: *#YH_ALGO_AES128, #YH_ALGO_AES192 or #YH_ALGO_AES256 * @param key The key to import. * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or the algorithm is *not one of #YH_ALGO_AES128, #YH_ALGO_AES192 or #YH_ALGO_AES256. See *#yh_rc for other possible errors **/ yh_rc yh_util_import_aes_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *key); /** * Import an RSA key into the device * * @param session Authenticated session to use * @param key_id Object ID the key. 0 if Object ID should be generated by *the device * @param label Label of the key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs specified as an unsigned int. *See #yh_string_to_domains() * @param capabilities Capabilities of the key. See *#yh_string_to_capabilities() * @param algorithm Algorithm of the key to import. Must be one of: *#YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 or #YH_ALGO_RSA_4096 * @param p P component of the RSA key to import * @param q Q component of the RSA key to import * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or the algorithm is *not one of #YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 or #YH_ALGO_RSA_4096. See *#yh_rc for other possible errors **/ yh_rc yh_util_import_rsa_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *p, const uint8_t *q); /** * Import an Elliptic Curve key into the device * * @param session Authenticated session to use * @param key_id Object ID of the key. 0 if the Object ID should be generated *by the device * @param label Label of the key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs specified as *an unsigned int. See #yh_string_to_domains() * @param capabilities Capabilities of the key. See *#yh_string_to_capabilities() * @param algorithm Algorithm of the key to import. Must be one of: *#YH_ALGO_EC_P224, #YH_ALGO_EC_P256, #YH_ALGO_EC_K256, #YH_ALGO_EC_BP256, *#YH_ALGO_EC_P384, #YH_ALGO_EC_BP384, #YH_ALGO_EC_BP512 or #YH_ALGO_EC_P521 * @param s the EC key to import * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or the algorithm is *not one of #YH_ALGO_EC_P224, #YH_ALGO_EC_P256, #YH_ALGO_EC_K256, *#YH_ALGO_EC_BP256, #YH_ALGO_EC_P384, #YH_ALGO_EC_BP384, #YH_ALGO_EC_BP512 or *#YH_ALGO_EC_P521. * See #yh_rc for other possible errors **/ yh_rc yh_util_import_ec_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *s); /** * Import an ED key into the device * * @param session Authenticated session to use * @param key_id Object ID of the key will have. 0 if the Object ID should be *generated by the device * @param label Label of the key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs. See #yh_string_to_domains() * @param capabilities Capabilities of the key. See *#yh_string_to_capabilities() * @param algorithm Algorithm of the key to import. Must be #YH_ALGO_EC_ED25519 * @param k the ED key to import * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or the algorithm is *not #YH_ALGO_EC_ED25519. See #yh_rc for other possible errors **/ yh_rc yh_util_import_ed_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *k); /** * Import an HMAC key into the device * * @param session Authenticated session to use * @param key_id Object ID of the key. 0 if the Object ID should be *generated by the device * @param label Label of the key. Maxium length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs. See #yh_string_to_domains() * @param capabilities Capabilities of the key. See *#yh_string_to_capabilities() * @param algorithm Algorithm of the key to import. Must be one of: *#YH_ALGO_HMAC_SHA1, #YH_ALGO_HMAC_SHA256, #YH_ALGO_HMAC_SHA384 *or #YH_ALGO_HMAC_SHA512 * @param key The HMAC key to import * @param key_len Length of the HMAC key to import * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_import_hmac_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *key, size_t key_len); /** * Generate an AES key in the device * * @param session Authenticated session to use * @param key_id Object ID of the key. 0 if the Object ID should be *generated by the device * @param label Label of the key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs. See #yh_string_to_domains() * @param capabilities Capabilities of the key. See *#yh_string_to_capabilities() * @param algorithm Algorithm to use to generate the AES key. Supported *algorithms: #YH_ALGO_AES128, #YH_ALGO_AES192 and #YH_ALGO_AES256 * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or the algorithm is *not one of #YH_ALGO_AES128, #YH_ALGO_AES192 or #YH_ALGO_AES256. * See #yh_rc for other possible errors **/ yh_rc yh_util_generate_aes_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm); /** * Generate an RSA key in the device * * @param session Authenticated session to use * @param key_id Object ID of the key. 0 if the Object ID should be *generated by the device * @param label Label of the key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs. See #yh_string_to_domains() * @param capabilities Capabilities of the key. See *#yh_string_to_capabilities() * @param algorithm Algorithm to use to generate the RSA key. Supported *algorithms: #YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 and #YH_ALGO_RSA_4096 * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or the algorithm is *not one of #YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 or #YH_ALGO_RSA_4096. * See #yh_rc for other possible errors **/ yh_rc yh_util_generate_rsa_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm); /** * Generate an Elliptic Curve key in the device * * @param session Authenticated session to use * @param key_id Object ID of the key. 0 if the Object ID should be generated *by the device * @param label Label of the key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs. See #yh_string_to_domains() * @param capabilities Capabilities of the key. See *#yh_string_to_capabilities() * @param algorithm Algorithm to use to generate the EC key. Supported *algorithm: #YH_ALGO_EC_P224, #YH_ALGO_EC_P256, #YH_ALGO_EC_K256, *#YH_ALGO_EC_BP256, #YH_ALGO_EC_P384, #YH_ALGO_EC_BP384, #YH_ALGO_EC_BP512 and *#YH_ALGO_EC_P521. * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or the algorithm is *not one of #YH_ALGO_EC_P224, #YH_ALGO_EC_P256, #YH_ALGO_EC_K256, *#YH_ALGO_EC_BP256, #YH_ALGO_EC_P384, #YH_ALGO_EC_BP384, #YH_ALGO_EC_BP512 or *#YH_ALGO_EC_P521. * See #yh_rc for other possible errors **/ yh_rc yh_util_generate_ec_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm); /** * Generate an ED key in the device * * @param session Authenticated session to use * @param key_id Object ID of the key. 0 if the Object ID should be generated *by the device * @param label Label for the key. Maximum length #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs. See #yh_string_to_domains() * @param capabilities Capabilities of the ED key. See *#yh_string_to_capabilities() * @param algorithm Algorithm to use to generate the ED key. Supported *algorithm: #YH_ALGO_EC_ED25519 * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or the algorithm is *not #YH_ALGO_EC_ED25519. * See #yh_rc for other possible errors **/ yh_rc yh_util_generate_ed_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm); /** * Verify a generated HMAC * * @param session Authenticated session to use * @param key_id Object ID of the HMAC key * @param signature HMAC signature (20, 32, 48 or 64 bytes) * @param signature_len length of HMAC signature * @param data data to verify * @param data_len length of data to verify * @param verified true if verification succeeded * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or if *signature_len + data_len is too long. * See #yh_rc for other possible errors * **/ yh_rc yh_util_verify_hmac(yh_session *session, uint16_t key_id, const uint8_t *signature, size_t signature_len, const uint8_t *data, size_t data_len, bool *verified); /** * Generate an HMAC key in the device * * @param session Authenticated session to use * @param key_id Object ID of the key. 0 if the Object ID should be *generated by the device * @param label Label of the key. Maximum length #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs. See #yh_string_to_domains() * @param capabilities Capabilities of the key. See *#yh_string_to_capabilities() * @param algorithm Algorithm to use to generate the HMAC key. Supported *algorithims: #YH_ALGO_HMAC_SHA1, #YH_ALGO_HMAC_SHA256, #YH_ALGO_HMAC_SHA384 *and #YH_ALGO_HMAC_SHA512 * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL. * See #yh_rc for other possible errors * **/ yh_rc yh_util_generate_hmac_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm); /** * Decrypt data that was encrypted using RSA-PKCS#1v1.5 * * @param session Authenticated session to use * @param key_id Object ID of the RSA key to use for decryption * @param in Encrypted data * @param in_len Length of encrypted data * @param out Decrypted data * @param out_len Length of decrypted data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or if *in_len is bigger than #YH_MSG_BUF_SIZE-2. * See #yh_rc for other possible errors * **/ yh_rc yh_util_decrypt_pkcs1v1_5(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Decrypt data using RSA-OAEP * * @param session Authenticated session to use * @param key_id Object ID of the RSA key to use for decryption * @param in Encrypted data * @param in_len Length of encrypted data. Must be 256, 384 or 512 * @param out Decrypted data * @param out_len Length of decrypted data * @param label Hash of OAEP label. Hash function must be SHA-1, SHA-256, *SHA-384 or SHA-512 * @param label_len Length of hash of OAEP label. Must be 20, 32, 48 or 64 * @param mgf1Algo MGF1 algorithm * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL. * #YHR_WRONG_LENGTH if in_len or label_len are not *what expected. * See #yh_rc for other possible errors * **/ yh_rc yh_util_decrypt_oaep(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len, const uint8_t *label, size_t label_len, yh_algorithm mgf1Algo); /** * Derive an ECDH key from a private EC key on the device and a provided public *EC key * * @param session Authenticated session to use * @param key_id Object ID of the EC private key to use for ECDH derivation * @param in Public key of another EC key-pair * @param in_len Length of public key * @param out Shared secret ECDH key * @param out_len Length of the shared ECDH key * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS input parameters are NULL or if *in_len is bigger than #YH_MSG_BUF_SIZE-2. * See #yh_rc for other possible errors * **/ yh_rc yh_util_derive_ecdh(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Delete an object in the device * * @param session Authenticated session to use * @param id Object ID of the object to delete * @param type Type of object to delete. See #yh_object_type * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if session is NULL. * See #yh_rc for other possible errors * **/ yh_rc yh_util_delete_object(yh_session *session, uint16_t id, yh_object_type type); /** * Export an object under wrap from the device * * @param session Authenticated session to use * @param wrapping_key_id Object ID of the Wrap Key to use to wrap the object * @param target_type Type of the object to be exported. See #yh_object_type * @param target_id Object ID of the object to be exported * @param out Wrapped data * @param out_len Length of wrapped data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_export_wrapped(yh_session *session, uint16_t wrapping_key_id, yh_object_type target_type, uint16_t target_id, uint8_t *out, size_t *out_len); /** * Export an object under wrap from the device with the option to include the *ED25519 seed * * @param session Authenticated session to use * @param wrapping_key_id Object ID of the Wrap Key to use to wrap the object * @param target_type Type of the object to be exported. See #yh_object_type * @param target_id Object ID of the object to be exported * @param format Curently supported formats: 0=legacy 1=include ED25519 seed * @param out Wrapped data * @param out_len Length of wrapped data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_export_wrapped_ex(yh_session *session, uint16_t wrapping_key_id, yh_object_type target_type, uint16_t target_id, uint8_t format, uint8_t *out, size_t *out_len); /** * Import a wrapped object into the device. The object should have been *previously exported by #yh_util_export_wrapped() * * @param session Authenticated session to use * @param wrapping_key_id Object ID of the Wrap Key to use to unwrap the object * @param in Wrapped data * @param in_len Length of wrapped data * @param target_type Type of the imported object * @param target_id Object ID of the imported object * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_import_wrapped(yh_session *session, uint16_t wrapping_key_id, const uint8_t *in, size_t in_len, yh_object_type *target_type, uint16_t *target_id); /** * Export a (a)symmetric key material using an RSA wrap key, meta data or *properties, like domains and capabilities, are not included. Only asymmetric *and symmetric key objects are valid targets. * * @param session Authenticated session to use * @param wrapping_key_id Object ID of the Wrap Key to use to wrap the object * @param target_type Type of the target key object * @param target_id Object ID of the target key object * @param aes Algorithm of the ephemeral AES key. Can be #YH_ALGO_AES128, *#YH_ALGO_AES192 or #YH_ALGO_AES256 * @param hash Hash algorithm. One of #YH_ALGO_RSA_OAEP_SHA1, *#YH_ALGO_RSA_OAEP_SHA256, #YH_ALGO_RSA_OAEP_SHA384 or #YH_ALGO_RSA_OAEP_SHA512 * @param mgf1 MGF1 algorithm. One of #YH_ALGO_MGF1_SHA1, #YH_ALGO_MGF1_SHA256, *#YH_ALGO_MGF1_SHA384 or #YH_ALGO_MGF1_SHA512 * @param label Label for the MGF1 algorithm * @param label_len Label length * @param out Wrapped key object bytes * @param out_len Length of the wrapped key * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the * command is not supported. * See #yh_rc for other possible errors **/ yh_rc yh_util_get_rsa_wrapped_key(yh_session *session, uint16_t wrap_key_id, yh_object_type target_type, uint16_t target_id, yh_algorithm aes, yh_algorithm hash, yh_algorithm mgf1, const uint8_t *oaep_label, size_t oaep_label_len, uint8_t *out, size_t *out_len); /** * Export an object using an RSA wrap key. The wrapped object contain all meta *data and properties, like domains and capabilities * * @param session Authenticated session to use * @param wrapping_key_id Object ID of the Wrap Key to use to wrap the object * @param target_type Type of the target object * @param target_id Object ID of the target object * @param aes Algorithm of the ephemeral AES key. Can be #YH_ALGO_AES128, *#YH_ALGO_AES192 or #YH_ALGO_AES256 * @param hash Hash algorithm. One of #YH_ALGO_RSA_OAEP_SHA1, *#YH_ALGO_RSA_OAEP_SHA256, #YH_ALGO_RSA_OAEP_SHA384 or #YH_ALGO_RSA_OAEP_SHA512 * @param mgf1 MGF1 algorithm. One of #YH_ALGO_MGF1_SHA1, #YH_ALGO_MGF1_SHA256, *#YH_ALGO_MGF1_SHA384 or #YH_ALGO_MGF1_SHA512 * @param label Label for the MGF1 algorithm * @param label_len Label length * @param out Wrapped object bytes * @param out_len Length of the wrapped object * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the * command is not supported. * See #yh_rc for other possible errors **/ yh_rc yh_util_export_rsa_wrapped(yh_session *session, uint16_t wrap_key_id, yh_object_type target_type, uint16_t target_id, yh_algorithm aes, yh_algorithm hash, yh_algorithm mgf1, const uint8_t *oaep_label, size_t oaep_label_len, uint8_t *out, size_t *out_len); /** * Import an object using an RSA wrap key. * * @param session Authenticated session to use * @param wrapping_key_id Object ID of the Wrap Key to use to unwrap the object * @param hash Hash algorithm. One of #YH_ALGO_RSA_OAEP_SHA1, *#YH_ALGO_RSA_OAEP_SHA256, #YH_ALGO_RSA_OAEP_SHA384 or #YH_ALGO_RSA_OAEP_SHA512 * @param mgf1 MGF1 algorithm. One of #YH_ALGO_MGF1_SHA1, #YH_ALGO_MGF1_SHA256, *#YH_ALGO_MGF1_SHA384 or #YH_ALGO_MGF1_SHA512 * @param label Label for the MGF1 algorithm * @param label_len Label length * @param in Wrapped object bytes * @param in_len Length of the wrapped object * @param target_type Type of the target object * @param target_id Object ID of the target object * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the * command is not supported. * See #yh_rc for other possible errors **/ yh_rc yh_util_import_rsa_wrapped(yh_session *session, uint16_t wrapping_key_id, yh_algorithm hash, yh_algorithm mgf1, const uint8_t *label, size_t label_len, const uint8_t *in, size_t in_len, yh_object_type *target_type, uint16_t *target_id); /** * Import an (a)symmetric key using an RSA wrap key. * * @param session Authenticated session to use * @param wrapping_key_id Object ID of the Wrap Key to use to unwrap the object * @param type Type of object to import. One of #YH_SYMMETRIC_KEY or *#YH_ASYMMETRIC_KEY * @param target_id Object ID of object to import * @param algo Key algorithm of object to import * @param label Label of object to import * @param domains Domains of object to import * @param capabilities of object to import * @param hash Hash algorithm. One of #YH_ALGO_RSA_OAEP_SHA1, *#YH_ALGO_RSA_OAEP_SHA256, #YH_ALGO_RSA_OAEP_SHA384 or #YH_ALGO_RSA_OAEP_SHA512 * @param mgf1 MGF1 algorithm. One of #YH_ALGO_MGF1_SHA1, #YH_ALGO_MGF1_SHA256, *#YH_ALGO_MGF1_SHA384 or #YH_ALGO_MGF1_SHA512 * @param oaep_label Label for the MGF1 algorithm * @param oaep_label_len Label length * @param in Wrapped object bytes * @param in_len Length of the wrapped object * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the * command is not supported. * See #yh_rc for other possible errors **/ yh_rc yh_util_put_rsa_wrapped_key( yh_session *session, uint16_t wrapping_key_id, yh_object_type type, uint16_t *target_id, yh_algorithm algo, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm hash, yh_algorithm mgf1, const uint8_t *oaep_label, size_t oaep_label_len, const uint8_t *in, size_t in_len); /** * Import a Wrap Key into the device * * @param session Authenticated session to use * @param key_id Object ID the Wrap Key. 0 if the Object ID should be generated *by the device * @param label Label of the Wrap Key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains where the Wrap Key will be operating within. See *#yh_string_to_domains() * @param capabilities Capabilities of the Wrap Key. See *#yh_string_to_capabilities() * @param algorithm Algorithm of the Wrap Key. Supported algorithms: *#YH_ALGO_AES128_CCM_WRAP, #YH_ALGO_AES192_CCM_WRAP, *#YH_ALGO_AES256_CCM_WRAP, #YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 and * #YH_ALGO_RSA_4096 * @param delegated_capabilities Delegated capabilities of the Wrap Key. See *#yh_string_to_capabilities() * @param in the Wrap Key to import * @param in_len Length of the Wrap Key to import * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL, in_len *is not what expected based on the algorithm and if the algorithms is not one *of #YH_ALGO_AES128_CCM_WRAP, #YH_ALGO_AES192_CCM_WRAP, *#YH_ALGO_AES256_CCM_WRAP or an RSA key algorithm. #YHR_INVALID_PARAMETERS will * also be returned if the firmware version does not support RSA wrap keys. * See #yh_rc for other possible errors **/ yh_rc yh_util_import_wrap_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const yh_capabilities *delegated_capabilities, const uint8_t *in, size_t in_len); /** * Import a public RSA key as a public wrap Key into the device * * @param session Authenticated session to use * @param key_id Object ID the Wrap Key. 0 if the Object ID should be generated *by the device * @param label Label of the Wrap Key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains where the Wrap Key will be operating within. See *#yh_string_to_domains() * @param capabilities Capabilities of the Wrap Key. See *#yh_string_to_capabilities() * @param algorithm Algorithm of the Public Wrap Key. Supported algorithms: *#YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 and #YH_ALGO_RSA_4096 * @param delegated_capabilities Delegated capabilities of the Wrap Key. See *#yh_string_to_capabilities() * @param in the Public Wrap Key to import in PEM format * @param in_len Length of the Wrap Key to import * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL, in_len *is not what expected based on the algorithm and if the algorithms is not one *of #YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 or #YH_ALGO_RSA_4096. * See #yh_rc for other possible errors **/ yh_rc yh_util_import_public_wrap_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const yh_capabilities *delegated_capabilities, const uint8_t *in, size_t in_len); /** * Generate a Wrap Key that can be used for export, import, wrap data and unwrap *data in the device. * * @param session Authenticated session to use * @param key_id Object ID of the Wrap Key. 0 if the Object ID should be *generated by the device * @param label Label of the Wrap Key. Maximum length #YH_OBJ_LABEL_LEN * @param domains Domains where the Wrap Key will be operating within. See *#yh_string_to_domains() * @param capabilities Capabilities of the Wrap Key. See *#yh_string_to_capabilities() * @param algorithm Algorithm used to generate the Wrap Key * @param delegated_capabilities Delegated capabilitites of the Wrap Key. See *#yh_string_to_capabilities() * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors * * @see yh_object_type **/ yh_rc yh_util_generate_wrap_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const yh_capabilities *delegated_capabilities); /** * Get audit logs from the device. * * When audit enforce is set, if the log buffer is full, no new operations *(other than authentication operations) can be performed unless the log entries *are read by this command and then the log index is set by calling *#yh_util_set_log_index(). * * @param session Authenticated session to use * @param unlogged_boot Number of unlogged boot events. Used if the log buffer *is full and audit enforce is set * @param unlogged_auth Number of unlogged authentication events. Used if the *log buffer is full and audit enforce is set * @param out Log entries on the device * @param n_items Number of log entries * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * #YHR_BUFFER_TOO_SMALL if n_items is smaller than the actual *number of retrieved log entries. * See #yh_rc for other possible errors **/ yh_rc yh_util_get_log_entries(yh_session *session, uint16_t *unlogged_boot, uint16_t *unlogged_auth, yh_log_entry *out, size_t *n_items); /** * Set the index of the last extracted log entry. * * This function should be called after #yh_util_get_log_entries() to inform the *device what the last extracted log entry is so new logs can be written. This *is used when forced auditing is enabled. * * @param session Authenticated session to use * @param index index to set. Should be the same index as the last entry *extracted using #yh_util_get_log_entries() * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the session is NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_set_log_index(yh_session *session, uint16_t index); /** * Get an #YH_OPAQUE object (like an X.509 certificate) from the device * * @param session Authenticated session to use * @param object_id Object ID of the Opaque object * @param out the retrieved Opaque object * @param out_len Length of the retrieved Opaque object * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ 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 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(yh_session *session, uint16_t *object_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *in, size_t in_len); /** * Get an #YH_OPAQUE object (like an X.509 certificate) from the device with an *option to decompress the data * * @param session Authenticated session to use * @param object_id Object ID of the Opaque object * @param out the retrieved Opaque object * @param out_len Length of the retrieved Opaque object * @param stored_len Length of the stored opaque object (compressed objects have *stored_len shorter than out_len) * @param compress Try decompressing the object data before returning it * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_get_opaque_ex(yh_session *session, uint16_t object_id, uint8_t *out, size_t *out_len, size_t *stored_len, bool try_decompress); /** * Import an #YH_OPAQUE object into the device with an option to compress the *data before import * * @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 in the Opaque object to import * @param in_len Length of the Opaque object to import * @param compress Compression option for X509 certificates * @param import_len Number of bytes imported * * @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, const uint8_t *in, size_t in_len, yh_compress_option compress, size_t *import_len); /** * Sign an SSH Certificate request. The function produces a signature that can *then be used to produce the SSH Certificate * * @param session Authenticated session to use * @param key_id Object ID of the key used to sign the request * @param template_id Object ID of the template to use as a certificate template * @param sig_algo Signature algorithm to use to sign the certificate request * @param in Certificate request * @param in_len Length of the certificate request * @param out Signature * @param out_len Length of the signature * * @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_sign_ssh_certificate(yh_session *session, uint16_t key_id, uint16_t template_id, yh_algorithm sig_algo, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Import an #YH_AUTHENTICATION_KEY into the device * * @param session Authenticated session to use * @param key_id Object ID of the imported key. 0 if the Object ID should be *generated by the device * @param label Label of the key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs. See #yh_string_to_domains() * @param capabilities Capabilities of the key. See #yh_string_to_capabilities() * @param delegated_capabilities Delegated capabilities of the key. See *#yh_string_to_capabilities() * @param key_enc Long lived encryption key of the Authentication Key to import * @param key_enc_len Length of the encryption key. Must be #YH_KEY_LEN * @param key_mac Long lived MAC key of the Authentication Key to import * @param key_mac_len Length of the MAC key. Must be #YH_KEY_LEN * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if *key_enc_len or key_mac_len are not the expected values. * See #yh_rc for other possible errors * * @see Authentication *Key **/ yh_rc yh_util_import_authentication_key( yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, const yh_capabilities *delegated_capabilities, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len); /** * Import an #YH_AUTHENTICATION_KEY with long lived keys derived from a password * * @param session Authenticated session to use * @param key_id Object ID of the key. 0 if the Object ID should be generated by *the device * @param label Label of the key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains to which the key belongs. See #yh_string_to_domains() * @param capabilities Capabilities of the key. See #yh_string_to_capabilities() * @param delegated_capabilities Delegated capabilities of the key. See *#yh_string_to_capabilities() * @param password Password used to derive the long lived encryption key and MAC *key of the Athentication Key * @param password_len Length of password * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors * @see Authentication *Key **/ yh_rc yh_util_import_authentication_key_derived( yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, const yh_capabilities *delegated_capabilities, const uint8_t *password, size_t password_len); /** * Replace the long lived encryption key and MAC key associated with an *#YH_AUTHENTICATION_KEY in the device * * @param session Authenticated session to use * @param key_id Object ID of the key to replace * @param key_enc New long lived encryption key * @param key_enc_len Length of the new encryption key. Must be #YH_KEY_LEN * @param key_mac New long lived MAC key * @param key_mac_len Length of the new MAC key. Must be #YH_KEY_LEN * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if *key_enc_len or key_mac_len are not the expected values. * See #yh_rc for other possible errors * * @see Authentication *Key **/ yh_rc yh_util_change_authentication_key(yh_session *session, uint16_t *key_id, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len); /** * Replace the long lived encryption key and MAC key associated with an *#YH_AUTHENTICATION_KEY in the device with keys derived from a password * * @param session Authenticated session to use * @param key_id Object ID of the key to replace * @param password Password to derive the new encryption key and MAC key * @param password_len Length of password * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors * * @see Authentication *Key * **/ yh_rc yh_util_change_authentication_key_derived(yh_session *session, uint16_t *key_id, const uint8_t *password, size_t password_len); /** * Get a #YH_TEMPLATE object from the device * * @param session Authenticated session to use * @param object_id Object ID of the Template to get * @param out The retrieved Template * @param out_len Length of the retrieved Template * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_get_template(yh_session *session, uint16_t object_id, uint8_t *out, size_t *out_len); /** * Import a #YH_TEMPLATE object into the device * * @param session Authenticated session to use * @param object_id Object ID of the Template. 0 if the Object ID should be *generated by the device * @param label Label of the Template. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains the Template will be operating within. See *#yh_string_to_domains() * @param capabilities Capabilities of the Template. See *#yh_string_to_capabilities * @param algorithm Algorithm of the Template * @param in Template to import * @param in_len Length of the Template to import * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if *in_len is too big. * See #yh_rc for other possible errors **/ yh_rc yh_util_import_template(yh_session *session, uint16_t *object_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *in, size_t in_len); /** * Create a Yubico OTP AEAD using the provided data * * @param session Authenticated session to use * @param key_id Object ID of the Otp-aead Key to use * @param key OTP key * @param private_id OTP private id * @param out The created AEAD * @param out_len Length of the created AEAD * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_create_otp_aead(yh_session *session, uint16_t key_id, const uint8_t *key, const uint8_t *private_id, uint8_t *out, size_t *out_len); /** * Create OTP AEAD from random data * * @param session Authenticated session to use * @param key_id Object ID of the Otp-aead Key to use * @param out The created AEAD * @param out_len Length of the created AEAD * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_randomize_otp_aead(yh_session *session, uint16_t key_id, uint8_t *out, size_t *out_len); /** * Decrypt a Yubico OTP and return counters and time information. * * @param session Authenticated session to use * @param key_id Object ID of the key used for decryption * @param aead AEAD as created by #yh_util_create_otp_aead() or *#yh_util_randomize_otp_aead() * @param aead_len Length of AEAD * @param otp OTP * @param useCtr OTP use counter * @param sessionCtr OTP session counter * @param tstph OTP timestamp high * @param tstpl OTP timestamp low * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_decrypt_otp(yh_session *session, uint16_t key_id, const uint8_t *aead, size_t aead_len, const uint8_t *otp, uint16_t *useCtr, uint8_t *sessionCtr, uint8_t *tstph, uint16_t *tstpl); /** * Rewrap an OTP AEAD from one #YH_OTP_AEAD_KEY to another. * * @param session Authenticated session to use * @param id_from Object ID of the AEAD Key to wrap from. * @param id_to Object ID of the AEAD Key to wrap to. * @param aead_in AEAD to unwrap * @param in_len Length of AEAD * @param aead_out The created AEAD * @param out_len Length of output AEAD * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_rewrap_otp_aead(yh_session *session, uint16_t id_from, uint16_t id_to, const uint8_t *aead_in, size_t in_len, uint8_t *aead_out, size_t *out_len); /** * Import an #YH_OTP_AEAD_KEY used for Yubico OTP Decryption * * @param session Authenticated session to use * @param key_id Object ID of the AEAD Key. 0 if the Object ID should be *generated by the device * @param label Label of the AEAD Key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains the AEAD Key will be operating within. See *#yh_string_to_domains() * @param capabilities Capabilities of the AEAD Key. See *#yh_string_to_capabilities() * @param nonce_id Nonce ID * @param in AEAD Key to import * @param in_len Length of AEAD Key to import. Must be 16, 24 or 32 * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if *in_len is not one of 16, 24 or 32. * See #yh_rc for other possible errors **/ yh_rc yh_util_import_otp_aead_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, uint32_t nonce_id, const uint8_t *in, size_t in_len); /** * Generate an #YH_OTP_AEAD_KEY for Yubico OTP decryption in the device. * * @param session Authenticated session to use * @param key_id Object ID of the AEAD Key. 0 if the Object ID should be *generated by the device * @param label Label of the AEAD Key. Maximum length is #YH_OBJ_LABEL_LEN * @param domains Domains the AEAD Key will be operating within. See *#yh_string_to_domains() * @param capabilities Capabilities of the AEAD Key. See *#yh_string_to_capabilities() * @param algorithm Algorithm used to generate the AEAD Key. Supported *algorithms: #YH_ALGO_AES128_YUBICO_OTP, #YH_ALGO_AES192_YUBICO_OTP and *#YH_ALGO_AES256_YUBICO_OTP * @param nonce_id Nonce ID * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_generate_otp_aead_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, uint32_t nonce_id); /** * Get attestation of an Asymmetric Key in the form of an X.509 certificate * * @param session Authenticated session to use * @param key_id Object ID of the Asymmetric Key to attest * @param attest_id Object ID for the key used to sign the attestation *certificate * @param out The attestation certificate * @param out_len Length of the attestation certificate * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_sign_attestation_certificate(yh_session *session, uint16_t key_id, uint16_t attest_id, uint8_t *out, size_t *out_len); /** * Set a device-global option * * @param session Authenticated session to use * @param option Option to set. See #yh_option * @param len Length of option value * @param val Option value * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if session or val are NULL *or if len is too long. * See #yh_rc for other possible errors **/ yh_rc yh_util_set_option(yh_session *session, yh_option option, size_t len, uint8_t *val); /** * Get a device-global option * * @param session Authenticated session to use * @param option Option to get. See #yh_option * @param out Option value * @param out_len Length of option value * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_get_option(yh_session *session, yh_option option, uint8_t *out, size_t *out_len); /** * Report currently free storage. This is reported as free records, free pages *and page size. * * @param session Authenticated session to use * @param total_records Total number of records * @param free_records Number of free records * @param total_pages Total number of pages * @param free_pages Number of free pages * @param page_size Page size in bytes * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the session is NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_get_storage_info(yh_session *session, uint16_t *total_records, uint16_t *free_records, uint16_t *total_pages, uint16_t *free_pages, uint16_t *page_size); /** * Encrypt (wrap) data using a #YH_WRAP_KEY. * * @param session Authenticated session to use * @param key_id Object ID of the Wrap Key to use * @param in Data to wrap * @param in_len Length of data to wrap * @param out Wrapped data * @param out_len Length of the wrapped data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if *in_len is too big. * See #yh_rc for other possible errors **/ yh_rc yh_util_wrap_data(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Decrypt (unwrap) data using a #YH_WRAP_KEY. * * @param session Authenticated session to use * @param key_id Object ID of the Wrap Key to use * @param in Wrapped data * @param in_len Length of wrapped data * @param out Unwrapped data * @param out_len Length of unwrapped data * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if *in_len is too big. * See #yh_rc for other possible errors **/ yh_rc yh_util_unwrap_data(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Encrypt data using a AES #YH_SYMMETRIC_KEY in ECB mode * * @param session Authenticated session to use * @param key_id Object ID of the Symmetric Key to use * @param in Plaintext data * @param in_len Length of plaintext data * @param out Encrypted data * @param out_len Length of encrypted data * * @return #YHR_SUCCESS if successful. See #yh_rc for possible errors. **/ yh_rc yh_util_encrypt_aes_ecb(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Decrypt data using a AES #YH_SYMMETRIC_KEY in ECB mode * * @param session Authenticated session to use * @param key_id Object ID of the Symmetric Key to use * @param in Encrypted data * @param in_len Length of encrypted data * @param out Decrypted data * @param out_len Length of decrypted data * * @return #YHR_SUCCESS if successful. See #yh_rc for possible errors. **/ yh_rc yh_util_decrypt_aes_ecb(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Encrypt data using an AES #YH_SYMMETRIC_KEY in CBC mode * * @param session Authenticated session to use * @param key_id Object ID of the Symmetric Key to use * @param iv The 16-byte initialization vector * @param in Plaintext data * @param in_len Length of plaintext data * @param out Encrypted data * @param out_len Length of encrypted data * * @return #YHR_SUCCESS if successful. See #yh_rc for possible errors. **/ yh_rc yh_util_encrypt_aes_cbc(yh_session *session, uint16_t key_id, const uint8_t iv[16], const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Decrypt data using an AES #YH_SYMMETRIC_KEY in CBC mode * * @param session Authenticated session to use * @param key_id Object ID of the Symmetric Key to use * @param iv The 16-byte initialization vector * @param in Encrypted data * @param in_len Length of encrypted data * @param out Decrypted data * @param out_len Length of decrypted data * * @return #YHR_SUCCESS if successful. See #yh_rc for possible errors. **/ yh_rc yh_util_decrypt_aes_cbc(yh_session *session, uint16_t key_id, const uint8_t iv[16], const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len); /** * Pad data using PKCS #7 padding * * @param buffer Data to be padded * @param length Pointer to the current length of the data * @param size The maximum size of the buffer * @param block_size The block size of the cipher used for encryption, in bytes * * @return If successful, returns #YHR_SUCCESS and sets the contents of * length to the padded length of the buffer. See #yh_rc for * other possible return codes. */ yh_rc yh_util_pad_pkcs7(uint8_t *buffer, size_t *length, size_t size, uint8_t block_size); /** * Unpad data that has PKCS #7 padding * * @warning Unpadding unauthenticated ciphertext provides a padding oracle. * * @param buffer Data to be unpadded * @param length Pointer to the current length of the data * @param block_size The block size of the cipher used for encryption, in bytes * * @return If successful, returns #YHR_SUCCESS and sets the contents of * length to the unpadded length of the buffer. See #yh_rc for * other possible return codes. */ yh_rc yh_util_unpad_pkcs7(uint8_t *buffer, size_t *length, uint8_t block_size); /** * Blink the LED of the device to identify it * * @param session Authenticated session to use * @param seconds Number of seconds to blink * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the session is NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_blink_device(yh_session *session, uint8_t seconds); /** * Factory reset the device. Resets and reboots the device, deletes all Objects *and restores the default #YH_AUTHENTICATION_KEY. * * @param session Authenticated session to use * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if the session is NULL. * See #yh_rc for other possible errors **/ yh_rc yh_util_reset_device(yh_session *session); /** * Get the session ID * * @param session Authenticated session to use * @param sid Session ID * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. **/ yh_rc yh_get_session_id(yh_session *session, uint8_t *sid); /** * Check if the connector has a device connected * * @param connector Connector currently in use * * @return True if the connector is not NULL and there is a device connected to *it. False otherwise **/ bool yh_connector_has_device(yh_connector *connector); /** * Get the connector version * * @param connector Connector currently in use * @param major Connector major version * @param minor Connector minor version * @param patch Connector patch version * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. **/ yh_rc yh_get_connector_version(yh_connector *connector, uint8_t *major, uint8_t *minor, uint8_t *patch); /** * Get connector address * * @param connector Connector currently in use * @param address Pointer to the connector address as string * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. **/ yh_rc yh_get_connector_address(yh_connector *connector, char **const address); /** * Convert capability string to byte array * * @param capability String of capabilities separated by ',', ':' or '|' * @param result Array of #yh_capabilities * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * #YHR_BUFFER_TOO_SMALL if capability is too big * * @par Examples: * * * "get-opaque" => {"\x00\x00\x00\x00\x00\x00\x00\x01"} * * "sign-hmac:verify-hmac|exportable-under-wrap," => *{"\x00\x00\x00\x00\x00\xc1\x00\x00"} * * ",,unwrap-data|:wrap-data,,," => {"\x00\x00\x00\x60\x00\x00\x00\x00"} * * "0x7fffffffffffffff" => {"\x7f\xff\xff\xff\xff\xff\xff\xff"} * * "0xffffffffffffffff" => {"\xff\xff\xff\xff\xff\xff\xff\xff"} * * @see Capability **/ yh_rc yh_string_to_capabilities(const char *capability, yh_capabilities *result); /** * Convert an array of #yh_capabilities into strings separated by ',' * * @param num Array of #yh_capabilities * @param result Array of the capabilies as strings * @param n_result Number of elements in result * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * #YHR_BUFFER_TOO_SMALL if n_result is too small * * @see Capability **/ yh_rc yh_capabilities_to_strings(const yh_capabilities *num, const char *result[], size_t *n_result); /** * Check if a capability is set * * @param capabilities Array of #yh_capabilities * @param capability Capability to check as a string. * * @return True if the capability is in capabilities. False *otherwise * * @par Code sample * * char *capabilities_str = "sign-pkcs,decrypt-pkcs,set-option"; * yh_capabilities capabilities = {{0}}; * yh_string_to_capabilities(capabilities_str, &capabilities); * //yh_check_capability(&capabilities, "something") => false * //yh_check_capability(&capabilities, "sign-pss") => false * //yh_check_capability(&capabilities, "decrypt-pkcs") => true * * @see Capability **/ bool yh_check_capability(const yh_capabilities *capabilities, const char *capability); /** * Merge two sets of capabilities. The resulting set of capabilities contain all *capabilities from both arrays * * @param a Array of #yh_capabilities * @param b Array of #yh_capabilities * @param result Resulting array of #yh_capabilities * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * * @see Capability **/ yh_rc yh_merge_capabilities(const yh_capabilities *a, const yh_capabilities *b, yh_capabilities *result); /** * Filter one set of capabilities with another. The resulting set of *capabilities contains only the capabilities that exist in both sets of input *capabilities * * @param capabilities Array of #yh_capabilities * @param filter Array of #yh_capabilities * @param result Resulting array of #yh_capabilities * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL. * * @see Capability **/ yh_rc yh_filter_capabilities(const yh_capabilities *capabilities, const yh_capabilities *filter, yh_capabilities *result); /** * Check if an algorithm is a supported Symmetric Key AES algorithm. * * Supported AES algorithms: #YH_ALGO_AES128, #YH_ALGO_AES192 and *#YH_ALGO_AES256 * * @param algorithm Algorithm to check. See #yh_algorithm * * @return True if the algorithm is one of the supported AES algorithms. False *otherwise **/ bool yh_is_aes(yh_algorithm algorithm); /** * Check if an algorithm is a supported RSA algorithm. * * Supported RSA algorithms: #YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 and *#YH_ALGO_RSA_4096 * * @param algorithm Algorithm to check. See #yh_algorithm * * @return True if the algorithm is one of the supported RSA algorithms . False *otherwise **/ bool yh_is_rsa(yh_algorithm algorithm); /** * Check if an algorithm is a supported Elliptic Curve algorithm. * * Supported EC algorithms: #YH_ALGO_EC_P224, #YH_ALGO_EC_P256, *#YH_ALGO_EC_P384, #YH_ALGO_EC_P521, #YH_ALGO_EC_K256, #YH_ALGO_EC_BP256, *#YH_ALGO_EC_BP384 and #YH_ALGO_EC_BP512 * * @param algorithm Algorithm to check. See #yh_algorithm * * @return True if the algorithm is one of the supported EC algorithms. False *otherwise **/ bool yh_is_ec(yh_algorithm algorithm); /** * Check if an algorithm is a supported ED algorithm. * * Supported ED algorithms: #YH_ALGO_EC_ED25519 * * @param algorithm algorithm. See #yh_algorithm * * @return True if the algorithm is #YH_ALGO_EC_ED25519. False otherwise **/ bool yh_is_ed(yh_algorithm algorithm); /** * Check if algorithm is a supported HMAC algorithm. * * Supported HMAC algorithms: #YH_ALGO_HMAC_SHA1, #YH_ALGO_HMAC_SHA256, *#YH_ALGO_HMAC_SHA384 and #YH_ALGO_HMAC_SHA512 * * @param algorithm Algorithm to check. See #yh_algorithm * * @return True if the algorithm is one of the supported HMAC algorithms. False *otherwise **/ bool yh_is_hmac(yh_algorithm algorithm); /** * Get the expected key length of a key generated by the given algorithm * * @param algorithm Algorithm to check. See #yh_algorithm * @param result Expected bitlength of a key generated by the algorithm * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if result is NULL or if the *algorithm is no supported by YubiHSM 2. For a list of supported algorithms, *see #yh_algorithm **/ yh_rc yh_get_key_bitlength(yh_algorithm algorithm, size_t *result); /** * Convert an algorithm to its string representation. * * @param algo Algorithm to convert. See #yh_algorithm * @param result The algorithm as a String. "Unknown" if the algorithm is not *supported by YubiHSM 2. * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if result is NULL. * * @see Algorithms **/ yh_rc yh_algo_to_string(yh_algorithm algo, char const **result); /** * Convert a string to an algorithm's numeric value * * @param string Algorithm as string. See #yh_algorithm * @param algo Algorithm numeric value * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the *algorithm is not supported by YubiHSM 2. * * @par Code sample * * yh_algorithm algorithm; * //yh_string_to_algo(NULL, &algorithm) => YHR_INVALID_PARAMETERS * //yh_string_to_algo("something", NULL) => YHR_INVALID_PARAMETERS * //yh_string_to_algo("something", &algorithm) => YHR_INVALID_PARAMETERS * //yh_string_to_algo("rsa-pkcs1-sha1", &algorithm) => *YH_ALGO_RSA_PKCS1_SHA1 * //yh_string_to_algo("rsa2048", &algorithm) => YH_ALGO_RSA_2048 * * @see Algorithms **/ yh_rc yh_string_to_algo(const char *string, yh_algorithm *algo); /** * Convert a #yh_object_type to its string representation * * @param type Type to convert. See #yh_object_type * @param result The type as a String. "Unknown" if the type was not recognized * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if result is NULL. * * @par Code sample * * const char *string; * //yh_type_to_string(0, NULL) => YHR_INVALID_PARAMETERS * //yh_type_to_string(99, &string) => string="Unknown" * //yh_type_to_string(YH_OPAQUE, &string) => string="opaque" * //yh_type_to_string(YH_AUTHENTICATION_KEY, &string) => *string="authentication-key" * * @see Object **/ yh_rc yh_type_to_string(yh_object_type type, char const **result); /** * Convert a string to a type's numeric value * * @param string Type as a String. See #yh_object_type * @param type Type numeric value * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the type *was not recognized. * * @par Code sample * * yh_object_type type; * //yh_string_to_type(NULL, &type) => YHR_INVALID_PARAMETERS * //yh_string_to_type("something", NULL) => YHR_INVALID_PARAMETERS * //yh_string_to_type("something", &type) => YHR_INVALID_PARAMETERS * //yh_string_to_type("opaque", &type) => type=YH_OPAQUE * //yh_string_to_type("authentication-key", &type) => *type=YH_AUTHENTICATION_KEY * * @see Object **/ yh_rc yh_string_to_type(const char *string, yh_object_type *type); /** * Convert a string to an option's numeric value * * @param string Option as string. See #yh_option * @param option Option numeric value * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the option *was not recognized. * * @par Code sample * * yh_option option; * //yh_string_to_option(NULL, &option) => YHR_INVALID_PARAMETERS * //yh_string_to_option("something", NULL) => YHR_INVALID_PARAMETERS * //yh_string_to_option("something", &option) => YHR_INVALID_PARAMETERS * //yh_string_to_option("force-audit", &option) => *option=YH_OPTION_FORCE_AUDIT * * @see Options **/ yh_rc yh_string_to_option(const char *string, yh_option *option); /** * Verify an array of log entries * * @param logs Array of log entries * @param n_items number of log entries * @param last_previous_log Optional pointer to the entry before the first entry *in logs * * @return True if verification succeeds. False otherwise * * @see Logs **/ bool yh_verify_logs(yh_log_entry *logs, size_t n_items, yh_log_entry *last_previous_log); /** * Convert a string to a domain's numeric value. * * The domains string can contain one or several domains separated by ',', ':' *or *'|'. Each domain can be written in decimal or hex format * * @param domains String of domains * @param result Resulting parsed domains as an unsigned int * * @return #YHR_SUCCESS if successful. * #YHR_INVALID_PARAMETERS if input parameters are NULL, if the domains *string is does not contains the expected values * * @par Examples * * * "1" => 1 * * "1,2:3,4|5,6;7,8,9,10,11,12,13,14,15,16" => 0xffff * * "1,16" => 0x8001 * * "16" => 0x8000 * * "16,15" => 0xc000 * * "1,0xf" => 0x4001 * * "0x1,0x2" => 3 * * "0x8888" => 0x8888 * * "0" => 0 * * "all" => 0xffff * * "2" => 2 * * "2:4" => 10 * * @see Domains **/ yh_rc yh_string_to_domains(const char *domains, uint16_t *result); /** * Convert domains parameter to its String representation * * @param domains Encoded domains * @param string Domains as a string * @param max_len Maximum length of the string * * @return #YHR_SUCCESS if successful. * #YHR_BUFFER_TOO_SMALL if max_len is too small * * @par Examples * * * 1 => "1" * * 0x8001 => "1:16" * * 0, "" * * 0xffff => "1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16" * * @see Domains **/ yh_rc yh_domains_to_string(uint16_t domains, char *string, size_t max_len); #ifdef __cplusplus } #endif #ifdef _MSC_VER #pragma strict_gs_check(on) #endif #ifdef FUZZING #include yh_rc compute_cryptogram(const uint8_t *key, uint16_t key_len, uint8_t type, const uint8_t context[SCP_CONTEXT_LEN], uint16_t L, uint8_t *key_out); void increment_ctr(uint8_t *ctr, uint16_t len); #endif #endif yubihsm-shell-2.7.3/lib/yubihsm.c0000644000175000017500000047101515167357110015676 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "yubihsm.h" #include "internal.h" #ifdef __WIN32 #include #else #include #include #include #endif #include #include #include #include #include #include "../common/rand.h" #include "../common/pkcs5.h" #include "../common/hash.h" #include "../common/ecdh.h" #include "../aes_cmac/aes_cmac.h" #include "debug_lib.h" #include "../common/insecure_memzero.h" #include "../ykhsmauth/ykhsmauth.h" #include "data_compress.h" #define STATIC_USB_BACKEND "usb" #define STATIC_HTTP_BACKEND "http" #define STATIC_FUZZ_BACKEND "yhfuzz" // If any of the values in scp.h are changed // they should be mirrored in yubihsm.h #ifdef _MSVC _STATIC_ASSERT(SCP_HOST_CHAL_LEN == YH_HOST_CHAL_LEN); _STATIC_ASSERT(SCP_CONTEXT_LEN == YH_CONTEXT_LEN); _STATIC_ASSERT(SCP_MSG_BUF_SIZE == YH_MSG_BUF_SIZE); _STATIC_ASSERT(SCP_KEY_LEN == YH_KEY_LEN); #define strtok_r strtok_s #define strcasecmp _stricmp #else _Static_assert(SCP_HOST_CHAL_LEN == YH_HOST_CHAL_LEN, "Host challenge length mismatch"); _Static_assert(SCP_CONTEXT_LEN == YH_CONTEXT_LEN, "Context length mismatch"); _Static_assert(SCP_MSG_BUF_SIZE == YH_MSG_BUF_SIZE, "Message buffer size mismatch"); _Static_assert(SCP_KEY_LEN == YH_KEY_LEN, "Message buffer size mismatch"); #endif #define LIST_SEPARATORS ":,;|" #ifdef FUZZING uint8_t _yh_verbosity = 0; FILE *_yh_output = NULL; #else uint8_t _yh_verbosity YH_INTERNAL = 0; FILE *_yh_output YH_INTERNAL = NULL; #endif #define UNUSED(x) (void) (x); static yh_rc compute_full_mac_ex(const uint8_t *data, uint16_t data_len, aes_context *aes_ctx, uint8_t *mac) { aes_cmac_context_t ctx = {0}; if (aes_cmac_init(aes_ctx, &ctx)) { DBG_ERR("aes_cmac_init failed"); return YHR_GENERIC_ERROR; } if (aes_cmac_encrypt(&ctx, data, data_len, mac)) { DBG_ERR("aes_cmac_encrypt failed"); aes_cmac_destroy(&ctx); return YHR_GENERIC_ERROR; } aes_cmac_destroy(&ctx); return YHR_SUCCESS; } static yh_rc compute_full_mac(const uint8_t *data, uint16_t data_len, const uint8_t *key, uint16_t key_len, uint8_t *mac) { aes_context aes_ctx = {0}; if (aes_set_key(key, key_len, &aes_ctx)) { DBG_ERR("aes_set_key failed"); return YHR_GENERIC_ERROR; } yh_rc yrc = compute_full_mac_ex(data, data_len, &aes_ctx, mac); aes_destroy(&aes_ctx); return yrc; } static yh_rc compute_cryptogram_ex(aes_context *aes_ctx, uint8_t type, const uint8_t context[SCP_CONTEXT_LEN], uint16_t L, uint8_t *key_out) { uint8_t n_iterations = 0; uint8_t input[16 + SCP_CONTEXT_LEN] = {0}; uint8_t *ptr = input; if (L == 0x40 || L == 0x80) n_iterations = 1; else if (L == 0xc0 || L == 0x100) n_iterations = 2; else return YHR_INVALID_PARAMETERS; // Label memset(ptr, 0, 11); ptr += 11; *ptr++ = type; // Delimiter byte *ptr++ = 0; // L *ptr++ = (L & 0xff00) >> 8; *ptr++ = (L & 0x00ff); // i *ptr++ = 0x01; // Context memcpy(ptr, context, SCP_CONTEXT_LEN); ptr += SCP_CONTEXT_LEN; aes_cmac_context_t ctx = {0}; if (aes_cmac_init(aes_ctx, &ctx)) { DBG_ERR("aes_cmac_init failed"); return YHR_GENERIC_ERROR; } uint8_t result[2 * SCP_PRF_LEN] = {0}; for (uint8_t i = 0; i < n_iterations; i++) { if (aes_cmac_encrypt(&ctx, input, ptr - input, result + (i * SCP_PRF_LEN))) { DBG_ERR("aes_cmac_encrypt failed"); aes_cmac_destroy(&ctx); return YHR_GENERIC_ERROR; } // Update i input[15]++; } memcpy(key_out, result, L / 8); aes_cmac_destroy(&ctx); return YHR_SUCCESS; } #ifndef FUZZING static #endif yh_rc compute_cryptogram(const uint8_t *key, uint16_t key_len, uint8_t type, const uint8_t context[SCP_CONTEXT_LEN], uint16_t L, uint8_t *key_out) { aes_context aes_ctx = {0}; if (aes_set_key(key, key_len, &aes_ctx)) { DBG_ERR("aes_set_key failed"); return YHR_GENERIC_ERROR; } yh_rc yrc = compute_cryptogram_ex(&aes_ctx, type, context, L, key_out); aes_destroy(&aes_ctx); return yrc; } #ifndef FUZZING static #endif void increment_ctr(uint8_t *ctr, uint16_t len) { while (len > 0) { if (++ctr[--len]) { break; } } } static yh_rc translate_device_error(uint8_t device_error) { enum { _DEVICE_OK = 0x00, // No error _DEVICE_INVALID_COMMAND = 0x01, // Invalid command _DEVICE_INVALID_DATA = 0x02, // Malformed command / invalid data _DEVICE_INVALID_SESSION = 0x03, // Invalid session _DEVICE_AUTHENTICATION_FAILED = 0x04, // Message encryption / verification failed _DEVICE_SESSIONS_FULL = 0x05, // All sessions are allocated _DEVICE_SESSION_FAILED = 0x06, // Session creation failed _DEVICE_STORAGE_FAILED = 0x07, // Storage failure _DEVICE_WRONG_LENGTH = 0x08, // Wrong length _DEVICE_INSUFFICIENT_PERMISSIONS = 0x09, // Wrong permissions for operation _DEVICE_LOG_FULL = 0x0a, // Log buffer is full and forced audit is set _DEVICE_OBJECT_NOT_FOUND = 0x0b, // Object not found _DEVICE_INVALID_ID = 0x0c, // Invalid ID _DEVICE_SSH_CA_CONSTRAINT_VIOLIATION = 0x0e, // CA constraint violation _DEVICE_INVALID_OTP = 0x0f, // Invalid OTP _DEVICE_DEMO_MODE = 0x10, // Demo mode, power cycle device _DEVICE_OBJECT_EXISTS = 0x11, // Object with that ID already exists _DEVICE_ALGORITHM_DISABLED = 0x12, // Algorithm is disabled _DEVICE_COMMAND_UNEXECUTED = 0xff, // The command execution has not terminated }; switch (device_error) { case _DEVICE_OK: return YHR_DEVICE_OK; case _DEVICE_INVALID_COMMAND: return YHR_DEVICE_INVALID_COMMAND; case _DEVICE_INVALID_DATA: return YHR_DEVICE_INVALID_DATA; case _DEVICE_INVALID_SESSION: return YHR_DEVICE_INVALID_SESSION; case _DEVICE_AUTHENTICATION_FAILED: return YHR_DEVICE_AUTHENTICATION_FAILED; case _DEVICE_SESSIONS_FULL: return YHR_DEVICE_SESSIONS_FULL; case _DEVICE_SESSION_FAILED: return YHR_DEVICE_SESSION_FAILED; case _DEVICE_STORAGE_FAILED: return YHR_DEVICE_STORAGE_FAILED; case _DEVICE_WRONG_LENGTH: return YHR_DEVICE_WRONG_LENGTH; case _DEVICE_INSUFFICIENT_PERMISSIONS: return YHR_DEVICE_INSUFFICIENT_PERMISSIONS; case _DEVICE_LOG_FULL: return YHR_DEVICE_LOG_FULL; case _DEVICE_OBJECT_NOT_FOUND: return YHR_DEVICE_OBJECT_NOT_FOUND; case _DEVICE_INVALID_ID: return YHR_DEVICE_INVALID_ID; case _DEVICE_SSH_CA_CONSTRAINT_VIOLIATION: return YHR_DEVICE_SSH_CA_CONSTRAINT_VIOLATION; case _DEVICE_INVALID_OTP: return YHR_DEVICE_INVALID_OTP; case _DEVICE_DEMO_MODE: return YHR_DEVICE_DEMO_MODE; case _DEVICE_OBJECT_EXISTS: return YHR_DEVICE_OBJECT_EXISTS; case _DEVICE_ALGORITHM_DISABLED: return YHR_DEVICE_ALGORITHM_DISABLED; case _DEVICE_COMMAND_UNEXECUTED: return YHR_DEVICE_COMMAND_UNEXECUTED; } return YHR_GENERIC_ERROR; } static yh_rc check_buffer_len(yh_connector *connector, size_t msg_len) { size_t max_message_size = SCP_MSG_BUF_SIZE; if (connector->device_info.major < 2 || (connector->device_info.major == 2 && connector->device_info.minor < 4)) { max_message_size = 2048; } if (msg_len > max_message_size) { DBG_ERR("%s (%zu > %zu)", yh_strerror(YHR_BUFFER_TOO_SMALL), msg_len, max_message_size); return YHR_BUFFER_TOO_SMALL; } return YHR_SUCCESS; } static yh_rc send_msg(yh_connector *connector, Msg *msg, Msg *response, const char *identifier) { if (connector == NULL || connector->bf == NULL) { DBG_ERR("No backend loaded"); return YHR_INVALID_PARAMETERS; } DBG_NET(msg, dump_msg); yh_rc yrc = connector->bf->backend_send_msg(connector->connection, msg, response, identifier); if (yrc == YHR_SUCCESS) { if (ntohs(response->st.len) > sizeof(response->st.data)) { return YHR_WRONG_LENGTH; } DBG_NET(response, dump_response); } return yrc; } yh_rc yh_send_plain_msg(yh_connector *connector, yh_cmd cmd, const uint8_t *data, size_t data_len, yh_cmd *response_cmd, uint8_t *response, size_t *response_len) { if (connector == NULL || (data_len != 0 && data == NULL) || response_cmd == NULL || response == NULL || response_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } Msg msg = {0}; Msg response_msg = {0}; yh_rc yrc = check_buffer_len(connector, data_len + 3); if (yrc != YHR_SUCCESS) { return yrc; } msg.st.cmd = cmd; msg.st.len = htons(data_len); if (data_len > 0) { memcpy(msg.st.data, data, data_len); } yrc = send_msg(connector, &msg, &response_msg, NULL); if (yrc != YHR_SUCCESS) { DBG_ERR("send_msg %s", yh_strerror(yrc)); return yrc; } uint16_t len = ntohs(response_msg.st.len); *response_cmd = response_msg.st.cmd; if (*response_len < len) { DBG_ERR("%s (received %u Bytes, can fit %zu Bytes) ", yh_strerror(YHR_BUFFER_TOO_SMALL), len, *response_len); *response_len = len; return YHR_BUFFER_TOO_SMALL; } *response_len = len; memcpy(response, response_msg.st.data, len); return (*response_cmd == YHC_ERROR) ? translate_device_error(response[0]) : YHR_SUCCESS; } static yh_rc send_authenticated_msg(Scp_ctx *session, Msg *msg, Msg *resp, bool require_resp) { DBG_NET(msg, dump_msg); uint16_t len = ntohs(msg->st.len); uint16_t raw_len = len + 3; yh_rc yrc = check_buffer_len(session->parent, raw_len + SCP_MAC_LEN); if (yrc != YHR_SUCCESS) { return yrc; } msg->st.len = htons(len + SCP_MAC_LEN); uint8_t mac_buf[SCP_PRF_LEN + sizeof(Msg)] = {0}; memcpy(mac_buf, session->mac_chaining_value, SCP_PRF_LEN); memcpy(mac_buf + SCP_PRF_LEN, msg->raw, raw_len); yrc = compute_full_mac(mac_buf, SCP_PRF_LEN + raw_len, session->s_mac, SCP_KEY_LEN, session->mac_chaining_value); if (yrc != YHR_SUCCESS) { DBG_ERR("compute_full_mac %s", yh_strerror(yrc)); return yrc; } memcpy(msg->st.data + len, session->mac_chaining_value, SCP_MAC_LEN); yrc = send_msg(session->parent, msg, resp, session->identifier); if (yrc != YHR_SUCCESS) { DBG_ERR("send_msg %s", yh_strerror(yrc)); return yrc; } len = ntohs(resp->st.len); if (len >= SCP_MAC_LEN) { raw_len = 3 + len - SCP_MAC_LEN; memcpy(mac_buf, session->mac_chaining_value, SCP_PRF_LEN); memcpy(mac_buf + SCP_PRF_LEN, resp->raw, raw_len); uint8_t host_mac[SCP_PRF_LEN] = {0}; yrc = compute_full_mac(mac_buf, SCP_PRF_LEN + raw_len, session->s_rmac, SCP_KEY_LEN, host_mac); if (yrc != YHR_SUCCESS) { DBG_ERR("compute_full_mac %s", yh_strerror(yrc)); return yrc; } len -= SCP_MAC_LEN; resp->st.len = htons(len); if (memcmp(host_mac, resp->st.data + len, SCP_MAC_LEN)) { DBG_ERR("Bad MAC received"); yrc = YHR_MAC_MISMATCH; } } else if (require_resp) { if (len != 1 || resp->st.cmd != YHC_ERROR) { DBG_ERR("No MAC received"); yrc = YHR_MAC_MISMATCH; } } DBG_NET(resp, dump_response); return yrc; } static yh_rc send_encrypted_msg(Scp_ctx *session, yh_cmd cmd, const uint8_t *data, size_t data_len, yh_cmd *response_cmd, uint8_t *response, size_t *response_len) { if (session == NULL || (data_len != 0 && data == NULL) || data_len > SCP_MSG_BUF_SIZE || response_cmd == NULL || response == NULL || response_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } // Payload { cmd | cmd_len | data } uint16_t len = 3 + data_len; // Padded payload { cmd | cmd_len | data | padding 1-16 bytes } if (aes_add_padding(NULL, 0, &len)) { return YHR_INVALID_PARAMETERS; } // Outer command { cmd | cmd_len | sid | encrypted payload | mac } yh_rc yrc = check_buffer_len(session->parent, 3 + 1 + len + SCP_MAC_LEN); if (yrc != YHR_SUCCESS) { return yrc; } Msg msg = {0}, enc_msg = {0}; msg.st.cmd = cmd; msg.st.len = htons(data_len); if (data_len > 0) { memcpy(msg.st.data, data, data_len); } DBG_NET(&msg, dump_msg); len = 3 + data_len; if (aes_add_padding(msg.raw, sizeof(msg.raw), &len)) { return YHR_INVALID_PARAMETERS; } aes_context aes_ctx = {0}; if (aes_set_key(session->s_enc, SCP_KEY_LEN, &aes_ctx)) { DBG_ERR("aes_set_key %s", yh_strerror(YHR_GENERIC_ERROR)); return YHR_GENERIC_ERROR; } uint8_t encrypted_ctr[AES_BLOCK_SIZE]; if (aes_encrypt(session->ctr, encrypted_ctr, &aes_ctx)) { DBG_ERR("aes_encrypt %s", yh_strerror(YHR_GENERIC_ERROR)); yrc = YHR_GENERIC_ERROR; goto cleanup; } enc_msg.st.cmd = YHC_SESSION_MESSAGE; enc_msg.st.len = htons(len + 1); enc_msg.st.data[0] = session->sid; if (aes_cbc_encrypt(msg.raw, enc_msg.st.data + 1, len, encrypted_ctr, &aes_ctx)) { DBG_ERR("aes_cbc_encrypt %s", yh_strerror(YHR_GENERIC_ERROR)); yrc = YHR_GENERIC_ERROR; goto cleanup; } yrc = send_authenticated_msg(session, &enc_msg, &msg, true); if (yrc != YHR_SUCCESS) { DBG_ERR("send_authenticated_msg %s", yh_strerror(yrc)); goto cleanup; } if (msg.st.cmd == YHC_ERROR) { yrc = translate_device_error(msg.st.data[0]); DBG_ERR("%s", yh_strerror(yrc)); *response_cmd = YHC_ERROR; response[0] = msg.st.data[0]; *response_len = 1; goto cleanup; } if (session->sid != msg.st.data[0]) { DBG_ERR("Session ID mismatch, expected %d, got %d", session->sid, msg.st.data[0]); yrc = YHR_DEVICE_INVALID_SESSION; goto cleanup; } len = ntohs(msg.st.len); // The minimum message is { sid | 1 aes block } if (len < 1 + AES_BLOCK_SIZE) { DBG_ERR("%s", yh_strerror(YHR_BUFFER_TOO_SMALL)); yrc = YHR_BUFFER_TOO_SMALL; goto cleanup; } len -= 1; if (aes_cbc_decrypt(msg.st.data + 1, enc_msg.raw, len, encrypted_ctr, &aes_ctx)) { DBG_ERR("aes_cbc_decrypt %s", yh_strerror(YHR_GENERIC_ERROR)); yrc = YHR_GENERIC_ERROR; goto cleanup; } aes_remove_padding(enc_msg.raw, &len); if (len < 3 || len - 3 != ntohs(enc_msg.st.len)) { DBG_ERR("aes_remove_padding %s", yh_strerror(YHR_WRONG_LENGTH)); yrc = YHR_WRONG_LENGTH; goto cleanup; } increment_ctr(session->ctr, SCP_PRF_LEN); DBG_NET(&enc_msg, dump_response); *response_cmd = enc_msg.st.cmd; len -= 3; if (*response_len < len) { DBG_ERR("%s (received %u Bytes, can fit %zu Bytes) ", yh_strerror(YHR_BUFFER_TOO_SMALL), len, *response_len); *response_len = len; yrc = YHR_BUFFER_TOO_SMALL; goto cleanup; } memcpy(response, enc_msg.st.data, len); *response_len = len; if (*response_cmd == YHC_ERROR) { yrc = translate_device_error(response[0]); } cleanup: aes_destroy(&aes_ctx); insecure_memzero(&msg, sizeof(msg)); insecure_memzero(&enc_msg, sizeof(enc_msg)); return yrc; } yh_rc yh_send_secure_msg(yh_session *session, yh_cmd cmd, const uint8_t *data, size_t data_len, yh_cmd *response_cmd, uint8_t *response, size_t *response_len) { size_t saved_len = *response_len; yh_rc yrc = send_encrypted_msg(&session->s, cmd, data, data_len, response_cmd, response, response_len); if ((yrc == YHR_DEVICE_INVALID_SESSION || yrc == YHR_DEVICE_AUTHENTICATION_FAILED) && session->authkey_id) { DBG_INFO("Recreating session"); yrc = yh_create_session(session->s.parent, session->authkey_id, session->key_enc, SCP_KEY_LEN, session->key_mac, SCP_KEY_LEN, true, &session); if (yrc != YHR_SUCCESS) { return yrc; } *response_len = saved_len; yrc = send_encrypted_msg(&session->s, cmd, data, data_len, response_cmd, response, response_len); } return yrc; } static yh_rc derive_key(const uint8_t *password, size_t password_len, uint8_t *key, size_t key_len) { if (!pkcs5_pbkdf2_hmac(password, password_len, (const uint8_t *) YH_DEFAULT_SALT, strlen(YH_DEFAULT_SALT), YH_DEFAULT_ITERS, _SHA256, key, key_len)) { return YHR_GENERIC_ERROR; } return YHR_SUCCESS; } yh_rc yh_create_session_derived(yh_connector *connector, uint16_t authkey_id, const uint8_t *password, size_t password_len, bool recreate, yh_session **session) { if (connector == NULL || password == NULL || session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t key[2 * SCP_KEY_LEN] = {0}; yh_rc yrc = derive_key(password, password_len, key, sizeof(key)); if (yrc == YHR_SUCCESS) { yrc = yh_create_session(connector, authkey_id, key, SCP_KEY_LEN, key + SCP_KEY_LEN, SCP_KEY_LEN, recreate, session); insecure_memzero(key, sizeof(key)); } return yrc; } yh_rc yh_create_session(yh_connector *connector, uint16_t authkey_id, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len, bool recreate, yh_session **session) { if (connector == NULL || key_enc == NULL || key_enc_len != SCP_KEY_LEN || key_mac == NULL || key_mac_len != SCP_KEY_LEN || session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } yh_session *new_session = *session; uint8_t host_challenge[SCP_HOST_CHAL_LEN] = {0}; size_t host_challenge_len = 0; uint8_t card_cryptogram[SCP_CARD_CRYPTO_LEN] = {0}; size_t card_cryptogram_len = sizeof(card_cryptogram); yh_rc yrc = yh_begin_create_session(connector, authkey_id, NULL, host_challenge, &host_challenge_len, card_cryptogram, &card_cryptogram_len, &new_session); if (yrc != YHR_SUCCESS) goto cs_failure; // Derive session keys yrc = compute_cryptogram(key_enc, key_enc_len, SCP_S_ENC_DERIVATION, new_session->context, SCP_KEY_LEN * 8, new_session->s.s_enc); if (yrc != YHR_SUCCESS) goto cs_failure; yrc = compute_cryptogram(key_mac, key_mac_len, SCP_S_MAC_DERIVATION, new_session->context, SCP_KEY_LEN * 8, new_session->s.s_mac); if (yrc != YHR_SUCCESS) goto cs_failure; yrc = compute_cryptogram(key_mac, key_mac_len, SCP_S_RMAC_DERIVATION, new_session->context, SCP_KEY_LEN * 8, new_session->s.s_rmac); if (yrc != YHR_SUCCESS) goto cs_failure; yrc = yh_finish_create_session(new_session, new_session->s.s_enc, YH_KEY_LEN, new_session->s.s_mac, YH_KEY_LEN, new_session->s.s_rmac, YH_KEY_LEN, card_cryptogram, card_cryptogram_len); if (yrc != YHR_SUCCESS) goto cs_failure; if (recreate) { new_session->authkey_id = authkey_id; if (new_session->key_enc != key_enc) memcpy(new_session->key_enc, key_enc, SCP_KEY_LEN); if (new_session->key_mac != key_mac) memcpy(new_session->key_mac, key_mac, SCP_KEY_LEN); } else { new_session->authkey_id = 0; memset(new_session->key_enc, 0, SCP_KEY_LEN); memset(new_session->key_mac, 0, SCP_KEY_LEN); } *session = new_session; return YHR_SUCCESS; cs_failure: // Only clear and free if we didn't reuse the session if (new_session != *session) { insecure_memzero(new_session, sizeof(yh_session)); free(new_session); new_session = NULL; } DBG_ERR("%s", yh_strerror(yrc)); return yrc; } yh_rc yh_create_session_ex(yh_connector *connector, uint16_t authkey_id, const char *key_enc_name, const char *key_mac_name, yh_session **session) { if (connector == NULL || key_enc_name == NULL || key_mac_name == NULL || session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } yh_session *new_session = *session; uint8_t host_challenge[SCP_HOST_CHAL_LEN] = {0}; size_t host_challenge_len = 0; uint8_t card_cryptogram[SCP_CARD_CRYPTO_LEN] = {0}; size_t card_cryptogram_len = sizeof(card_cryptogram); aes_context enc_ctx = {0}; aes_context mac_ctx = {0}; yh_rc yrc = yh_begin_create_session(connector, authkey_id, NULL, host_challenge, &host_challenge_len, card_cryptogram, &card_cryptogram_len, &new_session); if (yrc != YHR_SUCCESS) goto cs_failure; // Derive session keys if (aes_load_key(key_enc_name, &enc_ctx)) { DBG_ERR("aes_load_key %s failed", key_enc_name); yrc = YHR_GENERIC_ERROR; goto cs_failure; } yrc = compute_cryptogram_ex(&enc_ctx, SCP_S_ENC_DERIVATION, new_session->context, SCP_KEY_LEN * 8, new_session->s.s_enc); if (yrc != YHR_SUCCESS) goto cs_failure; if (aes_load_key(key_mac_name, &mac_ctx)) { DBG_ERR("aes_load_key %s failed", key_mac_name); yrc = YHR_GENERIC_ERROR; goto cs_failure; } yrc = compute_cryptogram_ex(&mac_ctx, SCP_S_MAC_DERIVATION, new_session->context, SCP_KEY_LEN * 8, new_session->s.s_mac); if (yrc != YHR_SUCCESS) goto cs_failure; yrc = compute_cryptogram_ex(&mac_ctx, SCP_S_RMAC_DERIVATION, new_session->context, SCP_KEY_LEN * 8, new_session->s.s_rmac); if (yrc != YHR_SUCCESS) goto cs_failure; yrc = yh_finish_create_session(new_session, new_session->s.s_enc, YH_KEY_LEN, new_session->s.s_mac, YH_KEY_LEN, new_session->s.s_rmac, YH_KEY_LEN, card_cryptogram, card_cryptogram_len); if (yrc != YHR_SUCCESS) goto cs_failure; aes_destroy(&enc_ctx); aes_destroy(&mac_ctx); new_session->authkey_id = 0; memset(new_session->key_enc, 0, SCP_KEY_LEN); memset(new_session->key_mac, 0, SCP_KEY_LEN); *session = new_session; return YHR_SUCCESS; cs_failure: aes_destroy(&enc_ctx); aes_destroy(&mac_ctx); // Only clear and free if we didn't reuse the session if (new_session != *session) { insecure_memzero(new_session, sizeof(yh_session)); free(new_session); new_session = NULL; } DBG_ERR("%s", yh_strerror(yrc)); return yrc; } yh_rc yh_begin_create_session_ext(yh_connector *connector, uint16_t authkey_id, uint8_t **context, uint8_t *card_cryptogram, size_t card_cryptogram_len, yh_session **session) { uint8_t host_challenge[SCP_HOST_CHAL_LEN] = {0}; size_t host_challenge_len = 0; return yh_begin_create_session(connector, authkey_id, context, host_challenge, &host_challenge_len, card_cryptogram, &card_cryptogram_len, session); } yh_rc yh_begin_create_session(yh_connector *connector, uint16_t authkey_id, uint8_t **context, uint8_t *host_challenge, size_t *host_challenge_len, uint8_t *card_cryptogram, size_t *card_cryptogram_len, yh_session **session) { if (connector == NULL || host_challenge == NULL || host_challenge_len == NULL || card_cryptogram == NULL || card_cryptogram_len == NULL || session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (*host_challenge_len == 0) { if (!rand_generate(host_challenge, SCP_HOST_CHAL_LEN)) { DBG_ERR("Failed getting randomness"); return YHR_GENERIC_ERROR; } *host_challenge_len = SCP_HOST_CHAL_LEN; } DBG_INT(host_challenge, *host_challenge_len, "Host challenge: "); switch (*host_challenge_len) { case SCP_HOST_CHAL_LEN: if (*card_cryptogram_len < SCP_CARD_CRYPTO_LEN) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } *card_cryptogram_len = SCP_CARD_CRYPTO_LEN; break; case YH_EC_P256_PUBKEY_LEN: if (*card_cryptogram_len < SCP_KEY_LEN) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } *card_cryptogram_len = SCP_KEY_LEN; break; default: return YHR_INVALID_PARAMETERS; } yh_session *new_session; if (!*session) { new_session = calloc(1, sizeof(yh_session)); if (new_session == NULL) { DBG_ERR("%s", yh_strerror(YHR_MEMORY_ERROR)); return YHR_MEMORY_ERROR; } } else { new_session = *session; } // Save link back to connector new_session->s.parent = connector; memcpy(new_session->context, host_challenge, *host_challenge_len); yh_rc yrc = YHR_SUCCESS; uint8_t identifier[8] = {0}; if (!rand_generate(identifier, sizeof(identifier))) { DBG_ERR("Failed getting randomness"); yrc = YHR_GENERIC_ERROR; goto bcse_failure; } snprintf(new_session->s.identifier, 17, "%02x%02x%02x%02x%02x%02x%02x%02x", identifier[0], identifier[1], identifier[2], identifier[3], identifier[4], identifier[5], identifier[6], identifier[7]); Msg msg = {0}; Msg response_msg = {0}; yrc = check_buffer_len(connector, SCP_AUTHKEY_ID_LEN + *host_challenge_len + 3); if (yrc != YHR_SUCCESS) { goto bcse_failure; } // Send CREATE SESSION command msg.st.cmd = YHC_CREATE_SESSION; msg.st.len = htons(SCP_AUTHKEY_ID_LEN + *host_challenge_len); uint16_t authkey_id_n = htons(authkey_id); memcpy(msg.st.data, &authkey_id_n, SCP_AUTHKEY_ID_LEN); memcpy(msg.st.data + SCP_AUTHKEY_ID_LEN, host_challenge, *host_challenge_len); yrc = send_msg(connector, &msg, &response_msg, new_session->s.identifier); if (yrc != YHR_SUCCESS) { DBG_ERR("send_msg %s", yh_strerror(yrc)); goto bcse_failure; } // Parse response if (response_msg.st.cmd != YHC_CREATE_SESSION_R) { yrc = translate_device_error(response_msg.st.data[0]); DBG_ERR("Device error %s (%d)", yh_strerror(yrc), response_msg.st.data[0]); goto bcse_failure; } if (ntohs(response_msg.st.len) != 1 + *host_challenge_len + *card_cryptogram_len) { yrc = YHR_WRONG_LENGTH; goto bcse_failure; } uint8_t *ptr = response_msg.st.data; // Save sid new_session->s.sid = (*ptr++); DBG_INFO("Received Session ID: %d", new_session->s.sid); // Save card challenge memcpy(new_session->context + *host_challenge_len, ptr, *host_challenge_len); ptr += *host_challenge_len; DBG_INT(new_session->context + *host_challenge_len, *host_challenge_len, "Card challenge: "); memcpy(card_cryptogram, ptr, *card_cryptogram_len); ptr += *card_cryptogram_len; DBG_INT(card_cryptogram, *card_cryptogram_len, "Card cryptogram: "); *session = new_session; if (context) *context = new_session->context; return YHR_SUCCESS; bcse_failure: // Only clear and free if we didn't reuse the session if (new_session != *session) { insecure_memzero(new_session, sizeof(yh_session)); free(new_session); new_session = NULL; } DBG_ERR("%s", yh_strerror(yrc)); return yrc; } yh_rc yh_finish_create_session_ext(yh_connector *connector, yh_session *session, const uint8_t *key_senc, size_t key_senc_len, const uint8_t *key_smac, size_t key_smac_len, const uint8_t *key_srmac, size_t key_srmac_len, uint8_t *card_cryptogram, size_t card_cryptogram_len) { if (connector != session->s.parent) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } return yh_finish_create_session(session, key_senc, key_senc_len, key_smac, key_smac_len, key_srmac, key_srmac_len, card_cryptogram, card_cryptogram_len); } yh_rc yh_finish_create_session(yh_session *session, const uint8_t *key_senc, size_t key_senc_len, const uint8_t *key_smac, size_t key_smac_len, const uint8_t *key_srmac, size_t key_srmac_len, uint8_t *card_cryptogram, size_t card_cryptogram_len) { if (session == NULL || key_senc == NULL || key_senc_len != SCP_KEY_LEN || key_smac == NULL || key_smac_len != SCP_KEY_LEN || key_srmac == NULL || key_srmac_len != SCP_KEY_LEN || card_cryptogram == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (session->s.s_enc != key_senc) memcpy(session->s.s_enc, key_senc, SCP_KEY_LEN); if (session->s.s_mac != key_smac) memcpy(session->s.s_mac, key_smac, SCP_KEY_LEN); if (session->s.s_rmac != key_srmac) memcpy(session->s.s_rmac, key_srmac, SCP_KEY_LEN); DBG_INT(session->s.s_enc, SCP_KEY_LEN, "S-ENC: "); DBG_INT(session->s.s_mac, SCP_KEY_LEN, "S-MAC: "); DBG_INT(session->s.s_rmac, SCP_KEY_LEN, "S-RMAC: "); if (card_cryptogram_len == SCP_KEY_LEN) { // Validation of receipt is assumed to be done externally // since it can't be calculated from session keys // Initial mac chaining value is the receipt memcpy(session->s.mac_chaining_value, card_cryptogram, SCP_PRF_LEN); } else if (card_cryptogram_len == SCP_CARD_CRYPTO_LEN) { memset(session->s.mac_chaining_value, 0, SCP_PRF_LEN); // Verify card cryptogram uint8_t computed_cryptogram[SCP_CARD_CRYPTO_LEN]; yh_rc yrc = compute_cryptogram(session->s.s_mac, SCP_KEY_LEN, SCP_CARD_CRYPTOGRAM, session->context, SCP_CARD_CRYPTO_LEN * 8, computed_cryptogram); if (yrc != YHR_SUCCESS) { DBG_ERR("%s", yh_strerror(yrc)); return yrc; } Msg msg = {0}; Msg response_msg = {0}; msg.st.cmd = YHC_AUTHENTICATE_SESSION; msg.st.len = htons(1 + SCP_HOST_CRYPTO_LEN); msg.st.data[0] = session->s.sid; yrc = compute_cryptogram(session->s.s_mac, SCP_KEY_LEN, SCP_HOST_CRYPTOGRAM, session->context, SCP_HOST_CRYPTO_LEN * 8, msg.st.data + 1); if (yrc != YHR_SUCCESS) { DBG_ERR("%s", yh_strerror(yrc)); return yrc; } DBG_INT(msg.st.data + 1, SCP_HOST_CRYPTO_LEN, "Host cryptogram: "); yrc = send_authenticated_msg(&session->s, &msg, &response_msg, false); if (yrc != YHR_SUCCESS) { DBG_ERR("send_authenticated_msg %s", yh_strerror(yrc)); return yrc; } if (response_msg.st.cmd != YHC_AUTHENTICATE_SESSION_R) { yrc = translate_device_error(response_msg.st.data[0]); DBG_ERR("Device error %s (%d)", yh_strerror(yrc), response_msg.st.data[0]); return yrc; } // Verify card cryptogram (after sending response, so we clean up the hsm // session on failure) if (memcmp(card_cryptogram, computed_cryptogram, SCP_CARD_CRYPTO_LEN)) { DBG_ERR("%s", yh_strerror(YHR_CRYPTOGRAM_MISMATCH)); return YHR_CRYPTOGRAM_MISMATCH; } DBG_INFO("Card cryptogram successfully verified"); } else { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } memset(session->s.ctr, 0, SCP_PRF_LEN); increment_ctr(session->s.ctr, SCP_PRF_LEN); DBG_INT(session->s.ctr, SCP_PRF_LEN, "S-CTR: "); DBG_INT(session->s.mac_chaining_value, SCP_PRF_LEN, "MAC-CHAINING: "); return YHR_SUCCESS; } yh_rc yh_authenticate_session(yh_session *session) { if (session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } return YHR_SUCCESS; } static const uint8_t sharedInfo[] = {0x3c, 0x88, 0x10}; // sharedInfo as per SCP11 spec, Section 6.5.2.3 static bool x9_63_sha256_kdf(const uint8_t *shsee, size_t shsee_len, const uint8_t *shsss, size_t shsss_len, const uint8_t *shared, size_t shared_len, uint8_t *dst, size_t dst_len) { hash_ctx hashctx = NULL; if (!hash_create(&hashctx, _SHA256)) { return false; } bool ok = false; uint8_t cnt[4] = {0}; for (uint8_t *end = dst + dst_len; dst < end; dst += dst_len) { increment_ctr(cnt, sizeof(cnt)); if (!hash_init(hashctx)) { goto err_out; } if (!hash_update(hashctx, shsee, shsee_len)) { goto err_out; } if (!hash_update(hashctx, shsss, shsss_len)) { goto err_out; } if (!hash_update(hashctx, cnt, sizeof(cnt))) { goto err_out; } if (shared) { if (!hash_update(hashctx, shared, shared_len)) { goto err_out; } } if (!hash_final(hashctx, dst, &dst_len)) { goto err_out; } } ok = true; err_out: hash_destroy(hashctx); return ok; } yh_rc yh_util_get_device_pubkey(yh_connector *connector, uint8_t *device_pubkey, size_t *device_pubkey_len, yh_algorithm *algorithm) { yh_cmd response_cmd = 0; yh_rc yrc = yh_send_plain_msg(connector, YHC_GET_DEVICE_PUBKEY, NULL, 0, &response_cmd, device_pubkey, device_pubkey_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET DEVICE PUBKEY command: %s", yh_strerror(yrc)); return yrc; } // Return the algorithm of the key if requested if (algorithm) { *algorithm = device_pubkey[0]; } device_pubkey[0] = 0x04; return YHR_SUCCESS; } yh_rc yh_util_derive_ec_p256_key(const uint8_t *password, size_t password_len, uint8_t *privkey, size_t privkey_len, uint8_t *pubkey, size_t pubkey_len) { if (password == NULL || privkey == NULL || pubkey == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } int curve = ecdh_curve_p256(); if (!curve) { DBG_ERR("%s: Platform support for ec-p256 is missing", yh_strerror(YHR_GENERIC_ERROR)); return YHR_GENERIC_ERROR; } uint8_t *pwd = calloc(1, password_len + 1); if (pwd == NULL) { DBG_ERR("%s", yh_strerror(YHR_MEMORY_ERROR)); return YHR_MEMORY_ERROR; } memcpy(pwd, password, password_len); do { DBG_INFO("Deriving key with perturbation %u", pwd[password_len]); // We rely on the fact that a trailing zero doesn't change the derived key yh_rc yrc = derive_key(pwd, password_len + 1, privkey, privkey_len); if (yrc != YHR_SUCCESS) { insecure_memzero(pwd, password_len + 1); free(pwd); DBG_ERR("%s", yh_strerror(yrc)); return yrc; } pwd[password_len]++; } while (!ecdh_calculate_public_key(curve, privkey, privkey_len, pubkey, pubkey_len)); insecure_memzero(pwd, password_len + 1); free(pwd); DBG_INT(pubkey, YH_EC_P256_PUBKEY_LEN, "Derived PubKey: "); return YHR_SUCCESS; } yh_rc yh_util_generate_ec_p256_key(uint8_t *privkey, size_t privkey_len, uint8_t *pubkey, size_t pubkey_len) { if (privkey == NULL || pubkey == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } int curve = ecdh_curve_p256(); if (!curve) { DBG_ERR("%s: Platform support for ec-p256 is missing", yh_strerror(YHR_GENERIC_ERROR)); return YHR_GENERIC_ERROR; } if (!ecdh_generate_keypair(curve, privkey, privkey_len, pubkey, pubkey_len)) { DBG_ERR("Failed to generate ecp256 key %s", yh_strerror(YHR_GENERIC_ERROR)); return YHR_GENERIC_ERROR; } return YHR_SUCCESS; } yh_rc yh_create_session_asym(yh_connector *connector, uint16_t authkey_id, const uint8_t *privkey, size_t privkey_len, const uint8_t *device_pubkey, size_t device_pubkey_len, yh_session **session) { if (connector == NULL || privkey == NULL || device_pubkey == NULL || session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } int curve = ecdh_curve_p256(); if (!curve) { DBG_ERR("%s: Platform support for ec-p256 is missing", yh_strerror(YHR_GENERIC_ERROR)); return YHR_GENERIC_ERROR; } uint8_t esk_oce[YH_EC_P256_PRIVKEY_LEN]; uint8_t epk_oce[YH_EC_P256_PUBKEY_LEN]; size_t epk_oce_len = sizeof(epk_oce); yh_session *new_session = *session; yh_rc rc = YHR_SUCCESS; if (!ecdh_generate_keypair(curve, esk_oce, sizeof(esk_oce), epk_oce, sizeof(epk_oce))) { DBG_ERR("ecdh_generate_keypair %s", yh_strerror(YHR_INVALID_PARAMETERS)); rc = YHR_INVALID_PARAMETERS; goto err; } uint8_t receipt[SCP_KEY_LEN]; size_t receipt_len = sizeof(receipt); rc = yh_begin_create_session(connector, authkey_id, NULL, epk_oce, &epk_oce_len, receipt, &receipt_len, &new_session); if (rc != YHR_SUCCESS) { DBG_ERR("yh_begin_create_session %s", yh_strerror(rc)); goto err; } uint8_t *epk_sd = new_session->context + YH_EC_P256_PUBKEY_LEN; uint8_t shsee[YH_EC_P256_PRIVKEY_LEN]; if (!ecdh_calculate_secret(curve, esk_oce, sizeof(esk_oce), epk_sd, YH_EC_P256_PUBKEY_LEN, shsee, sizeof(shsee))) { DBG_ERR("ecdh_calculate_secret(shsee) %s", yh_strerror(YHR_INVALID_PARAMETERS)); rc = YHR_INVALID_PARAMETERS; goto err; } uint8_t shsss[YH_EC_P256_PRIVKEY_LEN]; if (!ecdh_calculate_secret(curve, privkey, privkey_len, device_pubkey, device_pubkey_len, shsss, sizeof(shsss))) { DBG_ERR("ecdh_calculate_secret(shsss) %s", yh_strerror(YHR_INVALID_PARAMETERS)); rc = YHR_INVALID_PARAMETERS; goto err; } uint8_t shs[4 * SCP_KEY_LEN]; if (!x9_63_sha256_kdf(shsee, sizeof(shsee), shsss, sizeof(shsss), sharedInfo, sizeof(sharedInfo), shs, sizeof(shs))) { DBG_ERR("x9_63_sha256_kdf %s", yh_strerror(YHR_GENERIC_ERROR)); rc = YHR_GENERIC_ERROR; goto err; } uint8_t keys[2 * YH_EC_P256_PUBKEY_LEN], mac[SCP_PRF_LEN]; memcpy(keys, epk_sd, YH_EC_P256_PUBKEY_LEN); memcpy(keys + YH_EC_P256_PUBKEY_LEN, epk_oce, sizeof(epk_oce)); rc = compute_full_mac(keys, sizeof(keys), shs, SCP_KEY_LEN, mac); if (rc != YHR_SUCCESS) { DBG_ERR("compute_full_mac %s", yh_strerror(rc)); goto err; } if (memcmp(mac, receipt, sizeof(receipt))) { DBG_ERR("Verify receipt %s", yh_strerror(YHR_SESSION_AUTHENTICATION_FAILED)); rc = YHR_SESSION_AUTHENTICATION_FAILED; goto err; } DBG_INFO("Card cryptogram successfully verified"); rc = yh_finish_create_session(new_session, shs + SCP_KEY_LEN, SCP_KEY_LEN, shs + 2 * SCP_KEY_LEN, SCP_KEY_LEN, shs + 3 * SCP_KEY_LEN, SCP_KEY_LEN, receipt, receipt_len); if (rc != YHR_SUCCESS) { DBG_ERR("yh_finish_create_session %s", yh_strerror(rc)); goto err; } new_session->authkey_id = 0; memset(new_session->key_enc, 0, SCP_KEY_LEN); memset(new_session->key_mac, 0, SCP_KEY_LEN); *session = new_session; err: insecure_memzero(esk_oce, sizeof(esk_oce)); insecure_memzero(shsss, sizeof(shsss)); insecure_memzero(shsee, sizeof(shsee)); insecure_memzero(shs, sizeof(shs)); if (new_session != *session) { insecure_memzero(new_session, sizeof(yh_session)); free(new_session); new_session = NULL; } return rc; } yh_rc yh_destroy_session(yh_session **session) { if (session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } else if (*session == NULL) { return YHR_SUCCESS; } insecure_memzero(*session, sizeof(yh_session)); free(*session); *session = NULL; return YHR_SUCCESS; } bool yh_connector_has_device(yh_connector *connector) { return connector && connector->has_device; } yh_rc yh_get_connector_version(yh_connector *connector, uint8_t *major, uint8_t *minor, uint8_t *patch) { if (connector == NULL || major == NULL || minor == NULL || patch == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } *major = connector->version_major; *minor = connector->version_minor; *patch = connector->version_patch; return YHR_SUCCESS; } yh_rc yh_get_connector_address(yh_connector *connector, char **const address) { if (connector == NULL || address == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } *address = connector->address; return YHR_SUCCESS; } yh_rc yh_util_get_partnumber(yh_connector *connector, char *part_number, size_t *part_number_len) { if (part_number == NULL || part_number_len == NULL) { // Nothing to read return YHR_SUCCESS; } if (connector == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t response[256] = {0}; size_t response_len = sizeof(response); yh_cmd response_cmd = 0; uint8_t data[1] = {1}; yh_rc yrc = yh_send_plain_msg(connector, YHC_GET_DEVICE_INFO, data, sizeof(data), &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET DEVICE INFO command for page 1: %s", yh_strerror(yrc)); *part_number_len = 0; return yrc; } if (*part_number_len < (response_len + 1)) { DBG_ERR("Response buffer too small"); *part_number_len = 0; return YHR_BUFFER_TOO_SMALL; } memcpy(part_number, response, response_len); part_number[response_len] = 0; *part_number_len = response_len + 1; return YHR_SUCCESS; } yh_rc yh_util_get_device_info_ex(yh_connector *connector, yh_device_info *device_info) { device_info->n_algorithms = YH_MAX_ALGORITHM_COUNT; return yh_util_get_device_info(connector, &device_info->major, &device_info->minor, &device_info->patch, &device_info->serial, &device_info->log_total, &device_info->log_used, device_info->algorithms, &device_info->n_algorithms); } yh_rc yh_util_get_device_info(yh_connector *connector, uint8_t *major, uint8_t *minor, uint8_t *patch, uint32_t *serial, uint8_t *log_total, uint8_t *log_used, yh_algorithm *algorithms, size_t *n_algorithms) { if (connector == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } yh_rc yrc; #pragma pack(push, 1) union { struct { uint8_t major; uint8_t minor; uint8_t patch; uint32_t serial; uint8_t log_total; uint8_t log_used; uint8_t algorithms[YH_MAX_ALGORITHM_COUNT]; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; yrc = yh_send_plain_msg(connector, YHC_GET_DEVICE_INFO, NULL, 0, &response_cmd, response.buf, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET DEVICE INFO command: %s", yh_strerror(yrc)); return yrc; } if (major != NULL) { *major = response.major; } if (minor != NULL) { *minor = response.minor; } if (patch != NULL) { *patch = response.patch; } if (serial != NULL) { *serial = ntohl(response.serial); } if (log_total != NULL) { *log_total = response.log_total; } if (log_used != NULL) { *log_used = response.log_used; } if (algorithms != NULL && n_algorithms) { size_t items = response_len - sizeof(response.major) - sizeof(response.minor) - sizeof(response.patch) - sizeof(response.serial) - sizeof(response.log_total) - sizeof(response.log_used); if (*n_algorithms < items) { DBG_ERR("Algorithms buffer too small"); return YHR_BUFFER_TOO_SMALL; } for (size_t i = 0; i < items; i++) { algorithms[i] = response.algorithms[i]; } *n_algorithms = items; } return YHR_SUCCESS; } #define LIST_ID 1 #define LIST_TYPE 2 #define LIST_DOMAINS 3 #define LIST_CAPABILITIES 4 #define LIST_ALGORITHM 5 #define LIST_LABEL 6 yh_rc yh_util_list_objects(yh_session *session, uint16_t id, yh_object_type type, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const char *label, yh_object_descriptor *objects, size_t *n_objects) { if (session == NULL || objects == NULL || n_objects == NULL || capabilities == NULL || (label != NULL && strlen(label) > YH_OBJ_LABEL_LEN)) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t data[YH_MSG_BUF_SIZE] = {0}; uint8_t *dataptr = data; if (id) { *dataptr++ = LIST_ID; *dataptr++ = id >> 8 & 0xff; *dataptr++ = id & 0xff; } if (type) { *dataptr++ = LIST_TYPE; *dataptr++ = type; } if (domains) { *dataptr++ = LIST_DOMAINS; *dataptr++ = domains >> 8 & 0xff; *dataptr++ = domains & 0xff; } if (algorithm) { *dataptr++ = LIST_ALGORITHM; *dataptr++ = algorithm; } if (label && strlen(label)) { *dataptr++ = LIST_LABEL; memcpy(dataptr, label, strlen(label)); memset(dataptr + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); dataptr += YH_OBJ_LABEL_LEN; } bool send_capabilities = false; for (uint16_t i = 0; i < YH_CAPABILITIES_LEN; i++) { if (capabilities->capabilities[i]) { send_capabilities = true; break; } } if (send_capabilities == true) { *dataptr++ = LIST_CAPABILITIES; for (uint16_t i = 0; i < YH_CAPABILITIES_LEN; i++) { *dataptr++ = capabilities->capabilities[i]; } } uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_cmd response_cmd = 0; yh_rc yrc = yh_send_secure_msg(session, YHC_LIST_OBJECTS, data, dataptr - data, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send LIST OBJECTS command: %s", yh_strerror(yrc)); return yrc; } if ((response_len / 4) > *n_objects) { DBG_ERR("Objects buffer too small"); return YHR_BUFFER_TOO_SMALL; } *n_objects = response_len / 4; for (size_t i = 0; i < *n_objects; i++) { // NOTE: clear the fields that we didn't set memset(&objects[i], 0, sizeof(yh_object_descriptor)); objects[i].id = ntohs(*((uint16_t *) (response + i * 4))); objects[i].type = response[i * 4 + 2]; objects[i].sequence = response[i * 4 + 3]; } DBG_INFO("Found %zu objects", *n_objects); return YHR_SUCCESS; } yh_rc yh_util_get_object_info(yh_session *session, uint16_t id, yh_object_type type, yh_object_descriptor *object) { if (session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t data[3] = {0}; uint8_t *dataptr = data; #pragma pack(push, 1) union { struct { uint8_t capabilities[YH_CAPABILITIES_LEN]; uint16_t id; uint16_t len; uint16_t domains; uint8_t type; uint8_t algorithm; uint8_t sequence; uint8_t origin; uint8_t label[YH_OBJ_LABEL_LEN]; uint8_t delegated_capabilities[YH_CAPABILITIES_LEN]; }; uint8_t buf[1]; } response = {0}; size_t response_len = sizeof(response); #pragma pack(pop) yh_cmd response_cmd = 0; *dataptr++ = id >> 8 & 0xff; *dataptr++ = id & 0xff; *dataptr++ = (uint16_t) type; yh_rc yrc = yh_send_secure_msg(session, YHC_GET_OBJECT_INFO, data, sizeof(data), &response_cmd, response.buf, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET OBJECT INFO command: %s", yh_strerror(yrc)); return yrc; } if (response_len == sizeof(response)) { if (object) { memcpy(object->capabilities.capabilities, response.capabilities, YH_CAPABILITIES_LEN); object->id = htons(response.id); object->len = htons(response.len); object->domains = htons(response.domains); object->type = response.type; object->algorithm = response.algorithm; object->sequence = response.sequence; object->origin = response.origin; memcpy(object->label, response.label, YH_OBJ_LABEL_LEN); object->label[YH_OBJ_LABEL_LEN] = 0; memcpy(object->delegated_capabilities.capabilities, response.delegated_capabilities, YH_CAPABILITIES_LEN); } } else { DBG_ERR("Wrong response length, expecting %lu, received %lu", (unsigned long) sizeof(yh_object_descriptor), (unsigned long) response_len); return YHR_WRONG_LENGTH; } return YHR_SUCCESS; } yh_rc yh_util_get_public_key_ex(yh_session *session, yh_object_type type, uint16_t id, uint8_t *data, size_t *data_len, yh_algorithm *algorithm) { if (session == NULL || data == NULL || data_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } type &= ~0x80; // Convert pseudo-public key type to real type uint8_t cmd[] = {id >> 8, id & 0xff, type}; yh_cmd response_cmd = 0; uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_send_secure_msg(session, YHC_GET_PUBLIC_KEY, cmd, type == YH_ASYMMETRIC_KEY ? sizeof(cmd) - 1 : sizeof(cmd), &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET PUBLIC KEY command: %s", yh_strerror(yrc)); return yrc; } if (response_len < 1) { // abg: why is the first byte of the response discarded? return YHR_DEVICE_WRONG_LENGTH; } if (response_len > *data_len) { return YHR_BUFFER_TOO_SMALL; } if (algorithm) { *algorithm = *response; } *data_len = response_len - 1; memcpy(data, response + 1, *data_len); return YHR_SUCCESS; } yh_rc yh_util_get_public_key(yh_session *session, uint16_t id, uint8_t *data, size_t *data_len, yh_algorithm *algorithm) { return yh_util_get_public_key_ex(session, YH_ASYMMETRIC_KEY, id, data, data_len, algorithm); } yh_rc yh_util_close_session(yh_session *session) { if (session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t response[5] = {0}; size_t response_len = sizeof(response); yh_cmd response_cmd = 0; yh_rc yrc = yh_send_secure_msg(session, YHC_CLOSE_SESSION, NULL, 0, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send CLOSE SESSION command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_sign_pkcs1v1_5(yh_session *session, uint16_t key_id, bool hashed, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { if (session == NULL || in == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len > YH_MSG_BUF_SIZE - 2) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } if (hashed) switch (in_len) { case 20: case 32: case 48: case 64: break; default: DBG_ERR("Data length must be 20, 32, 48 or 64"); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[YH_MSG_BUF_SIZE - 2]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) size_t data_len; yh_cmd response_cmd = 0; data.key_id = htons(key_id); memcpy(data.bytes, in, in_len); data_len = in_len; yh_rc yrc = yh_send_secure_msg(session, YHC_SIGN_PKCS1, data.buf, data_len + 2, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send SIGN PKCS1 command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_sign_pss(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len, size_t salt_len, yh_algorithm mgf1Algo) { if (session == NULL || in == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } switch (in_len) { case 20: case 32: case 48: case 64: break; default: DBG_ERR("Data length must be 20, 32, 48 or 64"); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t mgf1Algo; uint16_t salt_len; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) size_t data_len = in_len; yh_cmd response_cmd = 0; data.key_id = htons(key_id); data.mgf1Algo = mgf1Algo; // NOTE(adma): 'in' is already a hash of the data, which type is inferred from // the length data.salt_len = htons(salt_len); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_SIGN_PSS, data.buf, data_len + 5, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send SIGN PSS command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_sign_ecdsa(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { if (session == NULL || in == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } switch (in_len) { case 20: case 28: // p224.. case 32: case 48: case 64: case 66: // p521 needs 66 bytes input break; default: DBG_ERR("Data length must be 20, 28, 32, 48, 64 or 66"); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) size_t data_len = in_len; yh_cmd response_cmd = 0; data.key_id = htons(key_id); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_SIGN_ECDSA, data.buf, data_len + 2, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send SIGN ECDSA command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_sign_eddsa(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { if (session == NULL || in == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len > YH_MSG_BUF_SIZE - 2) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) size_t data_len = in_len; yh_cmd response_cmd = 0; data.key_id = htons(key_id); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_SIGN_EDDSA, data.buf, data_len + 2, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send SIGN EDDSA command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_sign_hmac(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { if (session == NULL || in == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len > YH_MSG_BUF_SIZE - 2) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = 2; yh_cmd response_cmd = 0; data[0] = htons(key_id) & 0xff; data[1] = htons(key_id) >> 8; memcpy(data + 2, in, in_len); data_len += in_len; yh_rc yrc = yh_send_secure_msg(session, YHC_SIGN_HMAC, data, data_len, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send SIGN HMAC command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_get_pseudo_random(yh_session *session, size_t len, uint8_t *out, size_t *out_len) { if (session == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } union { uint16_t len; uint8_t buf[2]; } data = {0}; data.len = htons(len); yh_cmd response_cmd = 0; yh_rc yrc = yh_send_secure_msg(session, YHC_GET_PSEUDO_RANDOM, data.buf, sizeof(data), &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET PSEUDO RANDOM command: %s", yh_strerror(yrc)); return yrc; } return yrc; } static yh_rc import_key(yh_cmd cmd, yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *key, size_t key_len) { if (cmd != YHC_PUT_ASYMMETRIC_KEY && cmd != YHC_PUT_SYMMETRIC_KEY) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algo; uint8_t bytes[512]; }; uint8_t buf[1]; } k = {0}; union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; k.key_id = htons(*key_id); memcpy(k.label, label, strlen(label)); memset(k.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); k.domains = htons(domains); k.algo = algorithm; memcpy(k.capabilities, capabilities, YH_CAPABILITIES_LEN); if (key_len > sizeof(k.bytes)) { return YHR_INVALID_PARAMETERS; } memcpy(k.bytes, key, key_len); size_t len = sizeof(k.key_id) + sizeof(k.domains) + sizeof(k.capabilities) + sizeof(k.algo) + sizeof(k.label) + key_len; yh_rc yrc = yh_send_secure_msg(session, cmd, k.buf, len, &response_cmd, response.buf, &response_len); insecure_memzero(k.buf, len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send PUT %s KEY command: %s", cmd == YHC_PUT_ASYMMETRIC_KEY ? "ASYMMETRIC" : "SYMMETRIC", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Stored %s key 0x%04x", cmd == YHC_PUT_ASYMMETRIC_KEY ? "asymmetric" : "symmetric", *key_id); return yrc; } yh_rc yh_util_import_aes_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *key) { if (session == NULL || key_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN || key == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } size_t len; if (algorithm == YH_ALGO_AES128) { len = 16; } else if (algorithm == YH_ALGO_AES192) { len = 24; } else if (algorithm == YH_ALGO_AES256) { len = 32; } else { return YHR_INVALID_PARAMETERS; } return import_key(YHC_PUT_SYMMETRIC_KEY, session, key_id, label, domains, capabilities, algorithm, key, len); } yh_rc yh_util_import_rsa_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *p, const uint8_t *q) { if (session == NULL || key_id == NULL || label == NULL || capabilities == NULL || strlen(label) > YH_OBJ_LABEL_LEN || p == NULL || q == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t keybuf[256 * 2] = {0}; size_t component_len; if (algorithm == YH_ALGO_RSA_2048) { component_len = 128; } else if (algorithm == YH_ALGO_RSA_3072) { component_len = 192; } else if (algorithm == YH_ALGO_RSA_4096) { component_len = 256; } else { return YHR_INVALID_PARAMETERS; } memcpy(keybuf, p, component_len); memcpy(keybuf + component_len, q, component_len); yh_rc yrc = import_key(YHC_PUT_ASYMMETRIC_KEY, session, key_id, label, domains, capabilities, algorithm, keybuf, component_len * 2); insecure_memzero(keybuf, sizeof(keybuf)); return yrc; } yh_rc yh_util_import_ec_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *s) { if (session == NULL || key_id == NULL || label == NULL || capabilities == NULL || strlen(label) > YH_OBJ_LABEL_LEN || s == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } size_t component_len; switch (algorithm) { case YH_ALGO_EC_P224: component_len = 28; break; case YH_ALGO_EC_P256: case YH_ALGO_EC_K256: case YH_ALGO_EC_BP256: component_len = 32; break; case YH_ALGO_EC_P384: case YH_ALGO_EC_BP384: component_len = 48; break; case YH_ALGO_EC_BP512: component_len = 64; break; case YH_ALGO_EC_P521: component_len = 66; break; default: return YHR_INVALID_PARAMETERS; } return import_key(YHC_PUT_ASYMMETRIC_KEY, session, key_id, label, domains, capabilities, algorithm, s, component_len); } yh_rc yh_util_import_ed_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *k) { if (session == NULL || key_id == NULL || label == NULL || capabilities == NULL || strlen(label) > YH_OBJ_LABEL_LEN || k == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } size_t component_len; switch (algorithm) { case YH_ALGO_EC_ED25519: component_len = 32; break; default: return YHR_INVALID_PARAMETERS; } return import_key(YHC_PUT_ASYMMETRIC_KEY, session, key_id, label, domains, capabilities, algorithm, k, component_len); } yh_rc yh_util_import_hmac_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *key, size_t key_len) { if (session == NULL || key_id == NULL || label == NULL || capabilities == NULL || strlen(label) > YH_OBJ_LABEL_LEN || key == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint8_t key[128]; }; uint8_t buf[1]; } k = {0}; union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; size_t max_len = 64; size_t len = sizeof(k) - sizeof(k.key); k.key_id = htons(*key_id); memcpy(k.label, label, strlen(label)); memset(k.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); k.domains = htons(domains); k.algorithm = algorithm; memcpy(k.capabilities, capabilities, YH_CAPABILITIES_LEN); if (algorithm == YH_ALGO_HMAC_SHA384 || algorithm == YH_ALGO_HMAC_SHA512) { max_len = 128; } if (key_len > max_len) { DBG_ERR("Too long key supplied, max %lu bytes allowed", (unsigned long) max_len); return YHR_WRONG_LENGTH; } memcpy(k.key, key, key_len); len += key_len; yh_rc yrc = yh_send_secure_msg(session, YHC_PUT_HMAC_KEY, k.buf, len, &response_cmd, response.buf, &response_len); insecure_memzero(k.buf, len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send PUT HMAC KEY command: %s", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Stored HMAC key 0x%04x", *key_id); return yrc; } static yh_rc generate_key(yh_cmd cmd, yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm) { if (session == NULL || key_id == NULL || label == NULL || capabilities == NULL || strlen(label) > YH_OBJ_LABEL_LEN) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (cmd != YHC_GENERATE_ASYMMETRIC_KEY && cmd != YHC_GENERATE_SYMMETRIC_KEY) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algo; }; uint8_t buf[1]; } data = {0}; size_t data_len = sizeof(data); union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; data.key_id = htons(*key_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); data.algo = algorithm; memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); yh_rc yrc = yh_send_secure_msg(session, cmd, data.buf, data_len, &response_cmd, response.buf, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GENERATE %s KEY command: %s", cmd == YHC_GENERATE_ASYMMETRIC_KEY ? "ASYMMETRIC" : "SYMMETRIC", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Generated %s key 0x%04x", cmd == YHC_GENERATE_ASYMMETRIC_KEY ? "asymmetric" : "symmetric", *key_id); return YHR_SUCCESS; } yh_rc yh_util_generate_aes_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm) { if (!yh_is_aes(algorithm)) { DBG_ERR("Invalid algorithm %d", algorithm); return YHR_INVALID_PARAMETERS; } return generate_key(YHC_GENERATE_SYMMETRIC_KEY, session, key_id, label, domains, capabilities, algorithm); } yh_rc yh_util_generate_rsa_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm) { if (!yh_is_rsa(algorithm)) { DBG_ERR("Invalid algorithm %d", algorithm); return YHR_INVALID_PARAMETERS; } return generate_key(YHC_GENERATE_ASYMMETRIC_KEY, session, key_id, label, domains, capabilities, algorithm); } yh_rc yh_util_generate_ec_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm) { if (!yh_is_ec(algorithm)) { DBG_ERR("Invalid algorithm %d", algorithm); return YHR_INVALID_PARAMETERS; } return generate_key(YHC_GENERATE_ASYMMETRIC_KEY, session, key_id, label, domains, capabilities, algorithm); } yh_rc yh_util_generate_ed_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm) { if (!yh_is_ed(algorithm)) { DBG_ERR("Invalid algorithm %d", algorithm); return YHR_INVALID_PARAMETERS; } return generate_key(YHC_GENERATE_ASYMMETRIC_KEY, session, key_id, label, domains, capabilities, algorithm); } yh_rc yh_util_verify_hmac(yh_session *session, uint16_t key_id, const uint8_t *signature, size_t signature_len, const uint8_t *data, size_t data_len, bool *verified) { if (session == NULL || signature == NULL || data == NULL || verified == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (data_len + signature_len < data_len) { // unsigned integer overflow detection return YHR_INVALID_PARAMETERS; } if (data_len + signature_len > YH_MSG_BUF_SIZE - 2) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } uint8_t cmd_data[YH_MSG_BUF_SIZE] = {0}; size_t cmd_data_len; uint8_t response[3] = {0}; size_t response_len = sizeof(response); yh_cmd response_cmd = 0; key_id = htons(key_id); memcpy(cmd_data, (uint8_t *) &key_id, 2); cmd_data_len = 2; memcpy(cmd_data + cmd_data_len, signature, signature_len); cmd_data_len += signature_len; memcpy(cmd_data + cmd_data_len, data, data_len); cmd_data_len += data_len; yh_rc yrc = yh_send_secure_msg(session, YHC_VERIFY_HMAC, cmd_data, cmd_data_len, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send HMAC VERIFY command: %s", yh_strerror(yrc)); return yrc; } *verified = response[0]; return YHR_SUCCESS; } yh_rc yh_util_generate_hmac_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm) { if (session == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN || key_id == NULL || capabilities == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; }; uint8_t buf[1]; } data = {0}; union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; data.key_id = htons(*key_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); data.algorithm = algorithm; yh_rc yrc = yh_send_secure_msg(session, YHC_GENERATE_HMAC_KEY, data.buf, sizeof(data), &response_cmd, response.buf, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GENERATE HMAC command: %s", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Generated HMAC key 0x%04x", *key_id); return YHR_SUCCESS; } yh_rc yh_util_decrypt_pkcs1v1_5(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { if (session == NULL || in == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len > YH_MSG_BUF_SIZE - 2) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) yh_cmd response_cmd = 0; data.key_id = htons(key_id); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_DECRYPT_PKCS1, data.buf, in_len + 2, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send DECRYPT PKCS1 command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_decrypt_oaep(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len, const uint8_t *label, size_t label_len, yh_algorithm mgf1Algo) { if (session == NULL || in == NULL || out == NULL || out_len == NULL || label == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t mgf1Algo; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) yh_cmd response_cmd = 0; size_t len = 0; data.key_id = htons(key_id); len += sizeof(data.key_id); data.mgf1Algo = mgf1Algo; len += sizeof(data.mgf1Algo); // in_len has to match the rsa key size if (in_len != 256 && in_len != 384 && in_len != 512) { DBG_ERR("Wrong input length"); return YHR_WRONG_LENGTH; } // label_len is hashed and specified the mgf hash if (label_len != 20 && label_len != 32 && label_len != 48 && label_len != 64) { DBG_ERR("Wrong label length"); return YHR_WRONG_LENGTH; } memcpy(data.bytes, in, in_len); len += in_len; memcpy(data.bytes + in_len, label, label_len); len += label_len; yh_rc yrc = yh_send_secure_msg(session, YHC_DECRYPT_OAEP, data.buf, len, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send DECRYPT OAEP command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_derive_ecdh(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { if (session == NULL || in == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len > YH_MSG_BUF_SIZE - 2) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) yh_cmd response_cmd = 0; data.key_id = htons(key_id); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_DERIVE_ECDH, data.buf, in_len + 2, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send DERIVE ECDH command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_delete_object(yh_session *session, uint16_t id, yh_object_type type) { if (session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t id; uint8_t type; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) yh_cmd response_cmd = 0; uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); data.type = type; data.id = htons(id); yh_rc yrc = yh_send_secure_msg(session, YHC_DELETE_OBJECT, data.buf, sizeof(data), &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send DELETE command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_export_wrapped(yh_session *session, uint16_t wrapping_key_id, yh_object_type target_type, uint16_t target_id, uint8_t *out, size_t *out_len) { return yh_util_export_wrapped_ex(session, wrapping_key_id, target_type, target_id, 0, out, out_len); } yh_rc yh_util_export_wrapped_ex(yh_session *session, uint16_t wrapping_key_id, yh_object_type target_type, uint16_t target_id, uint8_t format, uint8_t *out, size_t *out_len) { if (session == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t type; uint16_t tgt_id; uint8_t format; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) yh_cmd response_cmd = 0; data.key_id = htons(wrapping_key_id); data.type = (uint8_t) target_type; data.tgt_id = htons(target_id); data.format = format; yh_rc yrc = yh_send_secure_msg(session, YHC_EXPORT_WRAPPED, data.buf, format == 0 ? sizeof(data) - 1 : sizeof(data), &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send EXPORT WRAPPED command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_import_wrapped(yh_session *session, uint16_t wrapping_key_id, const uint8_t *in, size_t in_len, yh_object_type *target_type, uint16_t *target_id) { if (session == NULL || in == NULL || target_type == NULL || target_id == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len > YH_MSG_BUF_SIZE - 2) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[YH_MSG_BUF_SIZE - 2]; }; uint8_t buf[1]; } data = {0}; union { struct { uint8_t key_type; uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; size_t data_len = 2 + in_len; data.key_id = htons(wrapping_key_id); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_IMPORT_WRAPPED, data.buf, data_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send IMPORT WRAPPED command: %s", yh_strerror(yrc)); return yrc; } *target_type = response.key_type; *target_id = ntohs(response.key_id); return YHR_SUCCESS; } yh_rc yh_util_import_rsa_wrapped(yh_session *session, uint16_t wrapping_key_id, yh_algorithm hash, yh_algorithm mgf1, const uint8_t *label, size_t label_len, const uint8_t *in, size_t in_len, yh_object_type *target_type, uint16_t *target_id) { if (session == NULL || in == NULL || target_type == NULL || target_id == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len + label_len > YH_MSG_BUF_SIZE) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t wrap_key_id; uint8_t hash; uint8_t mgf1; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = { { htons(wrapping_key_id), hash, mgf1, { 0 } } }; union { struct { uint8_t key_type; uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; size_t data_len = 4; memcpy(data.bytes, in, in_len); data_len += in_len; memcpy(data.bytes + in_len, label, label_len); data_len += label_len; yh_rc yrc = yh_send_secure_msg(session, YHC_IMPORT_RSA_WRAPPED, data.buf, data_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send IMPORT RSA WRAPPED command: %s", yh_strerror(yrc)); return yrc; } *target_type = response.key_type; *target_id = ntohs(response.key_id); return YHR_SUCCESS; } yh_rc yh_util_put_rsa_wrapped_key(yh_session *session, uint16_t wrapping_key_id, yh_object_type type, uint16_t *target_id, yh_algorithm algo, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm hash, yh_algorithm mgf1, const uint8_t *oaep_label, size_t oaep_label_len, const uint8_t *in, size_t in_len) { if (session == NULL || in == NULL || target_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len + oaep_label_len > YH_MSG_BUF_SIZE) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t wrap_key_id; uint8_t target_type; uint16_t target_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint8_t hash; uint8_t mgf1; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = { { htons(wrapping_key_id), type, htons(*target_id), { 0 }, // label htons(domains), { 0 }, // capabilities algo, hash, mgf1, { 0 } } }; union { struct { uint8_t key_type; uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) // 2 bytes wrap key ID + // 1 byte target type + // 2 bytes target ID + // 2 bytes domains + // 1 byte algorithm + // 1 byte hash algorithm + // 1 byte MGF1 algorithm // = 10 bytes size_t data_len = 10 + YH_OBJ_LABEL_LEN + YH_CAPABILITIES_LEN; size_t response_len = sizeof(response); yh_cmd response_cmd = 0; memcpy(data.label, label, strlen(label)); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); memcpy(data.bytes, in, in_len); data_len += in_len; memcpy(data.bytes + in_len, oaep_label, oaep_label_len); data_len += oaep_label_len; yh_rc yrc = yh_send_secure_msg(session, YHC_PUT_RSA_WRAPPED_KEY, data.buf, data_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send IMPORT WRAPPED command: %s", yh_strerror(yrc)); return yrc; } *target_id = ntohs(response.key_id); if (response.key_type != type) { DBG_ERR("Imported key type does not match stated key. Removing key."); yh_util_delete_object(session, *target_id, response.key_type); *target_id = 0; return YHR_INVALID_PARAMETERS; } return YHR_SUCCESS; } static yh_rc do_rsa_wrap(yh_cmd cmd, yh_session *session, uint16_t wrap_key_id, yh_object_type target_type, uint16_t target_id, yh_algorithm aes, yh_algorithm hash, yh_algorithm mgf1, const uint8_t *oaep_label, size_t oaep_label_len, uint8_t *out, size_t *out_len) { if (session == NULL || out == NULL || out_len == NULL || oaep_label == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (oaep_label_len != 20 && oaep_label_len != 32 && oaep_label_len != 48 && oaep_label_len != 64) { DBG_ERR("Wrong digest length. %s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t wrap_key_id; uint8_t target_type; uint16_t target_id; uint8_t aes; uint8_t hash; uint8_t mgf1; uint8_t label[64]; }; uint8_t buf[1]; } data = { { htons(wrap_key_id), target_type, htons(target_id), aes, hash, mgf1, { 0 } } }; #pragma pack(pop) yh_cmd response_cmd = 0; size_t len = sizeof(data); memcpy(data.label, oaep_label, oaep_label_len); len -= sizeof(data.label); len += oaep_label_len; yh_rc yrc = yh_send_secure_msg(session, cmd, data.buf, len, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send 0x%02x command: %s", cmd, yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_get_rsa_wrapped_key(yh_session *session, uint16_t wrap_key_id, yh_object_type target_type, uint16_t target_id, yh_algorithm aes, yh_algorithm hash, yh_algorithm mgf1, const uint8_t *oaep_label, size_t oaep_label_len, uint8_t *out, size_t *out_len) { if (target_type != YH_ASYMMETRIC_KEY && target_type != YH_SYMMETRIC_KEY) { DBG_ERR("Only symmetric or asymmetric keys are supported"); return YHR_INVALID_PARAMETERS; } return do_rsa_wrap(YHC_GET_RSA_WRAPPED_KEY, session, wrap_key_id, target_type, target_id, aes, hash, mgf1, oaep_label, oaep_label_len, out, out_len); } yh_rc yh_util_export_rsa_wrapped(yh_session *session, uint16_t wrap_key_id, yh_object_type target_type, uint16_t target_id, yh_algorithm aes, yh_algorithm hash, yh_algorithm mgf1, const uint8_t *oaep_label, size_t oaep_label_len, uint8_t *out, size_t *out_len) { return do_rsa_wrap(YHC_EXPORT_RSA_WRAPPED, session, wrap_key_id, target_type, target_id, aes, hash, mgf1, oaep_label, oaep_label_len, out, out_len); } yh_rc yh_util_import_wrap_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const yh_capabilities *delegated_capabilities, const uint8_t *in, size_t in_len) { if (session == NULL || key_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN || capabilities == NULL || delegated_capabilities == NULL || in == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint8_t delegated_capabilities[YH_CAPABILITIES_LEN]; uint8_t key[512]; }; uint8_t buf[1]; } data = {0}; union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; size_t key_len = 0; switch (algorithm) { case YH_ALGO_AES128_CCM_WRAP: key_len = 16; break; case YH_ALGO_AES192_CCM_WRAP: key_len = 24; break; case YH_ALGO_AES256_CCM_WRAP: key_len = 32; break; case YH_ALGO_RSA_2048: key_len = 256; break; case YH_ALGO_RSA_3072: key_len = 384; break; case YH_ALGO_RSA_4096: key_len = 512; break; default: DBG_ERR("Bad algorithm specified: %x", algorithm); return YHR_INVALID_PARAMETERS; } size_t data_len = sizeof(data) - sizeof(data.key) + key_len; if (in_len != key_len) { DBG_ERR("Key length not matching, should be %zu", key_len); return YHR_INVALID_PARAMETERS; } data.key_id = htons(*key_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); data.algorithm = algorithm; memcpy(data.delegated_capabilities, delegated_capabilities, YH_CAPABILITIES_LEN); memcpy(data.key, in, key_len); yh_rc yrc = yh_send_secure_msg(session, YHC_PUT_WRAP_KEY, data.buf, data_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send PUT WRAP KEY command: %s", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Imported Wrap key 0x%04x", *key_id); return YHR_SUCCESS; } yh_rc yh_util_import_public_wrap_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const yh_capabilities *delegated_capabilities, const uint8_t *in, size_t in_len) { if (session == NULL || key_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN || capabilities == NULL || delegated_capabilities == NULL || in == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint8_t delegated_capabilities[YH_CAPABILITIES_LEN]; uint8_t key[512]; }; uint8_t buf[1]; } data = {0}; union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; size_t key_len; switch (algorithm) { case YH_ALGO_RSA_2048: key_len = 256; break; case YH_ALGO_RSA_3072: key_len = 384; break; case YH_ALGO_RSA_4096: key_len = 512; break; default: DBG_ERR("Bad algorithm specified: %x", algorithm); return YHR_INVALID_PARAMETERS; } size_t data_len = sizeof(data) - sizeof(data.key) + key_len; if (in_len != key_len) { DBG_ERR("Key length not matching, should be %zu", key_len); return YHR_INVALID_PARAMETERS; } data.key_id = htons(*key_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); data.algorithm = algorithm; memcpy(data.delegated_capabilities, delegated_capabilities, YH_CAPABILITIES_LEN); memcpy(data.key, in, key_len); yh_rc yrc = yh_send_secure_msg(session, YHC_PUT_PUBLIC_WRAPKEY, data.buf, data_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send PUT PUBLIC WRAP KEY command: %s", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Imported public wrap key 0x%04x", *key_id); return YHR_SUCCESS; } yh_rc yh_util_generate_wrap_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const yh_capabilities *delegated_capabilities) { if (session == NULL || key_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN || capabilities == NULL || delegated_capabilities == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint8_t delegated_capabilities[YH_CAPABILITIES_LEN]; }; uint8_t buf[1]; } data = {0}; size_t data_len = sizeof(data); union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; data.key_id = htons(*key_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); data.algorithm = algorithm; memcpy(data.delegated_capabilities, delegated_capabilities, YH_CAPABILITIES_LEN); yh_rc yrc = yh_send_secure_msg(session, YHC_GENERATE_WRAP_KEY, data.buf, data_len, &response_cmd, response.buf, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to generate wrap key: %s", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Generated Wrap key 0x%04x\n", *key_id); return YHR_SUCCESS; } yh_rc yh_util_get_log_entries(yh_session *session, uint16_t *unlogged_boot, uint16_t *unlogged_auth, yh_log_entry *out, size_t *n_items) { if (session == NULL || out == NULL || n_items == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } union { struct { uint16_t log_overflow_boot; uint16_t log_overflow_auth; uint8_t items; uint8_t data[1]; }; uint8_t buf[YH_MSG_BUF_SIZE]; } response = {0}; size_t response_len = sizeof(response); yh_cmd response_cmd = 0; yh_rc yrc = yh_send_secure_msg(session, YHC_GET_LOG_ENTRIES, NULL, 0, &response_cmd, response.buf, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET LOGS command: %s", yh_strerror(yrc)); return yrc; } if (response_len < sizeof(response.log_overflow_boot) + sizeof(response.log_overflow_auth) + sizeof(response.items)) { return YHR_WRONG_LENGTH; } size_t logs_size = response_len - sizeof(response.log_overflow_boot) - sizeof(response.log_overflow_auth) - sizeof(response.items); if (logs_size % sizeof(yh_log_entry) != 0 || logs_size / sizeof(yh_log_entry) != response.items) { return YHR_WRONG_LENGTH; } if (unlogged_boot) { *unlogged_boot = ntohs(response.log_overflow_boot); } if (unlogged_auth) { *unlogged_auth = ntohs(response.log_overflow_auth); } if (response.items > YH_MAX_LOG_ENTRIES) { DBG_ERR( "Response contain more items than the maximum number of log entries"); return YHR_DEVICE_INVALID_DATA; } if (response.items > *n_items) { DBG_ERR("Log buffer too small, needed at lest %d, got %zu", response.items, *n_items); return YHR_BUFFER_TOO_SMALL; } *n_items = response.items; yh_log_entry *ptr = (yh_log_entry *) response.data; for (size_t i = 0; i < *n_items; i++) { out[i].number = ntohs(ptr[i].number); out[i].command = ptr[i].command; out[i].length = ntohs(ptr[i].length); out[i].session_key = ntohs(ptr[i].session_key); out[i].target_key = ntohs(ptr[i].target_key); out[i].second_key = ntohs(ptr[i].second_key); out[i].result = ptr[i].result; out[i].systick = ntohl(ptr[i].systick); memcpy(out[i].digest, ptr[i].digest, YH_LOG_DIGEST_SIZE); } return YHR_SUCCESS; } yh_rc yh_util_set_log_index(yh_session *session, uint16_t index) { if (session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t data[2] = {0}; yh_cmd response_cmd = 0; uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); uint16_t index_h = htons(index); memcpy(data, &index_h, sizeof(index_h)); yh_rc yrc = yh_send_secure_msg(session, YHC_SET_LOG_INDEX, data, sizeof(data), &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send SET LOG INDEX command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_get_opaque(yh_session *session, uint16_t object_id, uint8_t *out, size_t *out_len) { if (session == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t data[2] = {0}; yh_cmd response_cmd = 0; uint16_t object_id_h = htons(object_id); memcpy(data, &object_id_h, sizeof(object_id_h)); yh_rc yrc = yh_send_secure_msg(session, YHC_GET_OPAQUE, data, sizeof(data), &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET OPAQUE command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_import_opaque(yh_session *session, uint16_t *object_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *in, size_t in_len) { if (session == NULL || object_id == NULL || label == NULL || capabilities == NULL || strlen(label) > YH_OBJ_LABEL_LEN || in == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t object_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint8_t bytes[YH_MSG_BUF_SIZE - sizeof(object_id) - sizeof(domains) - YH_CAPABILITIES_LEN - 2]; }; uint8_t buf[1]; } data = {0}; size_t data_len; union { struct { uint16_t object_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; data.object_id = htons(*object_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); data.algorithm = algorithm; if (in_len > sizeof(data.bytes)) { DBG_ERR("Data length must be in [0, %lu]\n", (unsigned long) sizeof(data.bytes)); return YHR_INVALID_PARAMETERS; } data_len = in_len + sizeof(data) - sizeof(data.bytes); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_PUT_OPAQUE, data.buf, data_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send PUT OPAQUE command: %s", yh_strerror(yrc)); return yrc; } *object_id = ntohs(response.object_id); DBG_INFO("Stored Opaque Object 0x%04x", *object_id); return YHR_SUCCESS; } yh_rc yh_util_get_opaque_ex(yh_session *session, uint16_t object_id, uint8_t *out, size_t *out_len, size_t *stored_len, bool try_decompress) { yh_rc yrc = yh_util_get_opaque(session, object_id, out, out_len); if (yrc != YHR_SUCCESS) { return yrc; } if (stored_len != NULL) { *stored_len = *out_len; } if (try_decompress) { #ifdef ENABLE_CERT_COMPRESS uint8_t uncompressed_data[16384] = {0}; size_t uncompressed_data_len = sizeof(uncompressed_data); if (decompress_data(out, *out_len, uncompressed_data, &uncompressed_data_len) != 0) { DBG_INFO("Failed decompress data. Probably not compressed data"); } else { DBG_INFO("Successfully decompressed stored data. Stored data length %zu. " "Decompressed data length %zu", *out_len, uncompressed_data_len); memcpy(out, uncompressed_data, uncompressed_data_len); *out_len = uncompressed_data_len; } #else DBG_INFO("Compression is not supported. Will not try to decompress"); #endif } 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, const uint8_t *in, size_t in_len, yh_compress_option compress, size_t *import_len) { if (in == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (compress == COMPRESS_IF_TOO_BIG || compress == NO_COMPRESS) { yh_rc yrc = yh_util_import_opaque(session, object_id, label, domains, capabilities, algorithm, in, in_len); if (yrc == YHR_SUCCESS) { if (import_len != NULL) { *import_len = in_len; } return yrc; } else if (compress == NO_COMPRESS || (compress == COMPRESS_IF_TOO_BIG && yrc != YHR_BUFFER_TOO_SMALL)) { return yrc; } } #ifndef ENABLE_CERT_COMPRESS DBG_ERR("Data compression is not supported"); return YHR_INVALID_PARAMETERS; #else uint8_t compressed_data[YH_MSG_BUF_SIZE] = {0}; size_t compressed_data_len = sizeof(compressed_data); if (compress_data(in, in_len, compressed_data, &compressed_data_len) != 0) { DBG_ERR("Failed to compress data"); return YHR_GENERIC_ERROR; } if (import_len != NULL) { *import_len = compressed_data_len; } return yh_util_import_opaque(session, object_id, label, domains, capabilities, algorithm, compressed_data, compressed_data_len); #endif } yh_rc yh_util_sign_ssh_certificate(yh_session *session, uint16_t key_id, uint16_t template_id, yh_algorithm sig_algo, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { if (session == NULL || in == NULL || out == NULL || out_len == NULL || in_len == 0) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint16_t template_id; uint8_t algo; uint8_t bytes[YH_MSG_BUF_SIZE - sizeof(key_id) - sizeof(template_id) - 2]; }; uint8_t buf[1]; } data = {0}; size_t data_len; #pragma pack(pop) yh_cmd response_cmd = 0; data.key_id = htons(key_id); data.template_id = htons(template_id); data.algo = sig_algo; if (in_len > sizeof(data.bytes)) { DBG_ERR("Data length must be in [0, %lu]\n", (unsigned long) sizeof(data.bytes)); return YHR_INVALID_PARAMETERS; } data_len = in_len + 5; memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_SIGN_SSH_CERTIFICATE, data.buf, data_len, &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send SIGN SSH CERTIFICATE command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_get_template(yh_session *session, uint16_t object_id, uint8_t *out, size_t *out_len) { if (session == NULL || out == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t data[2] = {0}; yh_cmd response_cmd = 0; uint16_t object_id_h = htons(object_id); memcpy(data, &object_id_h, sizeof(object_id_h)); yh_rc yrc = yh_send_secure_msg(session, YHC_GET_TEMPLATE, data, sizeof(data), &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET TEMPLATE command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_import_template(yh_session *session, uint16_t *object_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, const uint8_t *in, size_t in_len) { if (session == NULL || object_id == NULL || label == NULL || capabilities == NULL || strlen(label) > YH_OBJ_LABEL_LEN || in == NULL || in_len == 0) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t object_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint8_t bytes[YH_MSG_BUF_SIZE - sizeof(object_id) - sizeof(domains) - YH_OBJ_LABEL_LEN - YH_CAPABILITIES_LEN - 2]; }; uint8_t buf[1]; } data = {0}; size_t data_len; union { struct { uint16_t object_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; data.object_id = htons(*object_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); data.algorithm = algorithm; if (in_len > sizeof(data.bytes)) { DBG_ERR("Data length must be in [0, %lu]\n", (unsigned long) sizeof(data.bytes)); return YHR_INVALID_PARAMETERS; } data_len = in_len + sizeof(data.object_id) + sizeof(data.domains) + YH_CAPABILITIES_LEN + YH_OBJ_LABEL_LEN + sizeof(data.algorithm); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_PUT_TEMPLATE, data.buf, data_len, &response_cmd, response.buf, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send PUT TEMPLATE command: %s", yh_strerror(yrc)); return yrc; } *object_id = ntohs(response.object_id); DBG_INFO("Stored Opaque Object 0x%04x", *object_id); return YHR_SUCCESS; } yh_rc yh_get_session_id(yh_session *session, uint8_t *sid) { if (session == NULL || sid == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } *sid = session->s.sid; return YHR_SUCCESS; } static uint8_t get_auth_key_algo(size_t key_len) { switch (key_len) { case 32: return YH_ALGO_AES128_YUBICO_AUTHENTICATION; case 64: return YH_ALGO_EC_P256_YUBICO_AUTHENTICATION; default: return 0; } } yh_rc yh_util_import_authentication_key( yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, const yh_capabilities *delegated_capabilities, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len) { uint8_t algorithm = get_auth_key_algo(key_enc_len + key_mac_len); DBG_INFO("Auth Key Algorithm %u", algorithm); if (session == NULL || key_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN || capabilities == NULL || delegated_capabilities == NULL || (key_enc == NULL && key_enc_len > 0) || (key_mac == NULL && key_mac_len > 0) || key_enc_len + key_mac_len > 64 || algorithm == 0) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint8_t delegated_capabilities[YH_CAPABILITIES_LEN]; uint8_t key[64]; }; uint8_t buf[1]; } data = {0}; union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; memcpy(data.key, key_enc, key_enc_len); memcpy(data.key + key_enc_len, key_mac, key_mac_len); data.key_id = htons(*key_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); data.algorithm = algorithm; memcpy(data.delegated_capabilities, delegated_capabilities, YH_CAPABILITIES_LEN); yh_rc yrc = yh_send_secure_msg(session, YHC_PUT_AUTHENTICATION_KEY, data.buf, sizeof(data) - sizeof(data.key) + key_enc_len + key_mac_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, sizeof(data)); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send PUT AUTHENTICATION KEY command: %s\n", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Stored Authentication key 0x%04x", *key_id); return YHR_SUCCESS; } yh_rc yh_util_import_authentication_key_derived( yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, const yh_capabilities *delegated_capabilities, const uint8_t *password, size_t password_len) { if (session == NULL || key_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN || capabilities == NULL || delegated_capabilities == NULL || password == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t key[2 * SCP_KEY_LEN] = {0}; yh_rc yrc = derive_key(password, password_len, key, sizeof(key)); if (yrc == YHR_SUCCESS) { yrc = yh_util_import_authentication_key(session, key_id, label, domains, capabilities, delegated_capabilities, key, SCP_KEY_LEN, key + SCP_KEY_LEN, SCP_KEY_LEN); insecure_memzero(key, sizeof(key)); } return yrc; } yh_rc yh_util_change_authentication_key(yh_session *session, uint16_t *key_id, const uint8_t *key_enc, size_t key_enc_len, const uint8_t *key_mac, size_t key_mac_len) { uint8_t algorithm = get_auth_key_algo(key_enc_len + key_mac_len); DBG_INFO("Auth Key Algorithm %u", algorithm); if (session == NULL || key_id == NULL || algorithm == 0 || (key_enc == NULL && key_enc_len > 0) || (key_mac == NULL && key_mac_len > 0) || key_enc_len + key_mac_len > 64) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t algorithm; uint8_t key[64]; }; uint8_t buf[1]; } data = {0}; union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; data.key_id = htons(*key_id); data.algorithm = algorithm; memcpy(data.key, key_enc, key_enc_len); memcpy(data.key + key_enc_len, key_mac, key_mac_len); yh_rc yrc = yh_send_secure_msg(session, YHC_CHANGE_AUTHENTICATION_KEY, data.buf, sizeof(data) - sizeof(data.key) + key_enc_len + key_mac_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, sizeof(data)); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send CHANGE AUTHENTICATION KEY command: %s\n", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Changed Authentication key 0x%04x", *key_id); return YHR_SUCCESS; } yh_rc yh_util_change_authentication_key_derived(yh_session *session, uint16_t *key_id, const uint8_t *password, size_t password_len) { if (session == NULL || key_id == NULL || password == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t key[2 * SCP_KEY_LEN] = {0}; yh_rc yrc = derive_key(password, password_len, key, sizeof(key)); if (yrc == YHR_SUCCESS) { yrc = yh_util_change_authentication_key(session, key_id, key, SCP_KEY_LEN, key + SCP_KEY_LEN, SCP_KEY_LEN); insecure_memzero(key, sizeof(key)); } return yrc; } yh_rc yh_util_create_otp_aead(yh_session *session, uint16_t key_id, const uint8_t *key, const uint8_t *private_id, uint8_t *out, size_t *out_len) { if (session == NULL || key == NULL || private_id == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t key[16]; uint8_t private_id[6]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) yh_cmd response_cmd = 0; data.key_id = htons(key_id); memcpy(data.key, key, sizeof(data.key)); memcpy(data.private_id, private_id, sizeof(data.private_id)); yh_rc yrc = yh_send_secure_msg(session, YHC_CREATE_OTP_AEAD, data.buf, sizeof(data), &response_cmd, out, out_len); insecure_memzero(data.buf, sizeof(data)); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send CREATE OTP AEAD command: %s\n", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_randomize_otp_aead(yh_session *session, uint16_t key_id, uint8_t *out, size_t *out_len) { if (session == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) yh_cmd response_cmd = 0; data.key_id = htons(key_id); yh_rc yrc = yh_send_secure_msg(session, YHC_RANDOMIZE_OTP_AEAD, data.buf, sizeof(data), &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send RANDOMIZE OTP AEAD command: %s\n", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_decrypt_otp(yh_session *session, uint16_t key_id, const uint8_t *aead, size_t aead_len, const uint8_t *otp, uint16_t *useCtr, uint8_t *sessionCtr, uint8_t *tstph, uint16_t *tstpl) { #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t aead[6 + 16 + 6 + 8]; // FIXME: ya.. magic numbers! uint8_t otp[16]; }; uint8_t buf[1]; } data = {0}; union { struct { uint16_t useCtr; uint8_t sessionCtr; uint8_t tstph; uint16_t tstpl; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) if (session == NULL || aead == NULL || otp == NULL || aead_len != sizeof(data.aead)) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } yh_cmd response_cmd = 0; size_t response_len = sizeof(response); data.key_id = htons(key_id); memcpy(data.aead, aead, sizeof(data.aead)); memcpy(data.otp, otp, sizeof(data.otp)); yh_rc yrc = yh_send_secure_msg(session, YHC_DECRYPT_OTP, data.buf, sizeof(data), &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, sizeof(data)); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send DECRYPT OTP command: %s\n", yh_strerror(yrc)); return yrc; } if (response_len != sizeof(response)) { DBG_ERR("Wrong size returned"); return YHR_WRONG_LENGTH; } if (useCtr) { *useCtr = response.useCtr; } if (sessionCtr) { *sessionCtr = response.sessionCtr; } if (tstph) { *tstph = response.tstph; } if (tstpl) { *tstpl = response.tstpl; } return YHR_SUCCESS; } yh_rc yh_util_rewrap_otp_aead(yh_session *session, uint16_t id_from, uint16_t id_to, const uint8_t *aead_in, size_t in_len, uint8_t *aead_out, size_t *out_len) { #pragma pack(push, 1) union { struct { uint16_t from_key; uint16_t to_key; uint8_t aead[6 + 16 + 6 + 8]; // FIXME: magic numbers! }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) if (session == NULL || aead_in == NULL || aead_out == NULL || out_len == NULL || in_len != sizeof(data.aead) || *out_len < sizeof(data.aead)) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } data.from_key = htons(id_from); data.to_key = htons(id_to); memcpy(data.aead, aead_in, sizeof(data.aead)); yh_cmd response_cmd = 0; yh_rc yrc = yh_send_secure_msg(session, YHC_REWRAP_OTP_AEAD, data.buf, sizeof(data), &response_cmd, aead_out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send REWRAP OTP AEAD command: %s\n", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_import_otp_aead_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, uint32_t nonce_id, const uint8_t *in, size_t in_len) { if (session == NULL || key_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN || capabilities == NULL || in == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint32_t nonce_id; uint8_t key[32]; }; uint8_t buf[1]; } data = {0}; union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t data_len = sizeof(data); size_t response_len = sizeof(response); yh_cmd response_cmd = 0; if (in_len == 16) { data.algorithm = YH_ALGO_AES128_YUBICO_OTP; data_len -= 16; } else if (in_len == 24) { data.algorithm = YH_ALGO_AES192_YUBICO_OTP; data_len -= 8; } else if (in_len == 32) { data.algorithm = YH_ALGO_AES256_YUBICO_OTP; } else { DBG_ERR("Key length has to be 16, 24 or 32 bytes."); return YHR_INVALID_PARAMETERS; } data.key_id = htons(*key_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); data.nonce_id = nonce_id; memcpy(data.key, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_PUT_OTP_AEAD_KEY, data.buf, data_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send PUT OTP AEAD KEY command: %s", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Imported OTP AEAD key 0x%04x", *key_id); return YHR_SUCCESS; } yh_rc yh_util_generate_otp_aead_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, uint32_t nonce_id) { if (session == NULL || key_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN || capabilities == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t label[YH_OBJ_LABEL_LEN]; uint16_t domains; uint8_t capabilities[YH_CAPABILITIES_LEN]; uint8_t algorithm; uint32_t nonce_id; }; uint8_t buf[1]; } data = {0}; size_t data_len = sizeof(data); union { struct { uint16_t key_id; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_cmd response_cmd = 0; data.key_id = htons(*key_id); memcpy(data.label, label, strlen(label)); memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label)); data.domains = htons(domains); memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN); data.algorithm = algorithm; data.nonce_id = nonce_id; yh_rc yrc = yh_send_secure_msg(session, YHC_GENERATE_OTP_AEAD_KEY, data.buf, data_len, &response_cmd, response.buf, &response_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GENERATE OTP AEAD KEY command: %s", yh_strerror(yrc)); return yrc; } *key_id = ntohs(response.key_id); DBG_INFO("Generated OTP AEAD key 0x%04x\n", *key_id); return YHR_SUCCESS; } yh_rc yh_util_sign_attestation_certificate(yh_session *session, uint16_t key_id, uint16_t attest_id, uint8_t *out, size_t *out_len) { if (session == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint16_t attest_id; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) yh_cmd response_cmd = 0; data.key_id = htons(key_id); data.attest_id = htons(attest_id); yh_rc yrc = yh_send_secure_msg(session, YHC_SIGN_ATTESTATION_CERTIFICATE, data.buf, sizeof(data), &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send SIGN ATTESTATION CERTIFICATE command: %s\n", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } static int get_audit_cmd_value(uint8_t *option_value, size_t len, yh_cmd cmd) { for (size_t i = 0; i < len; i += 2) { if (option_value[i] == cmd) { return option_value[i + 1]; } } return -1; } yh_rc yh_util_set_option(yh_session *session, yh_option option, size_t len, uint8_t *val) { if (session == NULL || val == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (len > YH_MSG_BUF_SIZE - 3) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 3); return YHR_INVALID_PARAMETERS; } // This is a workaround for older YubiHSMs. By enabling command-audit for // 0x05, the YubiHSM risks ending up in a deadlock state where audit-log is // full but cannot be read. This is fixed in the firmware on newer YubiHSMs if (option == YH_OPTION_COMMAND_AUDIT && get_audit_cmd_value(val, len, YHC_SESSION_MESSAGE) > 0) { DBG_ERR("Command-audit cannot be turned on for command %02x", YHC_SESSION_MESSAGE); return YHR_DEVICE_INVALID_DATA; } #pragma pack(push, 1) union { struct { uint8_t option; uint16_t len; uint8_t bytes[1]; }; uint8_t buf[YH_MSG_BUF_SIZE]; } data = {0}; #pragma pack(pop) uint8_t out[YH_MSG_BUF_SIZE] = {0}; size_t outlen = sizeof(out); yh_cmd response_cmd = 0; data.option = option; data.len = htons(len); memcpy(data.bytes, val, len); yh_rc yrc = yh_send_secure_msg(session, YHC_SET_OPTION, data.buf, len + 3, &response_cmd, out, &outlen); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send SET OPTION command: %s\n", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_get_option(yh_session *session, yh_option option, uint8_t *out, size_t *out_len) { if (session == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t buf[1] = {option}; yh_cmd response_cmd = 0; yh_rc yrc = yh_send_secure_msg(session, YHC_GET_OPTION, buf, sizeof(buf), &response_cmd, out, out_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET OPTION command: %s\n", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_get_storage_info(yh_session *session, uint16_t *total_records, uint16_t *free_records, uint16_t *total_pages, uint16_t *free_pages, uint16_t *page_size) { if (session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } yh_cmd response_cmd = 0; #pragma pack(push, 1) union { struct { uint16_t total_records; uint16_t free_records; uint16_t total_pages; uint16_t free_pages; uint16_t page_size; }; uint8_t buf[1]; } response = {0}; #pragma pack(pop) size_t response_len = sizeof(response); yh_rc yrc = yh_send_secure_msg(session, YHC_GET_STORAGE_INFO, NULL, 0, &response_cmd, response.buf, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send GET STORAGE INFO command: %s\n", yh_strerror(yrc)); return yrc; } if (total_records) { *total_records = ntohs(response.total_records); } if (free_records) { *free_records = ntohs(response.free_records); } if (total_pages) { *total_pages = ntohs(response.total_pages); } if (free_pages) { *free_pages = ntohs(response.free_pages); } if (page_size) { *page_size = ntohs(response.page_size); } return YHR_SUCCESS; } yh_rc yh_util_wrap_data(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { if (session == NULL || in == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len > YH_MSG_BUF_SIZE - 2) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) size_t data_len = in_len + 2; yh_cmd response_cmd = 0; data.key_id = htons(key_id); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_WRAP_DATA, data.buf, data_len, &response_cmd, out, out_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send WRAP DATA command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_unwrap_data(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { if (session == NULL || in == NULL || out == NULL || out_len == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len > YH_MSG_BUF_SIZE - 2) { DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2); return YHR_INVALID_PARAMETERS; } #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[YH_MSG_BUF_SIZE]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) size_t data_len = in_len + 2; yh_cmd response_cmd = 0; data.key_id = htons(key_id); memcpy(data.bytes, in, in_len); yh_rc yrc = yh_send_secure_msg(session, YHC_UNWRAP_DATA, data.buf, data_len, &response_cmd, out, out_len); insecure_memzero(data.buf, data_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send UNWRAP DATA command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } static yh_rc encrypt_ecb(yh_cmd cmd, yh_session *session, size_t block_size, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[2026]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) if (session == NULL || in == NULL || out == NULL || out_len == NULL || block_size == 0 || block_size > sizeof(data.bytes) || in_len % block_size != 0) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len == 0) { *out_len = 0; return YHR_SUCCESS; } if (in_len > *out_len) { *out_len = in_len; return YHR_BUFFER_TOO_SMALL; } yh_cmd response_cmd = 0; data.key_id = htons(key_id); yh_rc yrc = YHR_SUCCESS; size_t rem = in_len; const size_t chunksiz = sizeof(data.bytes) / block_size * block_size; while (rem != 0) { size_t ochunk, ichunk; ochunk = ichunk = rem < chunksiz ? rem : chunksiz; memcpy(data.bytes, in, ichunk); if ((yrc = yh_send_secure_msg(session, cmd, data.buf, 2 + ichunk, &response_cmd, out, &ochunk)) != YHR_SUCCESS) { goto ecb_fail; } else if (ochunk != ichunk) { yrc = YHR_GENERIC_ERROR; goto ecb_fail; } in += ichunk; out += ichunk; rem -= ichunk; } *out_len = in_len; ecb_fail: insecure_memzero(data.buf, sizeof(data.buf)); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send ECB command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_encrypt_aes_ecb(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { return encrypt_ecb(YHC_ENCRYPT_ECB, session, AES_BLOCK_SIZE, key_id, in, in_len, out, out_len); } yh_rc yh_util_decrypt_aes_ecb(yh_session *session, uint16_t key_id, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { return encrypt_ecb(YHC_DECRYPT_ECB, session, AES_BLOCK_SIZE, key_id, in, in_len, out, out_len); } static yh_rc encrypt_cbc(yh_cmd cmd, yh_session *session, uint16_t key_id, const uint8_t *iv, size_t iv_len, const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { #pragma pack(push, 1) union { struct { uint16_t key_id; uint8_t bytes[2026]; }; uint8_t buf[1]; } data = {0}; #pragma pack(pop) if (session == NULL || in == NULL || out == NULL || out_len == NULL || iv_len == 0 || iv_len >= sizeof(data.bytes) || sizeof(data.bytes) - iv_len < iv_len || in_len % iv_len != 0) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (in_len == 0) { *out_len = 0; return YHR_SUCCESS; } if (in_len > *out_len) { *out_len = in_len; return YHR_BUFFER_TOO_SMALL; } yh_cmd response_cmd = 0; data.key_id = htons(key_id); memcpy(data.bytes, iv, iv_len); yh_rc yrc = YHR_SUCCESS; size_t rem = in_len; const size_t chunksiz = (sizeof(data.bytes) - iv_len) / iv_len * iv_len; while (rem != 0) { size_t ochunk, ichunk; ochunk = ichunk = rem < chunksiz ? rem : chunksiz; memcpy(data.bytes + iv_len, in, ichunk); if ((yrc = yh_send_secure_msg(session, cmd, data.buf, 2 + iv_len + ichunk, &response_cmd, out, &ochunk)) != YHR_SUCCESS) { goto cbc_fail; } else if (ochunk != ichunk) { yrc = YHR_GENERIC_ERROR; goto cbc_fail; } if (cmd == YHC_ENCRYPT_CBC) { memcpy(data.bytes, out + ichunk - iv_len, iv_len); } else { memcpy(data.bytes, data.bytes + ichunk, iv_len); } in += ichunk; out += ichunk; rem -= ichunk; } *out_len = in_len; cbc_fail: insecure_memzero(data.buf, sizeof(data)); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send CBC command: %s", yh_strerror(yrc)); } return yrc; } yh_rc yh_util_encrypt_aes_cbc(yh_session *session, uint16_t key_id, const uint8_t iv[AES_BLOCK_SIZE], const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { return encrypt_cbc(YHC_ENCRYPT_CBC, session, key_id, iv, AES_BLOCK_SIZE, in, in_len, out, out_len); } yh_rc yh_util_decrypt_aes_cbc(yh_session *session, uint16_t key_id, const uint8_t iv[AES_BLOCK_SIZE], const uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { return encrypt_cbc(YHC_DECRYPT_CBC, session, key_id, iv, AES_BLOCK_SIZE, in, in_len, out, out_len); } yh_rc yh_util_pad_pkcs7(uint8_t *buffer, size_t *length, size_t size, uint8_t block_size) { if (buffer == NULL || length == NULL || block_size == 0 || SIZE_MAX - block_size < *length) { return YHR_INVALID_PARAMETERS; } size_t padded = (*length + block_size) - (*length % block_size); uint8_t pad = padded - *length; if (padded > size) { return YHR_BUFFER_TOO_SMALL; } memset(&buffer[*length], pad, pad); *length = padded; return YHR_SUCCESS; } yh_rc yh_util_unpad_pkcs7(uint8_t *buffer, size_t *length, uint8_t block_size) { if (buffer == NULL || length == NULL || block_size == 0 || *length < block_size) { return YHR_INVALID_PARAMETERS; } uint8_t pad = buffer[*length - 1]; if (pad == 0 || pad > block_size) { return YHR_GENERIC_ERROR; } size_t unpadded = *length - pad; if (memcmp(&buffer[unpadded], &buffer[unpadded + 1], pad - 1)) { return YHR_GENERIC_ERROR; } *length = unpadded; return YHR_SUCCESS; } yh_rc yh_util_blink_device(yh_session *session, uint8_t seconds) { if (session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } uint8_t response[5] = {0}; size_t response_len = sizeof(response); yh_cmd response_cmd = 0; yh_rc yrc = yh_send_secure_msg(session, YHC_BLINK_DEVICE, &seconds, sizeof(seconds), &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send BLINK DEVICE command: %s", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_util_reset_device(yh_session *session) { if (session == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } yh_cmd response_cmd = 0; uint8_t response[1] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_send_secure_msg(session, YHC_RESET_DEVICE, NULL, 0, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { DBG_ERR("Failed to send RESET DEVICE command: %s\n", yh_strerror(yrc)); return yrc; } return YHR_SUCCESS; } yh_rc yh_set_verbosity(yh_connector *connector, uint8_t verbosity) { _yh_verbosity = verbosity; if (connector != NULL && connector->bf != NULL) { // TODO(adma): should we error out if NULL? connector->bf->backend_set_verbosity(_yh_verbosity, _yh_output); } return YHR_SUCCESS; } yh_rc yh_get_verbosity(uint8_t *verbosity) { if (verbosity == NULL) { return YHR_INVALID_PARAMETERS; } *verbosity = _yh_verbosity; return YHR_SUCCESS; } void yh_set_debug_output(yh_connector *connector, FILE *output) { _yh_output = output; if (connector != NULL && connector->bf != NULL) { // TODO(adma): should we error out if NULL? connector->bf->backend_set_verbosity(_yh_verbosity, _yh_output); } } yh_rc yh_init(void) { if (_yh_output == NULL) { _yh_output = stderr; } return YHR_SUCCESS; } #ifdef STATIC static yh_rc load_backend(const char *name, void **backend, struct backend_functions **bf) { UNUSED(backend); if (name == NULL) { DBG_ERR("No name given to load_backend"); return YHR_GENERIC_ERROR; } #ifndef FUZZING else if (strncmp(name, STATIC_USB_BACKEND, strlen(STATIC_USB_BACKEND)) == 0) { *bf = usb_backend_functions(); } else if (strncmp(name, STATIC_HTTP_BACKEND, strlen(STATIC_HTTP_BACKEND)) == 0) { *bf = http_backend_functions(); } #else else if (strncmp(name, STATIC_FUZZ_BACKEND, strlen(STATIC_FUZZ_BACKEND)) == 0) { *bf = fuzz_backend_functions(); } #endif else { DBG_ERR("Failed finding backend named '%s'", name); return YHR_GENERIC_ERROR; } return (*bf)->backend_init(_yh_verbosity, _yh_output); } #else static yh_rc load_backend(const char *name, void **backend, struct backend_functions **bf) { struct backend_functions *(*fptr_backend_functions)(void); #ifdef WIN32 HMODULE module = GetModuleHandle("libyubihsm"); if (!module) { DBG_ERR("Failed getting module handle for 'libyubihsm'"); return YHR_GENERIC_ERROR; } char path[1024]; if (!GetModuleFileName(module, path, sizeof(path))) { DBG_ERR("Failed getting module path for 'libyubihsm'"); return YHR_GENERIC_ERROR; } char *p = strrchr(path, '\\'); if (!p) { DBG_ERR("Path separator not found in module path '%s'", path); return YHR_GENERIC_ERROR; } p[1] = 0; strcat_s(path, sizeof(path), name); DBG_INFO("Loading backend library '%s'", path); *backend = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (*backend == NULL) { DBG_ERR("Failed loading backend library '%s'", path); return YHR_GENERIC_ERROR; } fptr_backend_functions = (struct backend_functions * (*) (void) ) GetProcAddress(*backend, "backend_functions"); #else *backend = dlopen(name, RTLD_NOW); if (*backend == NULL) { DBG_ERR("Failed loading '%s' with error: '%s'", name, dlerror()); return YHR_GENERIC_ERROR; } *(void **) (&fptr_backend_functions) = dlsym(*backend, "backend_functions"); #endif if (fptr_backend_functions == NULL) { DBG_ERR("Symbol 'backend_functions' not found in '%s'", name); return YHR_GENERIC_ERROR; } *bf = fptr_backend_functions(); return (*bf)->backend_init(_yh_verbosity, _yh_output); } #endif yh_rc yh_exit(void) { return YHR_SUCCESS; } #define STATUS_ENDPOINT "/connector/status" #define API_ENDPOINT "/connector/api" static yh_rc create_connector(yh_connector **connector, const char *url, void *backend, struct backend_functions *bf) { if (connector == NULL) { return YHR_INVALID_PARAMETERS; } *connector = calloc(1, sizeof(yh_connector)); if (*connector == NULL) { return YHR_MEMORY_ERROR; } yh_rc rc = YHR_SUCCESS; if (strncmp(url, YH_USB_URL_SCHEME, strlen(YH_USB_URL_SCHEME)) == 0) { snprintf((*connector)->status_url, sizeof((*connector)->status_url), "%s", url); snprintf((*connector)->api_url, sizeof((*connector)->api_url), "%s", url); } else { snprintf((*connector)->status_url, sizeof((*connector)->status_url), "%s%s", url, STATUS_ENDPOINT); snprintf((*connector)->api_url, sizeof((*connector)->api_url), "%s%s", url, API_ENDPOINT); } (*connector)->connection = bf->backend_create(); if ((*connector)->connection == NULL) { rc = YHR_CONNECTION_ERROR; goto cc_failure; } (*connector)->backend = backend; (*connector)->bf = bf; return YHR_SUCCESS; cc_failure: if (*connector) { free(*connector); *connector = NULL; } return rc; } static void destroy_connector(yh_connector *connector) { if (connector == NULL) { return; } if (connector->bf != NULL && connector->connection != NULL) { connector->bf->backend_disconnect(connector->connection); connector->connection = NULL; } memset(connector->status_url, 0, sizeof(connector->status_url)); memset(connector->api_url, 0, sizeof(connector->api_url)); if (connector->bf) { connector->bf->backend_cleanup(); #ifndef STATIC #ifdef WIN32 FreeLibrary(connector->backend); #else dlclose(connector->backend); #endif #endif connector->backend = NULL; connector->bf = NULL; } free(connector); } yh_rc yh_init_connector(const char *url, yh_connector **connector) { if (url == NULL || connector == NULL) { DBG_ERR("Invalid parameters: undefined pointer"); return YHR_INVALID_PARAMETERS; } #ifdef STATIC #define USB_LIB STATIC_USB_BACKEND #define HTTP_LIB STATIC_HTTP_BACKEND #elif defined WIN32 #define USB_LIB "libyubihsm_usb.dll" #define HTTP_LIB "libyubihsm_http.dll" #elif defined __APPLE__ #define USB_LIB "libyubihsm_usb." SOVERSION ".dylib" #define HTTP_LIB "libyubihsm_http." SOVERSION ".dylib" #else #define USB_LIB "libyubihsm_usb.so." SOVERSION #define HTTP_LIB "libyubihsm_http.so." SOVERSION #endif void *backend = NULL; struct backend_functions *bf = NULL; if (strncmp(url, YH_USB_URL_SCHEME, strlen(YH_USB_URL_SCHEME)) == 0) { DBG_INFO("Loading usb backend"); load_backend(USB_LIB, &backend, &bf); } else if (strncmp(url, "http://", strlen("http://")) == 0 || strncmp(url, "https://", strlen("https://")) == 0) { DBG_INFO("Loading http backend"); load_backend(HTTP_LIB, &backend, &bf); } #ifdef FUZZING else if (strncmp(url, YH_FUZZ_URL_SCHEME, strlen(YH_FUZZ_URL_SCHEME)) == 0) { DBG_INFO("Loading fuzzing backend"); load_backend(STATIC_FUZZ_BACKEND, &backend, &bf); } #endif if (bf == NULL) { DBG_ERR("Failed loading the backend"); return YHR_GENERIC_ERROR; } return create_connector(connector, url, backend, bf); } yh_rc yh_set_connector_option(yh_connector *connector, yh_connector_option opt, const void *val) { if (connector == NULL || val == NULL) { DBG_ERR("Invalid parameters: undefined pointer"); return YHR_INVALID_PARAMETERS; } if (connector->bf == NULL) { DBG_ERR("No backend loaded"); return YHR_INVALID_PARAMETERS; } return connector->bf->backend_option(connector->connection, opt, val); } yh_rc yh_connect(yh_connector *connector, int timeout) { if (connector == NULL || connector->bf == NULL) { DBG_ERR("Invalid parameters: undefined pointer"); return YHR_INVALID_PARAMETERS; } yh_rc rc = connector->bf->backend_connect(connector, timeout); if (rc != YHR_SUCCESS) { DBG_ERR("Failed when connecting: %s", yh_strerror(rc)); return rc; } rc = yh_util_get_device_info_ex(connector, &connector->device_info); if (rc != YHR_SUCCESS) { DBG_ERR("Failed when connecting: %s", yh_strerror(rc)); } return YHR_SUCCESS; } yh_rc yh_disconnect(yh_connector *connector) { if (connector == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } destroy_connector(connector); return YHR_SUCCESS; } #ifndef htonll #define htonll(x) \ ((1 == htonl(1)) \ ? (x) \ : ((uint64_t) htonl((x) &0xFFFFFFFF) << 32) | htonl((x) >> 32)) #endif yh_rc yh_string_to_capabilities(const char *capability, yh_capabilities *result) { char *endptr = NULL; char *saveptr = NULL; char *str = NULL; char tmp[2048] = {0}; if (capability == NULL || result == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } errno = 0; uint64_t value = strtoull(capability, &endptr, 0); if (capability != endptr && errno != ERANGE) { uint64_t actual = htonll(value); memcpy(result, &actual, 8); return YHR_SUCCESS; } if (strcasecmp(capability, "all") == 0) { memset(result->capabilities, 0xff, YH_CAPABILITIES_LEN); return YHR_SUCCESS; } else if (strcasecmp(capability, "none") == 0) { memset(result->capabilities, 0x00, YH_CAPABILITIES_LEN); return YHR_SUCCESS; } if (strlen(capability) > sizeof(tmp) - 1) { return YHR_BUFFER_TOO_SMALL; } strncpy(tmp, capability, sizeof(tmp) - 1); while ((str = strtok_r(str ? NULL : tmp, LIST_SEPARATORS, &saveptr))) { for (size_t i = 0; i < sizeof(yh_capability) / sizeof(yh_capability[0]); i++) { if (strcasecmp(str, yh_capability[i].name) == 0) { result ->capabilities[YH_CAPABILITIES_LEN - 1 - yh_capability[i].bit / 8] |= 1ULL << (yh_capability[i].bit % 8); break; } else if (i + 1 == sizeof(yh_capability) / sizeof(yh_capability[0])) { return YHR_INVALID_PARAMETERS; } } } return YHR_SUCCESS; } yh_rc yh_capabilities_to_strings(const yh_capabilities *num, const char *result[], size_t *n_result) { if (num == 0 || result == NULL || n_result == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } size_t matching = 0; for (size_t i = 0; i < sizeof(yh_capability) / sizeof(yh_capability[0]); i++) { if (((1ULL << (yh_capability[i].bit % 8)) & num->capabilities[YH_CAPABILITIES_LEN - 1 - (yh_capability[i].bit / 8)]) != 0) { if (++matching > *n_result) { memset(result, 0, *n_result); return YHR_BUFFER_TOO_SMALL; } result[matching - 1] = yh_capability[i].name; } } *n_result = matching; return YHR_SUCCESS; } bool yh_check_capability(const yh_capabilities *capabilities, const char *capability) { yh_capabilities check_capabilities = {{0}}; if (yh_string_to_capabilities(capability, &check_capabilities) != YHR_SUCCESS) { return false; } for (int i = 0; i < YH_CAPABILITIES_LEN; i++) { if (check_capabilities.capabilities[i] != 0 && (check_capabilities.capabilities[i] & capabilities->capabilities[i]) != 0) { return true; } } return false; } yh_rc yh_merge_capabilities(const yh_capabilities *a, const yh_capabilities *b, yh_capabilities *result) { if (a == NULL || b == NULL || result == NULL) { return YHR_INVALID_PARAMETERS; } for (int i = 0; i < YH_CAPABILITIES_LEN; i++) { result->capabilities[i] = a->capabilities[i] | b->capabilities[i]; } return YHR_SUCCESS; } yh_rc yh_filter_capabilities(const yh_capabilities *capabilities, const yh_capabilities *filter, yh_capabilities *result) { if (capabilities == NULL || filter == NULL || result == NULL) { return YHR_INVALID_PARAMETERS; } for (int i = 0; i < YH_CAPABILITIES_LEN; i++) { result->capabilities[i] = capabilities->capabilities[i] & filter->capabilities[i]; } return YHR_SUCCESS; } bool yh_is_aes(yh_algorithm algorithm) { switch (algorithm) { case YH_ALGO_AES128: case YH_ALGO_AES192: case YH_ALGO_AES256: return true; default: break; } return false; } bool yh_is_rsa(yh_algorithm algorithm) { switch (algorithm) { case YH_ALGO_RSA_2048: case YH_ALGO_RSA_3072: case YH_ALGO_RSA_4096: return true; default: break; } return false; } bool yh_is_ec(yh_algorithm algorithm) { switch (algorithm) { case YH_ALGO_EC_P224: case YH_ALGO_EC_P256: case YH_ALGO_EC_P384: case YH_ALGO_EC_P521: case YH_ALGO_EC_K256: case YH_ALGO_EC_BP256: case YH_ALGO_EC_BP384: case YH_ALGO_EC_BP512: return true; default: break; } return false; } bool yh_is_ed(yh_algorithm algorithm) { switch (algorithm) { case YH_ALGO_EC_ED25519: return true; default: break; } return false; } bool yh_is_hmac(yh_algorithm algorithm) { switch (algorithm) { case YH_ALGO_HMAC_SHA1: case YH_ALGO_HMAC_SHA256: case YH_ALGO_HMAC_SHA384: case YH_ALGO_HMAC_SHA512: return true; default: break; } return false; } yh_rc yh_get_key_bitlength(yh_algorithm algorithm, size_t *result) { if (result == NULL) { return YHR_INVALID_PARAMETERS; } switch (algorithm) { case YH_ALGO_RSA_2048: *result = 2048; break; case YH_ALGO_RSA_3072: *result = 3072; break; case YH_ALGO_RSA_4096: *result = 4096; break; case YH_ALGO_EC_P256: *result = 256; break; case YH_ALGO_EC_P384: *result = 384; break; case YH_ALGO_EC_P521: *result = 521; break; case YH_ALGO_EC_P224: *result = 224; break; case YH_ALGO_EC_K256: *result = 256; break; case YH_ALGO_EC_BP256: *result = 256; break; case YH_ALGO_EC_BP384: *result = 384; break; case YH_ALGO_EC_BP512: *result = 512; break; case YH_ALGO_EC_ED25519: *result = 255; break; case YH_ALGO_HMAC_SHA1: *result = 160; break; case YH_ALGO_HMAC_SHA256: *result = 256; break; case YH_ALGO_HMAC_SHA384: *result = 384; break; case YH_ALGO_HMAC_SHA512: *result = 512; break; case YH_ALGO_AES128: case YH_ALGO_AES128_CCM_WRAP: *result = 128; break; case YH_ALGO_AES192: case YH_ALGO_AES192_CCM_WRAP: *result = 192; break; case YH_ALGO_AES256: case YH_ALGO_AES256_CCM_WRAP: *result = 256; break; default: *result = 0; return YHR_INVALID_PARAMETERS; } return YHR_SUCCESS; } yh_rc yh_algo_to_string(yh_algorithm algo, char const **result) { if (result == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } for (size_t i = 0; i < sizeof(yh_algorithms) / sizeof(yh_algorithms[0]); i++) { if (algo == yh_algorithms[i].algorithm) { *result = yh_algorithms[i].name; return YHR_SUCCESS; } } *result = "Unknown"; return YHR_SUCCESS; } yh_rc yh_string_to_algo(const char *string, yh_algorithm *algo) { if (string == NULL || algo == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (strcasecmp(string, "any") == 0) { *algo = 0; return YHR_SUCCESS; } for (size_t i = 0; i < sizeof(yh_algorithms) / sizeof(yh_algorithms[0]); i++) { if (strcasecmp(string, yh_algorithms[i].name) == 0) { *algo = yh_algorithms[i].algorithm; return YHR_SUCCESS; } } return YHR_INVALID_PARAMETERS; } yh_rc yh_type_to_string(yh_object_type type, char const **result) { if (result == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } for (size_t i = 0; i < sizeof(yh_types) / sizeof(yh_types[0]); i++) { if (type == yh_types[i].type) { *result = yh_types[i].name; return YHR_SUCCESS; } } *result = "Unknown"; return YHR_SUCCESS; } yh_rc yh_string_to_type(const char *string, yh_object_type *type) { if (string == NULL || type == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } if (strcasecmp(string, "any") == 0) { *type = 0; return YHR_SUCCESS; } for (size_t i = 0; i < sizeof(yh_types) / sizeof(yh_types[0]); i++) { if (strcasecmp(string, yh_types[i].name) == 0) { *type = yh_types[i].type; return YHR_SUCCESS; } } return YHR_INVALID_PARAMETERS; } yh_rc yh_string_to_option(const char *string, yh_option *option) { if (string == NULL || option == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } for (size_t i = 0; i < sizeof(yh_options) / sizeof(yh_options[0]); i++) { if (strcasecmp(string, yh_options[i].name) == 0) { *option = yh_options[i].option; return YHR_SUCCESS; } } return YHR_INVALID_PARAMETERS; } bool yh_verify_logs(yh_log_entry *logs, size_t n_items, yh_log_entry *last_previous_log) { if (logs == NULL || n_items == 0) { return false; } hash_ctx hashctx = NULL; uint8_t previous_hash[32] = {0}; size_t previous_hash_len = sizeof(previous_hash); int start; bool ret = false; if (!hash_create(&hashctx, _SHA256)) { return false; } if (last_previous_log != NULL) { memcpy(previous_hash, last_previous_log->digest, YH_LOG_DIGEST_SIZE); start = 0; } else { memcpy(previous_hash, logs[0].digest, YH_LOG_DIGEST_SIZE); start = 1; } for (size_t i = start; i < n_items; i++) { yh_log_entry inverted; inverted.number = htons(logs[i].number); inverted.command = logs[i].command; inverted.length = htons(logs[i].length); inverted.session_key = htons(logs[i].session_key); inverted.target_key = htons(logs[i].target_key); inverted.second_key = htons(logs[i].second_key); inverted.result = logs[i].result; inverted.systick = htonl(logs[i].systick); hash_init(hashctx); hash_update(hashctx, (const uint8_t *) &inverted, sizeof(yh_log_entry) - YH_LOG_DIGEST_SIZE); hash_update(hashctx, previous_hash, YH_LOG_DIGEST_SIZE); hash_final(hashctx, previous_hash, &previous_hash_len); if (memcmp(logs[i].digest, previous_hash, YH_LOG_DIGEST_SIZE) != 0) { goto out; } } ret = true; out: hash_destroy(hashctx); hashctx = NULL; return ret; } yh_rc yh_string_to_domains(const char *domains, uint16_t *result) { char *endptr = NULL; char *saveptr = NULL; char *str = NULL; char tmp[64] = {0}; unsigned long value; if (domains == NULL || result == NULL) { DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); return YHR_INVALID_PARAMETERS; } *result = 0; if (strcasecmp(domains, "all") == 0) { *result = 0xffff; goto out; } else if (strcmp(domains, "0") == 0) { goto out; } errno = 0; value = strtoul(domains, &endptr, 0); if (strncmp(domains, "0x", 2) == 0 && *endptr == '\0' && errno != ERANGE && value != ULONG_MAX) { if (value > USHRT_MAX) { DBG_ERR("Tried to parse to long number for domains"); return YHR_INVALID_PARAMETERS; } *result = value; } else { if (strlen(domains) > sizeof(tmp)) { return YHR_BUFFER_TOO_SMALL; } strncpy(tmp, domains, sizeof(tmp) - 1); while ((str = strtok_r(str ? NULL : tmp, LIST_SEPARATORS, &saveptr))) { endptr = NULL; value = strtoul(str, &endptr, 0); if (errno == ERANGE || value > YH_MAX_DOMAINS || value == 0) { DBG_ERR("Domains are numbered from 1 to %d", YH_MAX_DOMAINS); return YHR_INVALID_PARAMETERS; } *result |= 1 << (value - 1); } } out: DBG_INFO("Domains parsed as %x", *result); return YHR_SUCCESS; } yh_rc yh_domains_to_string(uint16_t domains, char *string, size_t max_len) { char *ptr = string; *ptr = '\0'; for (uint16_t i = 0; i < YH_MAX_DOMAINS; i++) { if (domains & (1 << i)) { size_t wrote = snprintf(ptr, max_len, "%d:", i + 1); if (wrote >= max_len) { return YHR_BUFFER_TOO_SMALL; } ptr += wrote; max_len -= wrote; } } if (ptr != string) { *(ptr - 1) = '\0'; } return YHR_SUCCESS; } yubihsm-shell-2.7.3/lib/error.c0000644000175000017500000000600615167357110015341 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #define ERR(name, desc) \ { name, desc } typedef struct { yh_rc rc; const char *description; } err_t; static const err_t errors[] = { ERR(YHR_SUCCESS, "Success"), ERR(YHR_MEMORY_ERROR, "Unable to allocate memory"), ERR(YHR_INIT_ERROR, "Unable to initialize libyubihsm"), ERR(YHR_CONNECTION_ERROR, "Connection error"), ERR(YHR_CONNECTOR_NOT_FOUND, "Unable to find a suitable connector"), ERR(YHR_INVALID_PARAMETERS, "Invalid argument to a function"), ERR(YHR_WRONG_LENGTH, "Mismatch between expected and received length"), ERR(YHR_BUFFER_TOO_SMALL, "Not enough space to store data"), ERR(YHR_CRYPTOGRAM_MISMATCH, "Unable to verify cryptogram"), ERR(YHR_SESSION_AUTHENTICATION_FAILED, "Unable to authenticate session"), ERR(YHR_MAC_MISMATCH, "Unable to verify MAC"), ERR(YHR_DEVICE_OK, "No error"), ERR(YHR_DEVICE_INVALID_COMMAND, "Unrecognized command"), ERR(YHR_DEVICE_INVALID_DATA, "Malformed command / invalid data"), ERR(YHR_DEVICE_INVALID_SESSION, "Invalid session"), ERR(YHR_DEVICE_AUTHENTICATION_FAILED, "Message encryption / verification failed"), ERR(YHR_DEVICE_SESSIONS_FULL, "All sessions are allocated"), ERR(YHR_DEVICE_SESSION_FAILED, "Session creation failed"), ERR(YHR_DEVICE_STORAGE_FAILED, "Storage failure"), ERR(YHR_DEVICE_WRONG_LENGTH, "Wrong length"), ERR(YHR_DEVICE_INSUFFICIENT_PERMISSIONS, "Wrong permissions for operation"), ERR(YHR_DEVICE_LOG_FULL, "Log buffer is full and forced audit is set"), ERR(YHR_DEVICE_OBJECT_NOT_FOUND, "Object not found"), ERR(YHR_DEVICE_INVALID_ID, "Invalid ID used"), ERR(YHR_DEVICE_INVALID_OTP, "Invalid OTP"), ERR(YHR_DEVICE_DEMO_MODE, "Demo mode, power cycle device"), ERR(YHR_DEVICE_COMMAND_UNEXECUTED, "The command execution has not terminated"), ERR(YHR_GENERIC_ERROR, "Generic error"), ERR(YHR_DEVICE_OBJECT_EXISTS, "An Object with that ID already exists"), ERR(YHR_CONNECTOR_ERROR, "Connector operation failed"), ERR(YHR_DEVICE_SSH_CA_CONSTRAINT_VIOLATION, "SSH CA constraint violation"), ERR(YHR_DEVICE_ALGORITHM_DISABLED, "Algorithm disabled"), }; const char *yh_strerror(yh_rc err) { static const char *unknown = "Unknown yubihsm error"; const char *p; if (-err < 0 || -err >= (int) (sizeof(errors) / sizeof(errors[0]))) { return unknown; } p = errors[-err].description; if (!p) { p = unknown; } return p; } yubihsm-shell-2.7.3/lib/tests/0000755000175000017500000000000015167357110015204 5ustar aveenaveenyubihsm-shell-2.7.3/lib/tests/test_util.c0000644000175000017500000000400215167357110017360 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include #include "yubihsm.h" #include "internal.h" uint8_t _yh_verbosity; FILE *_yh_output; static void test_status(void) { struct { const char *data; yh_connector c; } tests[] = { {"status=OK\nversion=1.2.3\n", {NULL, NULL, NULL, {0}, {0}, true, 1, 2, 3, "", 0, 0, {0}}}, {"", {NULL, NULL, NULL, {0}, {0}, false, 0, 0, 0, "", 0, 0, {0}}}, {"foobar", {NULL, NULL, NULL, {0}, {0}, false, 0, 0, 0, "", 0, 0, {0}}}, {"\n\n\n\n\n\n", {NULL, NULL, NULL, {0}, {0}, false, 0, 0, 0, "", 0, 0, {0}}}, {"status=NO_DEVICE\nserial=*\nversion=1.0.2\npid=412\naddress=\nport=12345", {NULL, NULL, NULL, {0}, {0}, false, 1, 0, 2, "", 12345, 412, {0}}}, {"version=1.2", {NULL, NULL, NULL, {0}, {0}, false, 1, 2, 0, "", 0, 0, {0}}}, {"version=foobar", {NULL, NULL, NULL, {0}, {0}, false, 0, 0, 0, "", 0, 0, {0}}}, {"version=2..\nstatus=OK", {NULL, NULL, NULL, {0}, {0}, true, 2, 0, 0, "", 0, 0, {0}}}, }; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { yh_connector c = {NULL, NULL, NULL, {0}, {0}, false, 0, 0, 0, "", 0, 0, {0}}; char *data = strdup(tests[i].data); parse_status_data(data, &c); free(data); assert(memcmp(&c, &tests[i].c, sizeof(c)) == 0); } } int main(void) { _yh_output = stderr; _yh_verbosity = 0; test_status(); return 0; } yubihsm-shell-2.7.3/lib/tests/CMakeLists.txt0000644000175000017500000000307015167357110017744 0ustar aveenaveen# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if(MSVC) set(ADDITIONAL_LIBRARY ws2_32) endif(MSVC) set ( SOURCE_PARSING test_parsing.c ) set ( SOURCE_PBKDF2 test_pbkdf2.c ../../common/pkcs5.c ../../common/hash.c ) set ( SOURCE_USB_URL test_usb_url.c ../lib_util.c ) if(MSVC) set(SOURCE_USB_URL ${SOURCE_USB_URL} ../../common/time_win.c) endif(MSVC) set ( SOURCE_UTIL test_util.c ../lib_util.c ) if(MSVC) set(SOURCE_UTIL ${SOURCE_UTIL} ../../common/time_win.c) endif(MSVC) include_directories ( ${CMAKE_CURRENT_SOURCE_DIR}/../lib ) add_executable (test_parsing ${SOURCE_PARSING}) add_executable (test_pbkdf2 ${SOURCE_PBKDF2}) add_executable (test_usb_url ${SOURCE_USB_URL}) add_executable (test_util ${SOURCE_UTIL}) target_link_libraries ( test_parsing yubihsm ) target_link_libraries ( test_pbkdf2 # this doesn't really need libyubihsm, needs openssl/windows whatever yubihsm ) target_link_libraries (test_usb_url ${ADDITIONAL_LIBRARY}) target_link_libraries (test_util ${ADDITIONAL_LIBRARY}) yubihsm-shell-2.7.3/lib/tests/test_parsing.c0000644000175000017500000002347415167357110020064 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "yubihsm.h" #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include static void test_domains1(void) { struct { const char *string; uint16_t domains; } tests[] = { {"1", 1}, {"1,2:3,4|5,6;7,8,9,10,11,12,13,14,15,16", 0xffff}, {"1,16", 0x8001}, {"16", 0x8000}, {"16,15", 0xc000}, {"1,0xf", 0x4001}, {"0x1,0x2", 3}, {"0x8888", 0x8888}, {"0", 0}, {"all", 0xffff}, {"2", 2}, {"2:4", 10}, }; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { uint16_t d = 0; assert(yh_string_to_domains(tests[i].string, &d) == YHR_SUCCESS); assert(d == tests[i].domains); } } static void test_domains2(void) { struct { uint16_t domains; const char *string; } tests[] = { {1, "1"}, {0x8001, "1:16"}, {0, ""}, {0xffff, "1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16"}, }; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { char s[256]; assert(yh_domains_to_string(tests[i].domains, s, 255) == YHR_SUCCESS); assert(strcmp(s, tests[i].string) == 0); } } static void test_capabilities1(void) { struct { const char *string; yh_capabilities capabilities; } tests[] = { {"get-opaque", {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}}, {"sign-hmac:verify-hmac|exportable-under-wrap,", {{0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00}}}, {",,unwrap-data|:wrap-data,,,", {{0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00}}}, {"0x7fffffffffffffff", {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}}, {"0xffffffffffffffff", {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}}, }; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { yh_capabilities c = {{0}}; assert(yh_string_to_capabilities(tests[i].string, &c) == YHR_SUCCESS); assert(memcmp(&c, &tests[i].capabilities, sizeof(c)) == 0); } } static void test_capabilities2(void) { yh_rc yrc = YHR_GENERIC_ERROR; yh_capabilities capabilities = {{0}}; const char *capabilities_array[8]; size_t capabilities_array_len; char *capabilities_list[] = {"sign-pkcs", "decrypt-pkcs", "export-wrapped", "set-option", "get-pseudo-random", "sign-hmac", "verify-hmac", "get-log-entries"}; char capabilities_string[1024]; size_t len = 0; for (size_t i = 0; i < sizeof(capabilities_list) / sizeof(capabilities_list[0]); i++) { snprintf(capabilities_string + len, sizeof(capabilities_string) - len, "%s:", capabilities_list[i]); len += strlen(capabilities_list[i]) + 1; } capabilities_string[len - 1] = '\0'; yrc = yh_string_to_capabilities(capabilities_string, &capabilities); assert(yrc == YHR_SUCCESS); assert(yh_check_capability(&capabilities, "something") == false); assert(yh_check_capability(&capabilities, "sign-pss") == false); assert(yh_check_capability(&capabilities, "sign-pkcs") == true); assert(yh_check_capability(&capabilities, "decrypt-pkcs") == true); assert(yh_check_capability(&capabilities, "export-wrapped") == true); assert(yh_check_capability(&capabilities, "set-option") == true); assert(yh_check_capability(&capabilities, "get-pseudo-random") == true); assert(yh_check_capability(&capabilities, "sign-hmac") == true); assert(yh_check_capability(&capabilities, "verify-hmac") == true); assert(yh_check_capability(&capabilities, "get-log-entries") == true); assert(yh_check_capability(&capabilities, "verify-hmac:get-log-entries") == true); capabilities_array_len = 1; yrc = yh_capabilities_to_strings(&capabilities, capabilities_array, &capabilities_array_len); assert(yrc == YHR_BUFFER_TOO_SMALL); capabilities_array_len = sizeof(capabilities_array) / sizeof(capabilities_array[0]); yrc = yh_capabilities_to_strings(&capabilities, capabilities_array, &capabilities_array_len); assert(yrc == YHR_SUCCESS); for (size_t i = 0; i < sizeof(capabilities_list) / sizeof(capabilities_list[0]); i++) { size_t j; for (j = 0; j < capabilities_array_len; j++) { if (strcmp(capabilities_list[i], capabilities_array[j]) == 0) { break; } } assert(j < capabilities_array_len); } } static void test_capabilities3(void) { const char *cap1 = "sign-pkcs,sign-pss"; const char *cap2 = "decrypt-pkcs,decrypt-oaep"; const char *cap3 = "sign-pss,decrypt-oaep"; yh_capabilities c1 = {{0}}; yh_capabilities c2 = {{0}}; yh_capabilities c3 = {{0}}; yh_capabilities res = {{0}}; assert(yh_string_to_capabilities(cap1, &c1) == YHR_SUCCESS); assert(yh_string_to_capabilities(cap2, &c2) == YHR_SUCCESS); assert(yh_string_to_capabilities(cap3, &c3) == YHR_SUCCESS); assert(yh_merge_capabilities(&c1, &c2, &res) == YHR_SUCCESS); assert(yh_check_capability(&res, "sign-pkcs") == true); assert(yh_check_capability(&res, "sign-pss") == true); assert(yh_check_capability(&res, "decrypt-pkcs") == true); assert(yh_check_capability(&res, "decrypt-oaep") == true); assert(yh_check_capability(&res, "sign-hmac") == false); assert(yh_filter_capabilities(&res, &c3, &res) == YHR_SUCCESS); assert(yh_check_capability(&res, "sign-pkcs") == false); assert(yh_check_capability(&res, "sign-pss") == true); assert(yh_check_capability(&res, "decrypt-pkcs") == false); assert(yh_check_capability(&res, "decrypt-oaep") == true); assert(yh_check_capability(&res, "sign-hmac") == false); } static void test_algorithms(void) { yh_rc yrc; assert(yh_is_hmac(YH_ALGO_RSA_2048) == false); assert(yh_is_hmac(YH_ALGO_HMAC_SHA1) == true); assert(yh_is_hmac(YH_ALGO_HMAC_SHA256) == true); assert(yh_is_hmac(YH_ALGO_HMAC_SHA384) == true); assert(yh_is_hmac(YH_ALGO_HMAC_SHA512) == true); yh_algorithm algorithm; yrc = yh_string_to_algo(NULL, &algorithm); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_string_to_algo("something", NULL); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_string_to_algo("something", &algorithm); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_string_to_algo("rsa-pkcs1-sha1", &algorithm); assert(yrc == YHR_SUCCESS && algorithm == YH_ALGO_RSA_PKCS1_SHA1); yrc = yh_string_to_algo("rsa2048", &algorithm); assert(yrc == YHR_SUCCESS && algorithm == YH_ALGO_RSA_2048); yrc = yh_string_to_algo("ecp384", &algorithm); assert(yrc == YHR_SUCCESS && algorithm == YH_ALGO_EC_P384); yrc = yh_string_to_algo("mgf1-sha512", &algorithm); assert(yrc == YHR_SUCCESS && algorithm == YH_ALGO_MGF1_SHA512); } static void test_options(void) { yh_rc yrc; yh_option option; yrc = yh_string_to_option(NULL, &option); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_string_to_option("something", NULL); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_string_to_option("something", &option); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_string_to_option("force-audit", &option); assert(yrc == YHR_SUCCESS && option == YH_OPTION_FORCE_AUDIT); } static void test_types(void) { yh_rc yrc; yh_object_type type; yrc = yh_string_to_type(NULL, &type); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_string_to_type("something", NULL); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_string_to_type("something", &type); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_string_to_type("opaque", &type); assert(yrc == YHR_SUCCESS && type == YH_OPAQUE); yrc = yh_string_to_type("authentication-key", &type); assert(yrc == YHR_SUCCESS && type == YH_AUTHENTICATION_KEY); yrc = yh_string_to_type("asymmetric-key", &type); assert(yrc == YHR_SUCCESS && type == YH_ASYMMETRIC_KEY); yrc = yh_string_to_type("wrap-key", &type); assert(yrc == YHR_SUCCESS && type == YH_WRAP_KEY); yrc = yh_string_to_type("hmac-key", &type); assert(yrc == YHR_SUCCESS && type == YH_HMAC_KEY); yrc = yh_string_to_type("template", &type); assert(yrc == YHR_SUCCESS && type == YH_TEMPLATE); yrc = yh_string_to_type("otp-aead-key", &type); assert(yrc == YHR_SUCCESS && type == YH_OTP_AEAD_KEY); const char *string; yrc = yh_type_to_string(0, NULL); assert(yrc == YHR_INVALID_PARAMETERS); yrc = yh_type_to_string(99, &string); assert(yrc == YHR_SUCCESS && strcmp(string, "Unknown") == 0); yrc = yh_type_to_string(YH_OPAQUE, &string); assert(yrc == YHR_SUCCESS && strcmp(string, "opaque") == 0); yrc = yh_type_to_string(YH_AUTHENTICATION_KEY, &string); assert(yrc == YHR_SUCCESS && strcmp(string, "authentication-key") == 0); yrc = yh_type_to_string(YH_ASYMMETRIC_KEY, &string); assert(yrc == YHR_SUCCESS && strcmp(string, "asymmetric-key") == 0); yrc = yh_type_to_string(YH_WRAP_KEY, &string); assert(yrc == YHR_SUCCESS && strcmp(string, "wrap-key") == 0); yrc = yh_type_to_string(YH_HMAC_KEY, &string); assert(yrc == YHR_SUCCESS && strcmp(string, "hmac-key") == 0); yrc = yh_type_to_string(YH_TEMPLATE, &string); assert(yrc == YHR_SUCCESS && strcmp(string, "template") == 0); yrc = yh_type_to_string(YH_OTP_AEAD_KEY, &string); assert(yrc == YHR_SUCCESS && strcmp(string, "otp-aead-key") == 0); } int main(void) { yh_init(); test_domains1(); test_domains2(); test_capabilities1(); test_capabilities2(); test_capabilities3(); test_algorithms(); test_options(); test_types(); return 0; } yubihsm-shell-2.7.3/lib/tests/test_pbkdf2.c0000644000175000017500000000561315167357110017564 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include "../../common/pkcs5.h" uint8_t _yh_verbosity = 0xff; FILE *_yh_output; static void test_pbkdf2_vectors(void) { struct vector { const uint8_t *password; size_t password_len; const uint8_t *salt; size_t salt_len; uint64_t iterations; hash_t hash; const uint8_t *output; size_t size; } vectors[] = { {(const uint8_t *) "password", 8, (const uint8_t *) "salt", 4, 1, _SHA1, (const uint8_t *) "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf" "\x60\x12\x06\x2f\xe0\x37\xa6", 20}, {(const uint8_t *) "password", 8, (const uint8_t *) "salt", 4, 2, _SHA1, (const uint8_t *) "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce" "\x1d\x41\xf0\xd8\xde\x89\x57", 20}, {(const uint8_t *) "password", 8, (const uint8_t *) "salt", 4, 4096, _SHA1, (const uint8_t *) "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26" "\xf7\x21\xd0\x65\xa4\x29\xc1", 20}, //{(const uint8_t*)"password", 8, (const uint8_t*)"salt", 4, 16777216, //_SHA1, (const // uint8_t*)"\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", // 20}, {(const uint8_t *) "passwordPASSWORDpassword", 24, (const uint8_t *) "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, 4096, _SHA1, (const uint8_t *) "\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62" "\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38", 25}, {(const uint8_t *) "pass\0word", 9, (const uint8_t *) "sa\0lt", 5, 4096, _SHA1, (const uint8_t *) "\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34\x25\xe0\xc3", 16}, }; for (size_t i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) { uint8_t key[256]; bool res = pkcs5_pbkdf2_hmac(vectors[i].password, vectors[i].password_len, vectors[i].salt, vectors[i].salt_len, vectors[i].iterations, vectors[i].hash, key, vectors[i].size); assert(res == true); assert(memcmp(key, vectors[i].output, vectors[i].size) == 0); } } int main(void) { test_pbkdf2_vectors(); return 0; } yubihsm-shell-2.7.3/lib/tests/test_usb_url.c0000644000175000017500000000304515167357110020064 0ustar aveenaveen/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include #include "yubihsm.h" #include "internal.h" uint8_t _yh_verbosity = YH_VERB_ALL; FILE *_yh_output; static void test_urls(void) { struct { const char *string; unsigned long serial; bool ret; } tests[] = { {"yhusb://serial=12345", 12345, true}, {"", 0, false}, {"yhusb://", 0, true}, {"yhusb://foo=bar&serial=1000000", 1000000, true}, {"yhusb://serial=0001234", 1234, true}, {"yhusb://serial=0x1234", 0, false}, {"yhusb://serial=FF", 0, false}, {"yhusb://serial=1234foo", 0, false}, {"yhusb://serial=", 0, false}, }; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { unsigned long serial = 0; assert(parse_usb_url(tests[i].string, &serial) == tests[i].ret); if (tests[i].ret) { assert(serial == tests[i].serial); } } } int main(void) { _yh_output = stderr; test_urls(); return 0; } yubihsm-shell-2.7.3/lib/Doxyfile0000644000175000017500000031732515167357110015563 0ustar aveenaveen# Doxyfile 1.8.11 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "libyubihsm" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doxygen # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = NO # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = YES # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete # parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = YES # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = yubihsm.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, # *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the # cost of reduced performance. This can be particularly helpful with template # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse-libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /