diff --git a/src/swtpm/capabilities.c b/src/swtpm/capabilities.c index 904e4fb..4c4d7f6 100644 --- a/src/swtpm/capabilities.c +++ b/src/swtpm/capabilities.c @@ -59,10 +59,11 @@ int capabilities_print_json(bool cusetpm) "{ " "\"type\": \"swtpm\", " "\"features\": [ " - "%s%s%s%s" + "%s%s%s%s%s" " ] " "}", !cusetpm ? "\"tpm-send-command-header\", ": "", + !cusetpm ? "\"flags-opt-startup\", " : "", cmdarg_seccomp, true ? "\"cmdarg-key-fd\", " : "", true ? "\"cmdarg-pwd-fd\"" : "" diff --git a/src/swtpm/common.c b/src/swtpm/common.c index 7da4ff8..e8f0586 100644 --- a/src/swtpm/common.c +++ b/src/swtpm/common.c @@ -68,6 +68,7 @@ #include "ctrlchannel.h" #include "server.h" #include "seccomp_profile.h" +#include "tpmlib.h" /* --log %s */ static const OptionDesc logging_opt_desc[] = { @@ -233,6 +234,22 @@ static const OptionDesc flags_opt_desc[] = { .name = "not-need-init", .type = OPT_TYPE_BOOLEAN, }, + { + .name = "startup-none", + .type = OPT_TYPE_BOOLEAN, + }, + { + .name = "startup-clear", + .type = OPT_TYPE_BOOLEAN, + }, + { + .name = "startup-state", + .type = OPT_TYPE_BOOLEAN, + }, + { + .name = "startup-deactivated", + .type = OPT_TYPE_BOOLEAN, + }, END_OPTION_DESC }; @@ -1154,7 +1171,8 @@ int handle_locality_options(char *options, uint32_t *flags) return 0; } -static int parse_flags_options(char *options, bool *need_init_cmd) +static int parse_flags_options(char *options, bool *need_init_cmd, + uint16_t *startupType) { OptionValues *ovs = NULL; char *error = NULL; @@ -1168,6 +1186,18 @@ static int parse_flags_options(char *options, bool *need_init_cmd) if (option_get_bool(ovs, "not-need-init", false)) *need_init_cmd = false; + if (option_get_bool(ovs, "startup-clear", false)) + *startupType = TPM_ST_CLEAR; + else if (option_get_bool(ovs, "startup-state", false)) + *startupType = TPM_ST_STATE; + else if (option_get_bool(ovs, "startup-deactivated", false)) + *startupType = TPM_ST_DEACTIVATED; + else if (option_get_bool(ovs, "startup-none", false)) + *startupType = _TPM_ST_NONE; + + if (*startupType != _TPM_ST_NONE) + *need_init_cmd = false; + option_values_free(ovs); return 0; @@ -1186,12 +1216,13 @@ error: * * Returns 0 on success, -1 on failure. */ -int handle_flags_options(char *options, bool *need_init_cmd) +int handle_flags_options(char *options, bool *need_init_cmd, + uint16_t *startupType) { if (!options) return 0; - if (parse_flags_options(options, need_init_cmd) < 0) + if (parse_flags_options(options, need_init_cmd, startupType) < 0) return -1; return 0; diff --git a/src/swtpm/common.h b/src/swtpm/common.h index 8e69df3..e1c20a3 100644 --- a/src/swtpm/common.h +++ b/src/swtpm/common.h @@ -51,7 +51,8 @@ int handle_ctrlchannel_options(char *options, struct ctrlchannel **cc); struct server; int handle_server_options(char *options, struct server **s); int handle_locality_options(char *options, uint32_t *flags); -int handle_flags_options(char *options, bool *need_init_cmd); +int handle_flags_options(char *options, bool *need_init_cmd, + uint16_t *startupType); #ifdef WITH_SECCOMP int handle_seccomp_options(char *options, unsigned int *seccomp_action); #else diff --git a/src/swtpm/mainloop.c b/src/swtpm/mainloop.c index b91b618..04ffa6a 100644 --- a/src/swtpm/mainloop.c +++ b/src/swtpm/mainloop.c @@ -134,6 +134,22 @@ int mainLoop(struct mainLoopParams *mlp, sockfd = SWTPM_IO_GetSocketFD(); + if (mlp->startupType != _TPM_ST_NONE) { + command_length = tpmlib_create_startup_cmd( + mlp->startupType, + mlp->tpmversion, + command, max_command_length); + if (command_length > 0) + rc = TPMLIB_Process(&rbuffer, &rlength, &rTotal, + command, command_length); + + if (rc || command_length == 0) { + mainloop_terminate = true; + if (rc) + logprintf(STDERR_FILENO, "Could not send Startup: 0x%x\n", rc); + } + } + while (!mainloop_terminate) { while (rc == 0) { diff --git a/src/swtpm/mainloop.h b/src/swtpm/mainloop.h index a3a802b..c006d14 100644 --- a/src/swtpm/mainloop.h +++ b/src/swtpm/mainloop.h @@ -59,6 +59,7 @@ struct mainLoopParams { struct ctrlchannel *cc; uint32_t locality_flags; TPMLIB_TPMVersion tpmversion; + uint16_t startupType; /* use TPM 1.2 types */ }; int mainLoop(struct mainLoopParams *mlp, diff --git a/src/swtpm/swtpm.c b/src/swtpm/swtpm.c index 3ecbb7b..0fc22c4 100644 --- a/src/swtpm/swtpm.c +++ b/src/swtpm/swtpm.c @@ -168,13 +168,14 @@ static void usage(FILE *file, const char *prgname, const char *iface) " can be given with the bindaddr parameter\n" "--server type=unixio[,path=path][,fd=fd][,mode=0...][,uid=uid][,gid=gid]\n" " : Expect UnixIO connections on the given path; if fd is\n" - " provided, packets wil be read from it directly;\n" + " provided, packets will be read from it directly;\n" " mode allows to set the file mode bits of the socket; the\n" " value must be given in octal number format;\n" " uid and gid set the ownership of the Unixio socket's file;\n" - "--flags [not-need-init]\n" + "--flags [not-need-init][,startup-clear|startup-state|startup-deactivated|startup-none]\n" " : not-need-init: commands can be sent without needing to\n" " send an INIT via control channel;\n" + " startup-...: send Startup command with this type;\n" "-r|--runas : change to the given user\n" "--tpm2 : choose TPM2 functionality\n" #ifdef WITH_SECCOMP @@ -214,6 +215,7 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface) .fd = -1, .locality_flags = 0, .tpmversion = TPMLIB_TPM_VERSION_1_2, + .startupType = _TPM_ST_NONE, }; struct server *server = NULL; unsigned long val; @@ -435,7 +437,8 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface) handle_locality_options(localitydata, &mlp.locality_flags) < 0 || handle_tpmstate_options(tpmstatedata) < 0 || handle_seccomp_options(seccompdata, &seccomp_action) < 0 || - handle_flags_options(flagsdata, &need_init_cmd) < 0) { + handle_flags_options(flagsdata, &need_init_cmd, + &mlp.startupType) < 0) { goto exit_failure; } diff --git a/src/swtpm/swtpm_chardev.c b/src/swtpm/swtpm_chardev.c index e44d03b..d824ffd 100644 --- a/src/swtpm/swtpm_chardev.c +++ b/src/swtpm/swtpm_chardev.c @@ -193,10 +193,12 @@ static void usage(FILE *file, const char *prgname, const char *iface) "--locality [reject-locality-4][,allow-set-locality]\n" " : reject-locality-4: reject any command in locality 4\n" " allow-set-locality: accept SetLocality command\n" - "--flags [not-need-init]\n" + "--flags [not-need-init][,startup-clear|startup-state|startup-deactivated|startup-none]\n" " : not-need-init: commands can be sent without needing to\n" " send an INIT via control channel; not needed when using\n" " --vtpm-proxy\n" + " startup-...: send Startup command with this type;\n" + " when --vtpm-proxy is used, startup-clear is used\n" "--tpm2 : choose TPM2 functionality\n" #ifdef WITH_SECCOMP # ifndef SCMP_ACT_LOG @@ -234,6 +236,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i .flags = 0, .locality_flags = 0, .tpmversion = TPMLIB_TPM_VERSION_1_2, + .startupType = _TPM_ST_NONE, }; unsigned long val; char *end_ptr; @@ -423,6 +426,11 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i if (mlp.tpmversion == TPMLIB_TPM_VERSION_2) vtpm_new_dev.flags = VTPM_PROXY_FLAG_TPM2; + /* Will be adjusted for TPM 2; + * handle_flags_options() will cause need_init_cmd = false to be set + */ + mlp.startupType = TPM_ST_CLEAR; + if (mlp.fd >= 0) { logprintf(STDERR_FILENO, "Cannot use vTPM proxy with a provided device.\n"); @@ -483,7 +491,8 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i handle_pid_options(piddata) < 0 || handle_tpmstate_options(tpmstatedata) < 0 || handle_seccomp_options(seccompdata, &seccomp_action) < 0 || - handle_flags_options(flagsdata, &need_init_cmd) < 0) { + handle_flags_options(flagsdata, &need_init_cmd, + &mlp.startupType) < 0) { goto exit_failure; } @@ -513,11 +522,6 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i tpmlib_debug_libtpms_parameters(mlp.tpmversion); -#ifdef WITH_VTPM_PROXY - if (use_vtpm_proxy) - need_init_cmd = false; -#endif - if ((rc = tpmlib_register_callbacks(&callbacks))) goto error_no_tpm; diff --git a/src/swtpm/tpmlib.c b/src/swtpm/tpmlib.c index 83ad052..529b4d2 100644 --- a/src/swtpm/tpmlib.c +++ b/src/swtpm/tpmlib.c @@ -56,6 +56,7 @@ #ifdef WITH_VTPM_PROXY #include "vtpm_proxy.h" #endif +#include "utils.h" /* * convert the blobtype integer into a string that libtpms @@ -380,3 +381,46 @@ off_t tpmlib_handle_tcg_tpm2_cmd_header(const unsigned char *command, return ret; } + +/* + * Create a Startup command with the given startupType for the + * given TPM version. + */ +uint32_t tpmlib_create_startup_cmd(uint16_t startupType, + TPMLIB_TPMVersion tpmversion, + unsigned char *buffer, + uint32_t buffersize) +{ + struct tpm_startup ts; + uint32_t tocopy = min(sizeof(ts), buffersize); + + ts.hdr.size = htobe32(sizeof(ts)); + + switch (tpmversion) { + case TPMLIB_TPM_VERSION_1_2: + ts.hdr.tag = htobe16(TPM_TAG_RQU_COMMAND); + ts.hdr.ordinal = htobe32(TPMLIB_TPM_ORD_Startup); + ts.startupType = htobe16(startupType); + break; + case TPMLIB_TPM_VERSION_2: + ts.hdr.tag = htobe16(TPM2_ST_NO_SESSION); + ts.hdr.ordinal = htobe32(TPMLIB_TPM2_CC_Startup); + switch (startupType) { + case TPM_ST_CLEAR: + ts.startupType = htobe16(TPM2_SU_CLEAR); + break; + case TPM_ST_STATE: + ts.startupType = htobe16(TPM2_SU_STATE); + break; + case TPM_ST_DEACTIVATED: + tocopy = 0; + logprintf(STDERR_FILENO, + "TPM 2 does not support startup deactivated.\n"); + break; + } + break; + } + + memcpy(buffer, &ts, tocopy); + return tocopy; +} diff --git a/src/swtpm/tpmlib.h b/src/swtpm/tpmlib.h index 8947ff0..3086db1 100644 --- a/src/swtpm/tpmlib.h +++ b/src/swtpm/tpmlib.h @@ -73,6 +73,10 @@ TPM_RESULT tpmlib_process(unsigned char **rbuffer, uint32_t *rlength, off_t tpmlib_handle_tcg_tpm2_cmd_header(const unsigned char *command, uint32_t command_length, TPM_MODIFIER_INDICATOR *locality); +uint32_t tpmlib_create_startup_cmd(uint16_t startupType, + TPMLIB_TPMVersion tpmversion, + unsigned char *buffer, + uint32_t buffersize); struct tpm_req_header { uint16_t tag; @@ -96,6 +100,12 @@ struct tpm2_resp_prefix { uint32_t size; /* size of the following TPM response */ } __attribute__((packed)); +/* TPM 1.2 and TPM 2 used the same structured for startup */ +struct tpm_startup { + struct tpm_req_header hdr; + uint16_t startupType; +} __attribute__((packed)); + /* Commands in tcg_tpm2_cmd_header 'cmd' */ #define TPM2_SEND_COMMAND 8 @@ -103,9 +113,19 @@ struct tpm2_resp_prefix { #define TPM2_ST_NO_SESSION 0x8001 #define TPM2_ST_SESSIONS 0x8002 +/* Tags supported by TPM 1.2 */ +#define TPM_TAG_RQU_COMMAND 0x00C1 + /* TPM 1.2 ordinals */ #define TPMLIB_TPM_ORD_TakeOwnership 0x0000000d #define TPMLIB_TPM_ORD_CreateWrapKey 0x0000001f +#define TPMLIB_TPM_ORD_Startup 0x00000099 + +/* TPM 1.2 startup types */ +#define TPM_ST_CLEAR 0x0001 +#define TPM_ST_STATE 0x0002 +#define TPM_ST_DEACTIVATED 0x0003 +#define _TPM_ST_NONE 0x0000 /* do not send Startup */ /* TPM 2 error codes */ #define TPM_RC_INSUFFICIENT 0x09a @@ -114,6 +134,11 @@ struct tpm2_resp_prefix { /* TPM 2 commands */ #define TPMLIB_TPM2_CC_CreatePrimary 0x00000131 +#define TPMLIB_TPM2_CC_Startup 0x00000144 #define TPMLIB_TPM2_CC_Create 0x00000153 +/* TPM 2 startup types */ +#define TPM2_SU_CLEAR 0x0000 +#define TPM2_SU_STATE 0x0001 + #endif /* _SWTPM_TPMLIB_H_ */