aboutsummaryrefslogtreecommitdiffstats
path: root/TPM2-Plugin/lib
diff options
context:
space:
mode:
authorNingSun <ning.sun@intel.com>2018-03-27 10:42:51 -0700
committerNingSun <ning.sun@intel.com>2018-03-28 16:03:21 -0700
commit8a5b33a9ba846d785d244e29bc29a46f7be34928 (patch)
treea5b6ad7d3950a57fefd60dd1200c4ce52dd959b5 /TPM2-Plugin/lib
parentda00ff6db5e68773996ec79d711c45fb3444c580 (diff)
Add more codes in tpm2-plugin
Implement tpm2_plugin_load_key() and tpm2_plugin_rsa_sign() APIs Issue-ID: AAF-94 Change-Id: I5f4329fdf973e52264d9e0e8aabc864c5fbdeebf Signed-off-by: NingSun <ning.sun@intel.com>
Diffstat (limited to 'TPM2-Plugin/lib')
-rw-r--r--TPM2-Plugin/lib/Makefile.am5
-rw-r--r--TPM2-Plugin/lib/files.c8
-rw-r--r--TPM2-Plugin/lib/include/files.h34
-rw-r--r--TPM2-Plugin/lib/include/log.h2
-rw-r--r--TPM2-Plugin/lib/include/plugin_register.h45
-rw-r--r--TPM2-Plugin/lib/include/tpm2_alg_util.h2
-rw-r--r--TPM2-Plugin/lib/include/tpm2_attr_util.h2
-rw-r--r--TPM2-Plugin/lib/include/tpm2_convert.h99
-rw-r--r--TPM2-Plugin/lib/include/tpm2_error.h2
-rw-r--r--TPM2-Plugin/lib/include/tpm2_hash.h2
-rw-r--r--TPM2-Plugin/lib/include/tpm2_options.h208
-rw-r--r--TPM2-Plugin/lib/include/tpm2_plugin_api.h26
-rw-r--r--TPM2-Plugin/lib/include/tpm2_tcti_ldr.h16
-rw-r--r--TPM2-Plugin/lib/include/tpm2_tool.h86
-rw-r--r--TPM2-Plugin/lib/include/tpm2_util.h47
-rw-r--r--TPM2-Plugin/lib/tpm2_alg_util.c2
-rw-r--r--TPM2-Plugin/lib/tpm2_attr_util.c48
-rw-r--r--TPM2-Plugin/lib/tpm2_convert.c216
-rw-r--r--TPM2-Plugin/lib/tpm2_error.c3
-rw-r--r--TPM2-Plugin/lib/tpm2_hash.c2
-rw-r--r--TPM2-Plugin/lib/tpm2_plugin_api.c341
-rw-r--r--TPM2-Plugin/lib/tpm2_plugin_init.c26
-rw-r--r--TPM2-Plugin/lib/tpm2_tcti_ldr.c19
-rw-r--r--TPM2-Plugin/lib/tpm2_util.c67
24 files changed, 1125 insertions, 183 deletions
diff --git a/TPM2-Plugin/lib/Makefile.am b/TPM2-Plugin/lib/Makefile.am
index c82cf86..26689a7 100644
--- a/TPM2-Plugin/lib/Makefile.am
+++ b/TPM2-Plugin/lib/Makefile.am
@@ -1,4 +1,5 @@
AM_CPPFLAGS = -I ./include
lib_LTLIBRARIES = libtpm2-plugin.la
-libtpm2_plugin_la_SOURCES = tpm2_error.c tpm2_plugin_api.c tpm2_plugin_init.c tpm2_tcti_ldr.c tpm2_util.c log.c plugin_register.c files.c tpm2_attr_util.c tpm2_alg_util.c tpm2_hash.c
-libtpm2_plugin_la_LDFLAGS = -version-info @VERSION_INFO@ -lsapi -ltcti-socket -ltcti-device -lcrypto -lssl -ldl
+libtpm2_plugin_la_SOURCES = tpm2_error.c tpm2_plugin_api.c tpm2_plugin_init.c tpm2_tcti_ldr.c tpm2_util.c log.c plugin_register.c files.c tpm2_attr_util.c tpm2_alg_util.c tpm2_hash.c tpm2_convert.c
+#libtpm2_plugin_la_LDFLAGS = -version-info @VERSION_INFO@ -lsapi -ltss2 -ltcti-socket -ltcti-device -lcrypto -lssl -ldl
+libtpm2_plugin_la_LDFLAGS = -version-info @VERSION_INFO@ -lsapi -ltss2-mu -ltcti-socket -ltcti-device -lcrypto -lssl -ldl
diff --git a/TPM2-Plugin/lib/files.c b/TPM2-Plugin/lib/files.c
index e2e41f4..b28a225 100644
--- a/TPM2-Plugin/lib/files.c
+++ b/TPM2-Plugin/lib/files.c
@@ -32,9 +32,10 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
+#include <string.h>
-#include <sapi/tpm20.h>
-#include <sapi/tss2_mu.h>
+#include <tss2/tss2_sys.h>
+#include <tss2/tss2_mu.h>
#include "files.h"
#include "log.h"
@@ -634,3 +635,6 @@ LOAD_TYPE(TPM2B_SENSITIVE, sensitive)
SAVE_TYPE(TPMT_TK_HASHCHECK, validation)
LOAD_TYPE(TPMT_TK_HASHCHECK, validation)
+
+SAVE_TYPE(TPM2B_PRIVATE, private)
+LOAD_TYPE(TPM2B_PRIVATE, private)
diff --git a/TPM2-Plugin/lib/include/files.h b/TPM2-Plugin/lib/include/files.h
index 164e308..a4befc8 100644
--- a/TPM2-Plugin/lib/include/files.h
+++ b/TPM2-Plugin/lib/include/files.h
@@ -34,7 +34,7 @@
#include <stdbool.h>
#include <stdio.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
/**
* Reads a series of bytes from a file as a byte array. This is similar to files_read_bytes(),
@@ -214,6 +214,16 @@ bool files_load_ticket(const char *path, TPMT_TK_VERIFIED *ticket);
bool files_load_sensitive(const char *path, TPM2B_SENSITIVE *sensitive);
/**
+ * Serializes a TPM2B_SENSITIVE to the file path provided.
+ * @param sensitive
+ * The TPM2B_SENSITIVE to save to disk.
+ * @param path
+ * The path to save to.
+ * @return
+ * true on success, false on error.
+ */
+bool files_save_sensitive(TPM2B_SENSITIVE *sensitive, const char *path);
+/**
* Serializes a TPMT_TK_HASHCHECK to the file path provided.
* @param validation
* The TPMT_TK_HASHCHECK to save to disk.
@@ -236,6 +246,28 @@ bool files_save_validation(TPMT_TK_HASHCHECK *validation, const char *path);
bool files_load_validation(const char *path, TPMT_TK_HASHCHECK *validation);
/**
+ * Serializes a TPM2B_PRIVATE to the file path provided.
+ * @param private
+ * The TPM2B_PRIVATE to save to disk.
+ * @param path
+ * The path to save to.
+ * @return
+ * true on success, false on error.
+ */
+bool files_save_private(TPM2B_PRIVATE *private, const char *path);
+
+/**
+ * Loads a TPM2B_PRIVATE from disk.
+ * @param private
+ * The path to load from.
+ * @param validation
+ * The TPM2B_PRIVATE to load.
+ * @return
+ * true on success, false on error.
+ */
+bool files_load_private(const char *path, TPM2B_PRIVATE *private);
+
+/**
* Checks a file for existence.
* @param path
* The file to check for existence.
diff --git a/TPM2-Plugin/lib/include/log.h b/TPM2-Plugin/lib/include/log.h
index c4ae0bd..a93c1c2 100644
--- a/TPM2-Plugin/lib/include/log.h
+++ b/TPM2-Plugin/lib/include/log.h
@@ -34,7 +34,7 @@
#include <stdbool.h>
#include <stdio.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#include "tpm2_error.h"
#include "tpm2_util.h"
diff --git a/TPM2-Plugin/lib/include/plugin_register.h b/TPM2-Plugin/lib/include/plugin_register.h
index a154a24..2bb118d 100644
--- a/TPM2-Plugin/lib/include/plugin_register.h
+++ b/TPM2-Plugin/lib/include/plugin_register.h
@@ -36,17 +36,51 @@
extern "C" {
#endif
+#define MAX_ID_LENGTH (32)
+
+typedef struct buffer_info_s{
+ char id[MAX_ID_LENGTH+1];
+ int length_of_buffer;
+ unsigned char *buffer;
+}buffer_info_t;
+
+
+typedef struct sshsm_hw_plugin_activate_in_info_s {
+ int num_buffers;
+ buffer_info_t *buffer_info;
+}SSHSM_HW_PLUGIN_ACTIVATE_IN_INFO_t;
+
+typedef struct sshsm_hw_plugin_load_key_in_info_s {
+ int num_buffers;
+ buffer_info_t buffer_info[];
+}SSHSM_HW_PLUGIN_LOAD_KEY_IN_INFO_t;
+
+
+//typedef int (*sshsm_hw_plugin_load_key)(SSHSM_HW_PLUGIN_LOAD_KEY_IN_INFO_t *loadkey_in_info, void **keyHandle);
+
+//typedef int (*sshsm_hw_plugin_activate)(SSHSM_HW_PLUGIN_ACTIVATE_IN_INFO_t *activate_in_info);
+
/*
* Callback function definitions
*/
+typedef int (*fp_crypto_hw_plugin_init) ( );
+typedef int (*fp_crypto_hw_plugin_uninit) ( );
+typedef int (*fp_crypto_hw_plugin_activate)(
+ SSHSM_HW_PLUGIN_ACTIVATE_IN_INFO_t *activate_in_info
+ );
+
+typedef int (*fp_crypto_hw_plugin_load_key)(
+ SSHSM_HW_PLUGIN_LOAD_KEY_IN_INFO_t *loadkey_in_info,
+ void **keyHandle
+ );
typedef int (*fp_crypto_rsa_decrypt_init) (
/* IN */
unsigned long mechanism, /* PKCS#11 Mechanism */
void *param, /* PKCS#11 Paramter */
unsigned long param_len, /* PKCS#11 Parameter len */
/* OUT */
- void *cb /* Address of pointer to store context block */
+ void *cb /* Address of pointer to store context block */
);
typedef int (*fp_crypto_rsa_decrypt) (
@@ -167,10 +201,13 @@ typedef int (*fp_crypto_ecdsa_delete_object) (
);
-typedef struct
+typedef struct
{
- fp_crypto_rsa_decrypt_init cb_crypto_rsa_decrypt_init;
- fp_crypto_rsa_decrypt cb_crypto_rsa_decrypt;
+ fp_crypto_hw_plugin_init cb_crypto_hw_plugin_init;
+ fp_crypto_hw_plugin_uninit cb_crypto_hw_plugin_uninit;
+ fp_crypto_hw_plugin_activate cb_crypto_hw_plugin_activate;
+ fp_crypto_hw_plugin_load_key cb_crypto_hw_plugin_load_key;
+ fp_crypto_rsa_decrypt cb_crypto_rsa_decrypt;
fp_crypto_rsa_sign_init cb_crypto_rsa_sign_init;
fp_crypto_rsa_sign_update cb_crypto_rsa_sign_update;
fp_crypto_rsa_sign_final cb_crypto_rsa_sign_final;
diff --git a/TPM2-Plugin/lib/include/tpm2_alg_util.h b/TPM2-Plugin/lib/include/tpm2_alg_util.h
index ce4083c..b9511dc 100644
--- a/TPM2-Plugin/lib/include/tpm2_alg_util.h
+++ b/TPM2-Plugin/lib/include/tpm2_alg_util.h
@@ -33,7 +33,7 @@
#include <stdbool.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
/**
* Iterator callback routine for iterating over known algorithm name and value
diff --git a/TPM2-Plugin/lib/include/tpm2_attr_util.h b/TPM2-Plugin/lib/include/tpm2_attr_util.h
index 2487982..5964174 100644
--- a/TPM2-Plugin/lib/include/tpm2_attr_util.h
+++ b/TPM2-Plugin/lib/include/tpm2_attr_util.h
@@ -33,7 +33,7 @@
#include <stdbool.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
/**
* Converts a list of | (pipe) separated attributes as defined in tavle 204
diff --git a/TPM2-Plugin/lib/include/tpm2_convert.h b/TPM2-Plugin/lib/include/tpm2_convert.h
new file mode 100644
index 0000000..275d96a
--- /dev/null
+++ b/TPM2-Plugin/lib/include/tpm2_convert.h
@@ -0,0 +1,99 @@
+//**********************************************************************;
+// Copyright (c) 2017, SUSE GmbH
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+//**********************************************************************;
+
+#ifndef CONVERSION_H
+#define CONVERSION_H
+
+#include <stdbool.h>
+
+#include <tss2/tss2_sys.h>
+
+typedef enum tpm2_convert_pubkey_fmt tpm2_convert_pubkey_fmt;
+enum tpm2_convert_pubkey_fmt {
+ pubkey_format_tss,
+ pubkey_format_pem,
+ pubkey_format_der,
+ pubkey_format_err
+};
+
+typedef enum tpm2_convert_sig_fmt tpm2_convert_sig_fmt;
+enum tpm2_convert_sig_fmt {
+ signature_format_tss,
+ signature_format_plain,
+ signature_format_err
+};
+
+/**
+ * Parses the given command line public key format option string and returns
+ * the corresponding pubkey_format enum value.
+ *
+ * LOG_ERR is used to communicate errors.
+ *
+ * @return
+ * On error pubkey_format_err is returned.
+ */
+tpm2_convert_pubkey_fmt tpm2_convert_pubkey_fmt_from_optarg(const char *label);
+
+/**
+ * Converts the given public key structure into the requested target format
+ * and writes the result to the given file system path.
+ *
+ * LOG_ERR is used to communicate errors.
+ */
+bool tpm2_convert_pubkey_save(TPM2B_PUBLIC *public, tpm2_convert_pubkey_fmt format, const char *path);
+
+/**
+ * Loads a public key in the TSS format from a file.
+ * @param public
+ * The public key to load
+ * @param format
+ * @param path
+ * @return
+ */
+bool tpm2_convert_pubkey_load(TPM2B_PUBLIC *public, const char *path);
+
+/**
+ * Parses the given command line signature format option string and returns
+ * the corresponding signature_format enum value.
+ *
+ * LOG_ERR is used to communicate errors.
+ *
+ * @return
+ * On error signature_format_err is returned.
+ */
+tpm2_convert_sig_fmt tpm2_convert_sig_fmt_from_optarg(const char *label);
+
+/**
+ * Converts the given signature data into the requested target format and
+ * writes the result to the given file system path.
+ *
+ * LOG_ERR is used to communicate errors.
+ */
+bool tpm2_convert_sig(TPMT_SIGNATURE *signature, tpm2_convert_sig_fmt format,
+ const char *path);
+
+#endif /* CONVERSION_H */
diff --git a/TPM2-Plugin/lib/include/tpm2_error.h b/TPM2-Plugin/lib/include/tpm2_error.h
index 0549edc..01ec043 100644
--- a/TPM2-Plugin/lib/include/tpm2_error.h
+++ b/TPM2-Plugin/lib/include/tpm2_error.h
@@ -30,7 +30,7 @@
#include <stdbool.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
/**
* Number of error layers
diff --git a/TPM2-Plugin/lib/include/tpm2_hash.h b/TPM2-Plugin/lib/include/tpm2_hash.h
index 7fab882..627a95a 100644
--- a/TPM2-Plugin/lib/include/tpm2_hash.h
+++ b/TPM2-Plugin/lib/include/tpm2_hash.h
@@ -33,7 +33,7 @@
#include <stdbool.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
/**
* Hashes a BYTE array via the tpm.
diff --git a/TPM2-Plugin/lib/include/tpm2_options.h b/TPM2-Plugin/lib/include/tpm2_options.h
new file mode 100644
index 0000000..860d9b0
--- /dev/null
+++ b/TPM2-Plugin/lib/include/tpm2_options.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <getopt.h>
+
+#include <tss2/tss2_sys.h>
+
+typedef union tpm2_option_flags tpm2_option_flags;
+union tpm2_option_flags {
+ struct {
+ UINT8 verbose : 1;
+ UINT8 quiet : 1;
+ UINT8 enable_errata : 1;
+ };
+ UINT8 all;
+};
+
+/**
+ * This function pointer defines the interface for tcti initialization.
+ * ALL tool supported TCTIs should implement this interface.
+ * @param opts
+ * An option string, that is defined by the tcti, and is passed
+ * via the --tcti= or -T options.
+ *
+ * Anything following the : in the --tcti option is provides as opts.
+ * @return
+ * NULL on error or an initialized TCTI.
+ */
+typedef TSS2_TCTI_CONTEXT *(*tcti_init)(char *opts);
+
+/**
+ * Tools may implement this optional interface if they need
+ * to handle options.
+ * @param key
+ * The key of the option, ie short option return value from getopt_long().
+ * @param value
+ * The getopt_long optarg value.
+ * @return
+ * true on success, false on error.
+ * @note
+ * LOG_INFO and TOOL_OUTPUT will not work correctly during this callback.
+ * This is called after onstart() finishes, but before
+ * onrun() is invoked.
+ *
+ */
+typedef bool (*tpm2_option_handler)(char key, char *value);
+
+/**
+ * Called after option handling to process arguments, if specified.
+ * @param argc
+ * The number of args in argv.
+ * @param argv
+ * The arguments.
+ * @return
+ * true on success, false otherwise.
+ * @note
+ * LOG_INFO adn TOOL_OUTPUT will not work correctly during this callback.
+ * This is called after onstart() and tpm2_option_handler() (if specified),
+ * but before onrun() is invoked.
+ *
+ */
+typedef bool (*tpm2_arg_handler)(int argc, char **argv);
+
+/**
+ * TPM2_OPTIONS_* flags change default behavior of the argument parser
+ *
+ * TPM2_OPTIONS_SHOW_USAGE:
+ * Enable printing a short usage summary (I.e. help)
+ * TPM2_OPTIONS_NO_SAPI:
+ * Skip SAPI initialization. Removes the "-T" common option.
+ */
+#define TPM2_OPTIONS_SHOW_USAGE 0x1
+#define TPM2_OPTIONS_NO_SAPI 0x2
+
+struct tpm2_options {
+ struct {
+ tpm2_option_handler on_opt;
+ tpm2_arg_handler on_arg;
+ } callbacks;
+ char *short_opts;
+ size_t len;
+ UINT32 flags;
+ struct option long_opts[];
+};
+
+typedef struct tpm2_options tpm2_options;
+
+/**
+ * The onstart() routine expects a return of NULL or a tpm2_options structure.
+ * This routine initializes said object.
+ * @param short_opts
+ * Any short options you wish to specify to getopt_long.
+ * @param len
+ * The length of the long_opts array.
+ * @param long_opts
+ * Any long options you wish to specify to getopt_long().
+ * @param on_opt
+ * An option handling callback, which may be null if you don't wish
+ * to handle options.
+ * @param on_arg
+ * An argument handling callback, which may be null if you don't wish
+ * to handle arguments.
+ * @param flags
+ * TPM2_OPTIONS_* bit flags
+ * @return
+ * NULL on failure or an initialized tpm2_options object.
+ */
+tpm2_options *tpm2_options_new(const char *short_opts, size_t len,
+ const struct option *long_opts, tpm2_option_handler on_opt,
+ tpm2_arg_handler on_arg, UINT32 flags);
+
+/**
+ * Concatenates two tpm2_options objects, with src appended on
+ * dest. The internal callbacks for tpm2_arg_handler and tpm2_option_handler
+ * which were specified during tpm2_options_new() are copied from src to
+ * dest, thus overwriting dest. Short and long options are concatenated.
+ * @param dest
+ * The tpm2_options object to append to.
+ * @param src
+ * The source tpm2_options to append onto dest.
+ * @return
+ * true on success, false otherwise.
+ */
+bool tpm2_options_cat(tpm2_options **dest, tpm2_options *src);
+
+/**
+ * Free's a tpm2_options created via tpm2_options_new().
+ * @param opts
+ * The tpm2_options object to deallocate.
+ */
+void tpm2_options_free(tpm2_options *opts);
+
+typedef enum tpm2_option_code tpm2_option_code;
+enum tpm2_option_code {
+ tpm2_option_code_continue,
+ tpm2_option_code_stop,
+ tpm2_option_code_err
+};
+
+/**
+ * Parses the tpm2_tool command line.
+ *
+ * @param argc
+ * The argc from main.
+ * @param argv
+ * The argv from main.
+ * @param tool_opts
+ * The tool options gathered during onstart() lifecycle call.
+ * @param flags
+ * The tpm2_option_flags to set during parsing.
+ * @param tcti
+ * The tcti initialized from the tcti options.
+ * @return
+ * A tpm option code indicating if an error, further processing
+ * or an immediate exit is desired.
+ * @note
+ * Used by tpm2_tool, and likely should only be used there.
+ *
+ */
+tpm2_option_code tpm2_handle_options (int argc, char **argv,
+ tpm2_options *tool_opts, tpm2_option_flags *flags,
+ TSS2_TCTI_CONTEXT **tcti);
+
+/**
+ * Print usage summary for a given tpm2 tool.
+ *
+ * @param command
+ * The command to print its usage summary text.
+ * @param tool_opts
+ * The tpm2_options array that contains the tool options to print as a summary.
+ */
+void tpm2_print_usage(const char *command, struct tpm2_options *tool_opts);
+
+#endif /* OPTIONS_H */
diff --git a/TPM2-Plugin/lib/include/tpm2_plugin_api.h b/TPM2-Plugin/lib/include/tpm2_plugin_api.h
index 238af99..4c3ad63 100644
--- a/TPM2-Plugin/lib/include/tpm2_plugin_api.h
+++ b/TPM2-Plugin/lib/include/tpm2_plugin_api.h
@@ -35,7 +35,7 @@
#include <ctype.h>
#include <getopt.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#include "plugin_register.h"
@@ -90,6 +90,14 @@ void TeardownSysContext( TSS2_SYS_CONTEXT **sysContext );
TSS2_RC TeardownTctiResMgrContext( TSS2_TCTI_CONTEXT *tctiContext );
+int tpm2_plugin_init();
+int tpm2_plugin_uninit();
+int tpm2_plugin_activate(SSHSM_HW_PLUGIN_ACTIVATE_IN_INFO_t *activate_in_info);
+int tpm2_plugin_load_key(
+ SSHSM_HW_PLUGIN_LOAD_KEY_IN_INFO_t *loadkey_in_info,
+ void **keyHandle
+ );
+
int tpm2_rsa_create_object(
unsigned long appHandle,
//DhsmWPKRSAFormat* wpk,
@@ -104,13 +112,13 @@ int tpm2_rsa_create_object(
int tpm2_rsa_delete_object(
void *cb_object);
-int tpm2_rsa_sign_init(
+int tpm2_plugin_rsa_sign_init(
unsigned long mechanish,
void *param,
size_t len,
void *ctx);
-int tpm2_rsa_sign(
+int tpm2_plugin_rsa_sign(
void *ctx,
unsigned char *msg,
int msg_len,
@@ -119,12 +127,12 @@ int tpm2_rsa_sign(
int tpm2_import_object(
- unsigned long appHandle,
- unsigned char* tlvbuffer,
- int buflen,
- unsigned char* iv,
- int iv_len,
- unsigned char* tpm_pwd,
+ unsigned long appHandle,
+ unsigned char* tlvbuffer,
+ int buflen,
+ unsigned char* iv,
+ int iv_len,
+ unsigned char* tpm_pwd,
int tpm_pwd_len);
diff --git a/TPM2-Plugin/lib/include/tpm2_tcti_ldr.h b/TPM2-Plugin/lib/include/tpm2_tcti_ldr.h
index 1e20d3d..684e5e2 100644
--- a/TPM2-Plugin/lib/include/tpm2_tcti_ldr.h
+++ b/TPM2-Plugin/lib/include/tpm2_tcti_ldr.h
@@ -25,7 +25,7 @@
// THE POSSIBILITY OF SUCH DAMAGE.
//**********************************************************************;
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#ifndef LIB_TPM2_TCTI_LDR_H_
#define LIB_TPM2_TCTI_LDR_H_
@@ -34,8 +34,8 @@
* Loads a TCTI from a friendly name, library name, or path.
* For example
* friendly: path = tabrmd
- * library name: path = libtcti-socket.so
- * full path: path = /home/user/lib/libtcti-custom.so
+ * library name: path = libtss2-tcti-mssim.so
+ * full path: path = /home/user/lib/libtss2-tcti-custom.so
* @param path
* The path/library to load.
* @param opts
@@ -55,6 +55,16 @@ TSS2_TCTI_CONTEXT *tpm2_tcti_ldr_load(const char *path, const char *opts);
const TSS2_TCTI_INFO *tpm2_tcti_ldr_getinfo(void);
/**
+ * Given a tcti name, like mssim, tells you if the
+ * library is present using dlopen(3).
+ * @param name
+ * The friendly name of the tcti.
+ * @return
+ * True if present, false otherwise.
+ */
+bool tpm2_tcti_ldr_is_tcti_present(const char *name);
+
+/**
* Unloads the tcti loaded via tpm2_tcti_ldr_load();
*/
void tpm2_tcti_ldr_unload(void);
diff --git a/TPM2-Plugin/lib/include/tpm2_tool.h b/TPM2-Plugin/lib/include/tpm2_tool.h
new file mode 100644
index 0000000..f24be38
--- /dev/null
+++ b/TPM2-Plugin/lib/include/tpm2_tool.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef MAIN_H
+#define MAIN_H
+
+#include <tss2/tss2_sys.h>
+#include <stdbool.h>
+
+#include "tpm2_options.h"
+
+extern bool output_enabled;
+
+/**
+ * An optional interface for tools to specify what options they support.
+ * They are concatenated with main's options and passed to getopt_long.
+ * @param opts
+ * The callee can choose to set *opts to a tpm_options pointer allocated
+ * via tpm2_options_new(). Setting *opts to NULL is not an error, and
+ * Indicates that no options are specified by the tool.
+ *
+ * @return
+ * True on success, false on error.
+ */
+bool tpm2_tool_onstart(tpm2_options **opts) __attribute__((weak));
+
+/**
+ * This is the main interface for tools, after tcti and sapi initialization
+ * are performed.
+ * @param sapi_context
+ * The system api context.
+ * @param flags
+ * Flags that tools may wish to respect.
+ * @return
+ * 0 on success.
+ */
+int tpm2_tool_onrun (TSS2_SYS_CONTEXT *sapi_context, tpm2_option_flags flags) __attribute__((weak));
+
+/**
+ * Called when the tool is exiting, useful for cleanup.
+ */
+void tpm2_tool_onexit(void) __attribute__((weak));
+
+/**
+ * prints output to stdout respecting the quiet option.
+ * Ie when quiet, don't print.
+ * @param fmt
+ * The format specifier, ala printf.
+ * @param ...
+ * The varargs, just like printf.
+ */
+#define tpm2_tool_output(fmt, ...) \
+ do { \
+ if (output_enabled) { \
+ printf(fmt, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#endif /* MAIN_H */
diff --git a/TPM2-Plugin/lib/include/tpm2_util.h b/TPM2-Plugin/lib/include/tpm2_util.h
index edc759d..de02777 100644
--- a/TPM2-Plugin/lib/include/tpm2_util.h
+++ b/TPM2-Plugin/lib/include/tpm2_util.h
@@ -35,7 +35,7 @@
#include <stdint.h>
#include <stdio.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#include "tpm2_error.h"
@@ -118,20 +118,10 @@
__result; \
})
-/**
- * prints output to stdout respecting the quiet option.
- * Ie when quiet, don't print.
- * @param fmt
- * The format specifier, ala printf.
- * @param ...
- * The varargs, just like printf.
- */
-#define tpm2_tool_output(fmt, ...) \
- do { \
- if (output_enabled) { \
- printf(fmt, ##__VA_ARGS__); \
- } \
- } while (0)
+typedef struct {
+ UINT16 size;
+ BYTE buffer[0];
+} TPM2B;
int tpm2_util_hex_to_byte_structure(const char *inStr, UINT16 *byteLenth, BYTE *byteBuffer);
@@ -176,28 +166,23 @@ bool tpm2_util_string_to_uint16(const char *str, uint16_t *value);
* The data to print.
* @param len
* The length of the data.
- * @param plain
- * true for a plain hex string false for an xxd compatable
- * dump.
*/
-void tpm2_util_hexdump(const BYTE *data, size_t len, bool plain);
+void tpm2_util_hexdump(const BYTE *data, size_t len);
/**
- * Prints an xxd compatible hexdump to stdout if output is enabled,
+ * Prints a file as a hex string to stdout if quiet mode
+ * is not enabled.
* ie no -Q option.
*
* @param fd
* A readable open file.
* @param len
* The length of the data to read and print.
- * @param plain
- * true for a plain hex string false for an xxd compatable
- * dump.
* @return
* true if len bytes were successfully read and printed,
* false otherwise
*/
-bool tpm2_util_hexdump_file(FILE *fd, size_t len, bool plain);
+bool tpm2_util_hexdump_file(FILE *fd, size_t len);
/**
* Prints a TPM2B as a hex dump.
@@ -205,7 +190,7 @@ bool tpm2_util_hexdump_file(FILE *fd, size_t len, bool plain);
*/
static inline void tpm2_util_print_tpm2b(TPM2B *buffer) {
- return tpm2_util_hexdump(buffer->buffer, buffer->size, true);
+ return tpm2_util_hexdump(buffer->buffer, buffer->size);
}
/**
@@ -216,18 +201,6 @@ static inline void tpm2_util_print_tpm2b(TPM2B *buffer) {
bool tpm2_util_print_tpm2b_file(FILE *fd);
/**
- * Copies a tpm2b from dest to src and clears dest if src is NULL.
- * If src is NULL, it is a NOP.
- * @param dest
- * The destination TPM2B
- * @param src
- * The source TPM2B
- * @return
- * The number of bytes copied.
- */
-UINT16 tpm2_util_copy_tpm2b(TPM2B *dest, TPM2B *src);
-
-/**
* Checks if the host is big endian
* @return
* True of the host is big endian false otherwise.
diff --git a/TPM2-Plugin/lib/tpm2_alg_util.c b/TPM2-Plugin/lib/tpm2_alg_util.c
index 975f4ae..3683b6e 100644
--- a/TPM2-Plugin/lib/tpm2_alg_util.c
+++ b/TPM2-Plugin/lib/tpm2_alg_util.c
@@ -32,7 +32,7 @@
#include <stdlib.h>
#include <string.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#include "files.h"
#include "log.h"
diff --git a/TPM2-Plugin/lib/tpm2_attr_util.c b/TPM2-Plugin/lib/tpm2_attr_util.c
index 03ce2d5..b21141d 100644
--- a/TPM2-Plugin/lib/tpm2_attr_util.c
+++ b/TPM2-Plugin/lib/tpm2_attr_util.c
@@ -32,7 +32,7 @@
#include <stdlib.h>
#include <string.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#include "log.h"
#include "tpm2_attr_util.h"
@@ -66,147 +66,147 @@ struct dispatch_table {
static bool authread(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_AUTHREAD;
+ *nv |= TPMA_NV_AUTHREAD;
return true;
}
static bool authwrite(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_AUTHWRITE;
+ *nv |= TPMA_NV_AUTHWRITE;
return true;
}
static bool clear_stclear(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_CLEAR_STCLEAR;
+ *nv |= TPMA_NV_CLEAR_STCLEAR;
return true;
}
static bool globallock(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_GLOBALLOCK;
+ *nv |= TPMA_NV_GLOBALLOCK;
return true;
}
static bool no_da(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_NO_DA;
+ *nv |= TPMA_NV_NO_DA;
return true;
}
static bool orderly(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_ORDERLY;
+ *nv |= TPMA_NV_ORDERLY;
return true;
}
static bool ownerread(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_OWNERREAD;
+ *nv |= TPMA_NV_OWNERREAD;
return true;
}
static bool ownerwrite(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_OWNERWRITE;
+ *nv |= TPMA_NV_OWNERWRITE;
return true;
}
static bool platformcreate(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_PLATFORMCREATE;
+ *nv |= TPMA_NV_PLATFORMCREATE;
return true;
}
static bool policyread(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_POLICYREAD;
+ *nv |= TPMA_NV_POLICYREAD;
return true;
}
static bool policywrite(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_POLICYWRITE;
+ *nv |= TPMA_NV_POLICYWRITE;
return true;
}
static bool policydelete(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_POLICY_DELETE;
+ *nv |= TPMA_NV_POLICY_DELETE;
return true;
}
static bool ppread(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_PPREAD;
+ *nv |= TPMA_NV_PPREAD;
return true;
}
static bool ppwrite(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_PPWRITE;
+ *nv |= TPMA_NV_PPWRITE;
return true;
}
static bool readlocked(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_READLOCKED;
+ *nv |= TPMA_NV_READLOCKED;
return true;
}
static bool read_stclear(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_READ_STCLEAR;
+ *nv |= TPMA_NV_READ_STCLEAR;
return true;
}
static bool writeall(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_WRITEALL;
+ *nv |= TPMA_NV_WRITEALL;
return true;
}
static bool writedefine(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_WRITEDEFINE;
+ *nv |= TPMA_NV_WRITEDEFINE;
return true;
}
static bool writelocked(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_WRITELOCKED;
+ *nv |= TPMA_NV_WRITELOCKED;
return true;
}
static bool write_stclear(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_WRITE_STCLEAR;
+ *nv |= TPMA_NV_WRITE_STCLEAR;
return true;
}
static bool written(TPMA_NV *nv, char *arg) {
UNUSED(arg);
- *nv |= TPMA_NV_TPMA_NV_WRITTEN;
+ *nv |= TPMA_NV_WRITTEN;
return true;
}
@@ -226,7 +226,7 @@ static bool nt(TPMA_NV *nv, char *arg) {
return false;
}
- *nv &= ~TPMA_NV_TPM2_NT;
+ *nv &= ~TPMA_NV_TPM2_NT_MASK;
*nv |= value << 4;
return true;
}
@@ -348,7 +348,7 @@ static bool decrypt(TPMA_OBJECT *obj, char *arg) {
static bool sign(TPMA_OBJECT *obj, char *arg) {
UNUSED(arg);
- *obj |= TPMA_OBJECT_SIGN;
+ *obj |= TPMA_OBJECT_SIGN_ENCRYPT;
return true;
}
diff --git a/TPM2-Plugin/lib/tpm2_convert.c b/TPM2-Plugin/lib/tpm2_convert.c
new file mode 100644
index 0000000..9b09c81
--- /dev/null
+++ b/TPM2-Plugin/lib/tpm2_convert.c
@@ -0,0 +1,216 @@
+//**********************************************************************;
+// Copyright (c) 2017, SUSE Linux GmbH
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of Intel Corporation nor the names of its contributors
+// may be used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+//**********************************************************************;
+
+#include <string.h>
+#include <errno.h>
+
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+
+#include "files.h"
+#include "log.h"
+#include "tpm2_alg_util.h"
+#include "tpm2_convert.h"
+#include "tpm2_util.h"
+
+static bool tpm2_convert_pubkey_ssl(TPMT_PUBLIC *public, tpm2_convert_pubkey_fmt format, const char *path);
+
+tpm2_convert_pubkey_fmt tpm2_convert_pubkey_fmt_from_optarg(const char *label) {
+ if (strcasecmp(label, "der") == 0) {
+ return pubkey_format_der;
+ }
+ else if (strcasecmp(label, "pem") == 0) {
+ return pubkey_format_pem;
+ }
+ else if (strcasecmp(label, "tss") == 0) {
+ return pubkey_format_tss;
+ }
+
+ LOG_ERR("Invalid public key output format '%s' specified", label);
+
+ return pubkey_format_err;
+}
+
+tpm2_convert_sig_fmt tpm2_convert_sig_fmt_from_optarg(const char *label) {
+ if (strcasecmp(label, "tss") == 0) {
+ return signature_format_tss;
+ }
+ else if (strcasecmp(label, "plain") == 0) {
+ return signature_format_plain;
+ }
+
+ LOG_ERR("Invalid signature output format '%s' specified", label);
+
+ return signature_format_err;
+}
+
+static void print_ssl_error(const char *failed_action) {
+ char errstr[256] = {0};
+ unsigned long errnum = ERR_get_error();
+
+ ERR_error_string_n(errnum, errstr, sizeof(errstr));
+ LOG_ERR("%s: %s", failed_action, errstr);
+}
+
+bool tpm2_convert_pubkey_save(TPM2B_PUBLIC *public, tpm2_convert_pubkey_fmt format, const char *path) {
+
+ if (format == pubkey_format_der || format == pubkey_format_pem) {
+ return tpm2_convert_pubkey_ssl(&public->publicArea, format, path);
+ }
+ else if (format == pubkey_format_tss) {
+ return files_save_public(public, path);
+ }
+
+ LOG_ERR("Unsupported public key output format.");
+ return false;
+}
+
+static bool tpm2_convert_pubkey_ssl(TPMT_PUBLIC *public, tpm2_convert_pubkey_fmt format, const char *path) {
+ bool ret = false;
+ FILE *fp = NULL;
+ RSA *ssl_rsa_key = NULL;
+ BIGNUM *e = NULL, *n = NULL;
+
+ // need this before the first SSL call for getting human readable error
+ // strings in print_ssl_error()
+ ERR_load_crypto_strings();
+
+ if (public->type != TPM2_ALG_RSA) {
+ LOG_ERR("Unsupported key type for requested output format. Only RSA is supported.");
+ goto error;
+ }
+
+ UINT32 exponent = (public->parameters).rsaDetail.exponent;
+ if (exponent == 0) {
+ exponent = 0x10001;
+ }
+
+ // OpenSSL expects this in network byte order
+ exponent = tpm2_util_hton_32(exponent);
+ ssl_rsa_key = RSA_new();
+ if (!ssl_rsa_key) {
+ print_ssl_error("Failed to allocate OpenSSL RSA structure");
+ goto error;
+ }
+
+ e = BN_bin2bn((void*)&exponent, sizeof(exponent), NULL);
+ n = BN_bin2bn(public->unique.rsa.buffer, public->unique.rsa.size,
+ NULL);
+
+ if (!n || !e) {
+ print_ssl_error("Failed to convert data to SSL internal format");
+ goto error;
+ }
+
+#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER) /* OpenSSL 1.1.0 */
+ ssl_rsa_key->e = e;
+ ssl_rsa_key->n = n;
+#else
+ if (!RSA_set0_key(ssl_rsa_key, n, e, NULL)) {
+ print_ssl_error("Failed to set RSA modulus and exponent components");
+ goto error;
+ }
+#endif
+
+ /* modulus and exponent components are now owned by the RSA struct */
+ n = e = NULL;
+
+ fp = fopen(path, "wb");
+ if (!fp) {
+ LOG_ERR("Failed to open public key output file '%s': %s",
+ path, strerror(errno));
+ goto error;
+ }
+
+ int ssl_res = 0;
+
+ switch(format) {
+ case pubkey_format_pem:
+ ssl_res = PEM_write_RSA_PUBKEY(fp, ssl_rsa_key);
+ break;
+ case pubkey_format_der:
+ ssl_res = i2d_RSA_PUBKEY_fp(fp, ssl_rsa_key);
+ break;
+ default:
+ LOG_ERR("Invalid OpenSSL target format %d encountered", format);
+ goto error;
+ }
+
+ if (ssl_res <= 0) {
+ print_ssl_error("OpenSSL public key conversion failed");
+ goto error;
+ }
+
+ ret = true;
+
+error:
+ if (fp) {
+ fclose(fp);
+ }
+ if (n) {
+ BN_free(n);
+ }
+ if (e) {
+ BN_free(e);
+ }
+ if (ssl_rsa_key) {
+ RSA_free(ssl_rsa_key);
+ }
+ ERR_free_strings();
+
+ return ret;
+}
+
+bool tpm2_convert_sig(TPMT_SIGNATURE *signature, tpm2_convert_sig_fmt format, const char *path) {
+
+ switch(format) {
+ case signature_format_tss:
+ return files_save_signature(signature, path);
+ case signature_format_plain: {
+ UINT8 *buffer;
+ UINT16 size;
+
+ buffer = tpm2_extract_plain_signature(&size, signature);
+ if (buffer == NULL) {
+ return false;
+ }
+
+ bool ret = files_save_bytes_to_file(path, buffer, size);
+ free(buffer);
+ return ret;
+ }
+ default:
+ LOG_ERR("Unsupported signature output format.");
+ return false;
+ }
+}
diff --git a/TPM2-Plugin/lib/tpm2_error.c b/TPM2-Plugin/lib/tpm2_error.c
index 7bc024d..32eeb41 100644
--- a/TPM2-Plugin/lib/tpm2_error.c
+++ b/TPM2-Plugin/lib/tpm2_error.c
@@ -28,8 +28,9 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
+#include <string.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#include "tpm2_error.h"
#include "tpm2_util.h"
diff --git a/TPM2-Plugin/lib/tpm2_hash.c b/TPM2-Plugin/lib/tpm2_hash.c
index ecf3a72..5ea7400 100644
--- a/TPM2-Plugin/lib/tpm2_hash.c
+++ b/TPM2-Plugin/lib/tpm2_hash.c
@@ -31,7 +31,7 @@
#include <errno.h>
#include <string.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#include "log.h"
#include "files.h"
diff --git a/TPM2-Plugin/lib/tpm2_plugin_api.c b/TPM2-Plugin/lib/tpm2_plugin_api.c
index adc8cf7..7e9a7a8 100644
--- a/TPM2-Plugin/lib/tpm2_plugin_api.c
+++ b/TPM2-Plugin/lib/tpm2_plugin_api.c
@@ -29,15 +29,21 @@
// THE POSSIBILITY OF SUCH DAMAGE.
//**********************************************************************;
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#include <stdbool.h>
#include <unistd.h>
#include "tpm2_plugin_api.h"
-#include "log.h"
+#include "tpm2_convert.h"
#include "tpm2_tcti_ldr.h"
+#include "tpm2_tool.h"
+#include "tpm2_hash.h"
+#include "tpm2_alg_util.h"
+#include "log.h"
+#include "files.h"
+bool output_enabled = true;
-const char *tcti_path="libtcti-device.so";
+const char *tcti_path="libtss2-tcti-device.so";
static void tcti_teardown (TSS2_TCTI_CONTEXT *tcti_context)
{
@@ -68,15 +74,18 @@ static void sapi_teardown_full (TSS2_SYS_CONTEXT *sapi_context)
tcti_teardown (tcti_context);
}
+#define SUPPORTED_ABI_VERSION \
+{ \
+ .tssCreator = 1, \
+ .tssFamily = 2, \
+ .tssLevel = 1, \
+ .tssVersion = 108, \
+}
+
static TSS2_SYS_CONTEXT* sapi_ctx_init(TSS2_TCTI_CONTEXT *tcti_ctx)
{
- TSS2_ABI_VERSION abi_version = {
- .tssCreator = TSSWG_INTEROP,
- .tssFamily = TSS_SAPI_FIRST_FAMILY,
- .tssLevel = TSS_SAPI_FIRST_LEVEL,
- .tssVersion = TSS_SAPI_FIRST_VERSION,
- };
+ TSS2_ABI_VERSION abi_version = SUPPORTED_ABI_VERSION;
size_t size = Tss2_Sys_GetContextSize(0);
TSS2_SYS_CONTEXT *sapi_ctx = (TSS2_SYS_CONTEXT*) calloc(1, size);
@@ -95,22 +104,325 @@ static TSS2_SYS_CONTEXT* sapi_ctx_init(TSS2_TCTI_CONTEXT *tcti_ctx)
return sapi_ctx;
}
-int tpm2_rsa_sign_init(
+
+
+int tpm2_plugin_init()
+{
+ printf("Init API done for TPM plugin ! \n");
+ return 0;
+}
+
+int tpm2_plugin_uninit()
+{
+ printf("UnInit API done for TPM plugin ! \n");
+ return 0;
+}
+
+int tpm2_plugin_activate(SSHSM_HW_PLUGIN_ACTIVATE_IN_INFO_t *activate_in_info)
+{
+
+ printf("Activate API done for TPM plugin ! \n");
+ return 0;
+
+}
+
+TPM2_HANDLE handle_load;
+
+typedef struct tpm_load_ctx tpm_load_ctx;
+struct tpm_load_ctx {
+ TPMS_AUTH_COMMAND session_data;
+ TPMI_DH_OBJECT parent_handle;
+ TPM2B_PUBLIC in_public;
+ TPM2B_PRIVATE in_private;
+ char *out_file;
+ char *context_file;
+ char *context_parent_file;
+ struct {
+ UINT8 H : 1;
+ UINT8 u : 1;
+ UINT8 r : 1;
+ UINT8 c : 1;
+ UINT8 C : 1;
+ } flags;
+};
+
+static tpm_load_ctx ctx_load = {
+ .session_data = {
+ .sessionHandle = TPM2_RS_PW,
+ .nonce = TPM2B_EMPTY_INIT,
+ .hmac = TPM2B_EMPTY_INIT,
+ .sessionAttributes = 0
+ }
+};
+
+int load (TSS2_SYS_CONTEXT *sapi_context) {
+ UINT32 rval;
+ TSS2L_SYS_AUTH_COMMAND sessionsData;
+ TSS2L_SYS_AUTH_RESPONSE sessionsDataOut;
+
+ TPM2B_NAME nameExt = TPM2B_TYPE_INIT(TPM2B_NAME, name);
+
+ sessionsData.count = 1;
+ sessionsData.auths[0] = ctx_load.session_data;
+
+ rval = TSS2_RETRY_EXP(Tss2_Sys_Load(sapi_context,
+ ctx_load.parent_handle,
+ &sessionsData,
+ &ctx_load.in_private,
+ &ctx_load.in_public,
+ &handle_load,
+ &nameExt,
+ &sessionsDataOut));
+ if(rval != TPM2_RC_SUCCESS)
+ {
+ LOG_PERR(Tss2_Sys_Load, rval);
+ return -1;
+ }
+ tpm2_tool_output("handle_load: 0x%08x\n", handle_load);
+
+ if (ctx_load.out_file) {
+ if(!files_save_bytes_to_file(ctx_load.out_file, nameExt.name, nameExt.size)) {
+ return -2;
+ }
+ }
+
+ return 0;
+}
+
+int tpm2_tool_load_key(TSS2_SYS_CONTEXT *sapi_context)
+{
+
+ int returnVal = 0;
+
+ if ((!ctx_load.flags.H && !ctx_load.flags.c) || (!ctx_load.flags.u || !ctx_load.flags.r)) {
+ LOG_ERR("Expected options (H or c) and u and r");
+ return 1;
+ }
+
+ if(ctx_load.flags.c) {
+ returnVal = files_load_tpm_context_from_path(sapi_context,
+ &ctx_load.parent_handle,
+ ctx_load.context_parent_file) != true;
+ if (returnVal) {
+ return 1;
+ }
+ }
+
+ returnVal = load(sapi_context);
+ if (returnVal) {
+ return 1;
+ }
+
+ if (ctx_load.flags.C) {
+ returnVal = files_save_tpm_context_to_path (sapi_context,
+ handle_load,
+ ctx_load.context_file) != true;
+ if (returnVal) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int tpm2_plugin_load_key(
+ SSHSM_HW_PLUGIN_LOAD_KEY_IN_INFO_t *loadkey_in_info,
+ void **keyHandle
+ )
+{
+ int ret = 1;
+ TSS2_TCTI_CONTEXT *tcti;
+ tcti = tpm2_tcti_ldr_load(tcti_path, NULL);
+ if (!tcti) {
+ LOG_ERR("Could not load tcti, got: \"%s\"", tcti_path);
+ return -1;
+ }
+
+ TSS2_SYS_CONTEXT *sapi_context = NULL;
+ if (tcti) {
+ sapi_context = sapi_ctx_init(tcti);
+ if (!sapi_context) {
+ goto free_tcti;
+ }
+ }
+
+ ret = tpm2_tool_load_key(sapi_context);
+ if (ret != 0) {
+ LOG_ERR("Unable to run tpm2_tool_iload_key");
+ sapi_teardown_full(sapi_context);
+
+free_tcti:
+ tpm2_tcti_ldr_unload();
+ return ret;
+ }
+
+ printf("Load key API done for TPM plugin ! \n");
+ return 0;
+
+}
+
+typedef struct tpm_sign_ctx tpm_sign_ctx;
+struct tpm_sign_ctx {
+ TPMT_TK_HASHCHECK validation;
+ TPMS_AUTH_COMMAND sessionData;
+ TPMI_DH_OBJECT keyHandle;
+ TPMI_ALG_HASH halg;
+ TPM2B_DIGEST digest;
+ char *outFilePath;
+ BYTE *msg;
+ UINT16 length;
+ char *contextKeyFile;
+ char *inMsgFileName;
+ tpm2_convert_sig_fmt sig_format;
+ struct {
+ UINT16 k : 1;
+ UINT16 P : 1;
+ UINT16 g : 1;
+ UINT16 m : 1;
+ UINT16 t : 1;
+ UINT16 s : 1;
+ UINT16 c : 1;
+ UINT16 f : 1;
+ UINT16 D : 1;
+ } flags;
+};
+
+tpm_sign_ctx ctx_sign = {
+ .msg = NULL,
+ .sessionData = TPMS_AUTH_COMMAND_INIT(TPM2_RS_PW),
+ .halg = TPM2_ALG_SHA1,
+ .digest = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer),
+};
+
+
+int tpm2_plugin_rsa_sign_init(
unsigned long mechanish,
void *param,
size_t len,
void *ctx)
{
- printf("executing tpm2_rsa_sign_init in tpm2_plugin... \n");
+ printf("rsa_sign_init API done for tpm2_plugin... \n");
return 0;
}
+static bool init_sign(TSS2_SYS_CONTEXT *sapi_context) {
+
+ if (!((ctx_sign.flags.k || ctx_sign.flags.c) && (ctx_sign.flags.m || ctx_sign.flags.D) && ctx_sign.flags.s)) {
+ LOG_ERR("Expected options (k or c) and (m or D) and s");
+ return false;
+ }
+
+ if (ctx_sign.flags.D && (ctx_sign.flags.t || ctx_sign.flags.m)) {
+ LOG_WARN("Option D provided, options m and t are ignored.");
+ }
+
+ if (ctx_sign.flags.D || !ctx_sign.flags.t) {
+ ctx_sign.validation.tag = TPM2_ST_HASHCHECK;
+ ctx_sign.validation.hierarchy = TPM2_RH_NULL;
+ memset(&ctx_sign.validation.digest, 0, sizeof(ctx_sign.validation.digest));
+ }
+
+ /*
+ * load tpm context from a file if -c is provided
+ */
+ if (ctx_sign.flags.c) {
+ bool result = files_load_tpm_context_from_path(sapi_context, &ctx_sign.keyHandle,
+ ctx_sign.contextKeyFile);
+ if (!result) {
+ return false;
+ }
+ }
+
+ /*
+ * Process the msg file if needed
+ */
+ if (ctx_sign.flags.m && !ctx_sign.flags.D) {
+ unsigned long file_size;
+ bool result = files_get_file_size_path(ctx_sign.inMsgFileName, &file_size);
+ if (!result) {
+ return false;
+ }
+ if (file_size == 0) {
+ LOG_ERR("The message file \"%s\" is empty!", ctx_sign.inMsgFileName);
+ return false;
+ }
+
+ if (file_size > UINT16_MAX) {
+ LOG_ERR(
+ "The message file \"%s\" is too large, got: %lu bytes, expected less than: %u bytes!",
+ ctx_sign.inMsgFileName, file_size, UINT16_MAX + 1);
+ return false;
+ }
+
+ ctx_sign.msg = (BYTE*) calloc(required_argument, file_size);
+ if (!ctx_sign.msg) {
+ LOG_ERR("oom");
+ return false;
+ }
+
+ ctx_sign.length = file_size;
+ result = files_load_bytes_from_path(ctx_sign.inMsgFileName, ctx_sign.msg, &ctx_sign.length);
+ if (!result) {
+ free(ctx_sign.msg);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+static bool sign_and_save(TSS2_SYS_CONTEXT *sapi_context) {
+
+ TPMT_SIG_SCHEME in_scheme;
+ TPMT_SIGNATURE signature;
+
+ TSS2L_SYS_AUTH_COMMAND sessions_data = { 1, { ctx_sign.sessionData }};
+ TSS2L_SYS_AUTH_RESPONSE sessions_data_out;
+
+ if (!ctx_sign.flags.D) {
+ bool res = tpm2_hash_compute_data(sapi_context, ctx_sign.halg, TPM2_RH_NULL,
+ ctx_sign.msg, ctx_sign.length, &ctx_sign.digest, NULL);
+ if (!res) {
+ LOG_ERR("Compute message hash failed!");
+ return false;
+ }
+ }
+
+ bool result = get_signature_scheme(sapi_context, ctx_sign.keyHandle, ctx_sign.halg, &in_scheme);
+ if (!result) {
+ return false;
+ }
+
+ TSS2_RC rval = TSS2_RETRY_EXP(Tss2_Sys_Sign(sapi_context, ctx_sign.keyHandle,
+ &sessions_data, &ctx_sign.digest, &in_scheme, &ctx_sign.validation, &signature,
+ &sessions_data_out));
+ if (rval != TPM2_RC_SUCCESS) {
+ LOG_PERR(Tss2_Sys_Sign, rval);
+ return false;
+ }
+
+ return tpm2_convert_sig(&signature, ctx_sign.sig_format, ctx_sign.outFilePath);
+}
+
+
int tpm2_tool_sign(TSS2_SYS_CONTEXT *sapi_context)
{
- return 0;
+
+ bool result = init_sign(sapi_context);
+ if (!result) {
+ return 1;
+ }
+
+ result = sign_and_save(sapi_context);
+
+ free(ctx_sign.msg);
+
+ return result != true;
}
-int tpm2_rsa_sign(
+
+int tpm2_plugin_rsa_sign(
void *ctx,
unsigned char *msg,
int msg_len,
@@ -141,7 +453,8 @@ int tpm2_rsa_sign(
free_tcti:
tpm2_tcti_ldr_unload();
return ret;
-}
+ }
+ printf("rsa_sign API done for tpm2_plugin... \n");
}
int tpm2_rsa_create_object(
diff --git a/TPM2-Plugin/lib/tpm2_plugin_init.c b/TPM2-Plugin/lib/tpm2_plugin_init.c
index 5ef0fce..d73b230 100644
--- a/TPM2-Plugin/lib/tpm2_plugin_init.c
+++ b/TPM2-Plugin/lib/tpm2_plugin_init.c
@@ -35,31 +35,17 @@
#include "tpm2_plugin_api.h"
-int __plugin_init(char* configPath)
-{
-// if tpm_plugin, do this
- printf("Init module done for TPM plug-in mode ! \n");
-// if SGX_plugin, do this
-
- return 0;
-}
-
-int __plugin_finialize()
-{
-// if tpm_plugin, do this
- printf("Finalize module done for SW mode ! \n");
-// if SGX_plugin, do this
-
- return 0;
-}
int __plugin_functions_mapping(plugin_register *plugin_fp)
{
printf("%s(): Assigning Function pointers for TPM (dTPM or PTT) mode \n", __func__);
- plugin_fp->cb_crypto_rsa_decrypt_init = NULL;
+ plugin_fp->cb_crypto_hw_plugin_init = &tpm2_plugin_init;
+ plugin_fp->cb_crypto_hw_plugin_uninit = &tpm2_plugin_uninit;
+ plugin_fp->cb_crypto_hw_plugin_activate = &tpm2_plugin_activate;
+ plugin_fp->cb_crypto_hw_plugin_load_key = &tpm2_plugin_load_key;
plugin_fp->cb_crypto_rsa_decrypt = NULL;
- plugin_fp->cb_crypto_rsa_sign_init = &tpm2_rsa_sign_init;
- plugin_fp->cb_crypto_rsa_sign = &tpm2_rsa_sign;
+ plugin_fp->cb_crypto_rsa_sign_init = &tpm2_plugin_rsa_sign_init;
+ plugin_fp->cb_crypto_rsa_sign = &tpm2_plugin_rsa_sign;
plugin_fp->cb_crypto_rsa_sign_update = NULL;
plugin_fp->cb_crypto_rsa_sign_final = NULL;
plugin_fp->cb_crypto_ecdsa_sign = NULL;
diff --git a/TPM2-Plugin/lib/tpm2_tcti_ldr.c b/TPM2-Plugin/lib/tpm2_tcti_ldr.c
index 9f25188..5b827a9 100644
--- a/TPM2-Plugin/lib/tpm2_tcti_ldr.c
+++ b/TPM2-Plugin/lib/tpm2_tcti_ldr.c
@@ -30,7 +30,7 @@
#include <stdio.h>
#include <dlfcn.h>
-#include <sapi/tpm20.h>
+#include <tss2/tss2_sys.h>
#include "log.h"
#include "tpm2_tcti_ldr.h"
@@ -52,6 +52,19 @@ const TSS2_TCTI_INFO *tpm2_tcti_ldr_getinfo(void) {
return info;
}
+bool tpm2_tcti_ldr_is_tcti_present(const char *name) {
+
+ char path[PATH_MAX];
+ snprintf(path, sizeof(path), "libtss2-tcti-%s.so", name);
+
+ void *handle = dlopen (path, RTLD_LAZY);
+ if (handle) {
+ dlclose(handle);
+ }
+
+ return handle != NULL;
+}
+
TSS2_TCTI_CONTEXT *tpm2_tcti_ldr_load(const char *path, const char *opts) {
TSS2_TCTI_CONTEXT *tcti_ctx = NULL;
@@ -63,13 +76,13 @@ TSS2_TCTI_CONTEXT *tpm2_tcti_ldr_load(const char *path, const char *opts) {
/*
* Try what they gave us, if it doesn't load up, try
- * libtcti-xxx.so replacing xxx with what they gave us.
+ * libtss2-tcti-xxx.so replacing xxx with what they gave us.
*/
handle = dlopen (path, RTLD_LAZY);
if (!handle) {
char buf[PATH_MAX];
- size_t size = snprintf(buf, sizeof(buf), "libtcti-%s.so", path);
+ size_t size = snprintf(buf, sizeof(buf), "libtss2-tcti-%s.so", path);
if (size >= sizeof(buf)) {
LOG_ERR("Truncated friendly name conversion, got: \"%s\", made: \"%s\"",
path, buf);
diff --git a/TPM2-Plugin/lib/tpm2_util.c b/TPM2-Plugin/lib/tpm2_util.c
index 7a42df7..c0a6cc4 100644
--- a/TPM2-Plugin/lib/tpm2_util.c
+++ b/TPM2-Plugin/lib/tpm2_util.c
@@ -31,13 +31,16 @@
#include <ctype.h>
#include <errno.h>
#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
#include "log.h"
#include "files.h"
#include "tpm2_alg_util.h"
#include "tpm2_attr_util.h"
+#include "tpm2_tool.h"
#include "tpm2_util.h"
-bool output_enabled;
+
bool tpm2_util_concat_buffer(TPM2B_MAX_BUFFER *result, TPM2B *append) {
if (!result || !append) {
@@ -131,45 +134,19 @@ int tpm2_util_hex_to_byte_structure(const char *inStr, UINT16 *byteLength,
return 0;
}
-void tpm2_util_hexdump(const BYTE *data, size_t len, bool plain) {
+void tpm2_util_hexdump(const BYTE *data, size_t len) {
if (!output_enabled) {
return;
}
- if (plain) {
- size_t i;
- for (i=0; i < len; i++) {
- printf("%02x", data[i]);
- }
- return;
- }
-
size_t i;
- size_t j;
- for (i = 0; i < len; i += 16) {
- printf("%06zx: ", i);
-
- for (j = 0; j < 16; j++) {
- if (i + j < len) {
- printf("%02x ", data[i + j]);
- } else {
- printf(" ");
- }
- }
-
- printf(" ");
-
- for (j = 0; j < 16; j++) {
- if (i + j < len) {
- printf("%c", isprint(data[i + j]) ? data[i + j] : '.');
- }
- }
- printf("\n");
+ for (i=0; i < len; i++) {
+ printf("%02x", data[i]);
}
}
-bool tpm2_util_hexdump_file(FILE *fd, size_t len, bool plain) {
+bool tpm2_util_hexdump_file(FILE *fd, size_t len) {
BYTE* buff = (BYTE*)malloc(len);
if (!buff) {
LOG_ERR("malloc() failed");
@@ -183,7 +160,7 @@ bool tpm2_util_hexdump_file(FILE *fd, size_t len, bool plain) {
return false;
}
- tpm2_util_hexdump(buff, len, plain);
+ tpm2_util_hexdump(buff, len);
free(buff);
return true;
@@ -197,29 +174,7 @@ bool tpm2_util_print_tpm2b_file(FILE *fd)
LOG_ERR("File read failed");
return false;
}
- return tpm2_util_hexdump_file(fd, len, true);
-}
-
-/* TODO OPTIMIZE ME */
-UINT16 tpm2_util_copy_tpm2b(TPM2B *dest, TPM2B *src) {
- int i;
- UINT16 rval = 0;
-
- if (dest != 0) {
- if (src == 0) {
- dest->size = 0;
- rval = 0;
- } else {
- dest->size = src->size;
- for (i = 0; i < src->size; i++)
- dest->buffer[i] = src->buffer[i];
- rval = (sizeof(UINT16) + src->size);
- }
- } else {
- rval = 0;
- }
-
- return rval;
+ return tpm2_util_hexdump_file(fd, len);
}
bool tpm2_util_is_big_endian(void) {
@@ -386,7 +341,7 @@ void tpm2_util_public_to_yaml(TPM2B_PUBLIC *public) {
if (public->publicArea.authPolicy.size) {
tpm2_tool_output("authorization policy: ");
tpm2_util_hexdump(public->publicArea.authPolicy.buffer,
- public->publicArea.authPolicy.size, true);
+ public->publicArea.authPolicy.size);
tpm2_tool_output("\n");
}
}