swtpm: Implement --print-info to run TPMLIB_GetInfo with flags

Implement --print-info that takes a number as argument and uses this number
as flags to call TPMLIB_GetInfo with. Display the JSON string and exit.

Extend the man page and update other parts where swtpm_ioctl is not necessary
anymore to use.

Extend a test case to also check that swtpm now returns the same result as
swtpm_ioctl does.

Append cmdarg-print-info to printed out capabilties. Adjust test cases.
(Expect 'profiles' to always be part of capabilties JSON.)

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2024-10-05 14:41:42 -04:00 committed by Stefan Berger
parent 770abf3ff0
commit 3f551e1dc1
8 changed files with 144 additions and 24 deletions

View File

@ -336,7 +336,8 @@ may contain the following:
"rsa-keysize-3072",
"cmdarg-profile",
"cmdarg-print-profiles",
"profile-opt-remove-disabled"
"profile-opt-remove-disabled",
"cmdarg-print-info",
],
"version": "0.7.0"
}
@ -413,18 +414,22 @@ rsa-keysize verbs is shown then only RSA 2048 bit keys are supported.
=item B<cmdarg-profile> (since v0.10)
The option <--profile> is supported to set a profile for a TPM 2 with either
The option I<--profile> is supported to set a profile for a TPM 2 with either
one of the option parameters I<name=>, I<profile=>, I<fd=>, or I<file=>.
=item B<cmdarg-print-profiles> (since v0.10)
The option <--print-profiles> is supported.
The option I<--print-profiles> is supported.
=item B<profile-opt-remove-disabled>
=item B<profile-opt-remove-disabled> (since v0.10)
The I<--profile> option supports the I<remove-disabled> option
parameter.
=item B<cmdard-print-info> (since v0.10)
The option I<--print-info> is supported.
=back
=item B<--print-states> (since v0.7)
@ -528,10 +533,9 @@ require a certain StateFormatLevel, it is recommended to omit the
StateFormatLevel field from the profile.
To see the list of algorithms that are supported and can be disabled, one
may use I<swtpm_ioctl> as follows. A swtpm instance is assumed to be
listening for control commands on port 2322:
may use I<swtpm> as follows.
$ swtpm_ioctl --tcp :2322 --info 0x08 | jq
$ swtpm socket --tpmstate dir=./ --tpm2 --print-info 0x08 | jq
{
"RuntimeAlgorithms": {
"Implemented": "rsa,rsa-min-size=1024,tdes,tdes-min-size=128,sha1,hmac,aes,aes-min-size=128,mgf1,keyedhash,xor,sha256,sha384,sha512,null,rsassa,rsaes,rsapss,oaep,ecdsa,ecdh,ecdaa,sm2,ecschnorr,ecmqv,kdf1-sp800-56a,kdf2,kdf1-sp800-108,ecc,ecc-min-size=192,ecc-nist,ecc-bn,ecc-nist-p192,ecc-nist-p224,ecc-nist-p256,ecc-nist-p384,ecc-nist-p521,ecc-bn-p256,ecc-bn-p638,ecc-sm2-p256,symcipher,camellia,camellia-min-size=128,cmac,ctr,ofb,cbc,cfb,ecb",
@ -543,7 +547,7 @@ listening for control commands on port 2322:
To see the list of supported commands:
$ swtpm_ioctl --tcp :2322 --info 0x10 | jq
$ swtpm socket --tpmstate dir=./ --tpm2 --print-info 0x10 | jq
{
"RuntimeCommands": {
"Implemented": "0x11f-0x122,0x124-0x12e,0x130-0x140,0x142-0x159,0x15b-0x15e,0x160-0x165,0x167-0x174,0x176-0x178,0x17a-0x193,0x197,0x199-0x19c",
@ -555,7 +559,7 @@ To see the list of supported commands:
To see the list of supported attributes:
$swtpm_ioctl --tcp :2322 --info 0x80 | jq
$ swtpm socket --tpmstate dir=./ --tpm2 --print-info 0x80 | jq
{
"RuntimeAttributes": {
"Implemented": "no-unpadded-encryption,no-sha1-signing,no-sha1-verification,no-sha1-hmac-creation,no-sha1-hmac-verification,no-sha1-hmac,fips-host",
@ -570,7 +574,7 @@ entry, which is similar to the "Algorithms" and "Commands" entries.
To see the list of available profiles:
$ swtpm_ioctl --tcp :2322 --info 0x40 | jq
$ swtpm socket --tpm2 --print-info 0x40 | jq
{
"AvailableProfiles": [
{
@ -597,7 +601,8 @@ To see the list of available profiles:
]
}
To see the current active profile:
To see the current active profile querying swtpm listening for control
message on port 2322:
$ swtpm_ioctl --tcp :2322 --info 0x20 | jq
{
@ -619,6 +624,37 @@ none of them relies on disabled commands or algorithms.
Display the profiles supported by libtpms. Use with I<--tpm2> option.
=item B<--print-info> (since v0.10)
Display information about the TPM from libtpms TPMLIB_GetInfo call and exit.
Use the I<--tpm2> option for information about TPM 2. If the I<--tpmstate>
option is also provided then the output will show information about the profile
as well. Note that with this option a TPM state may be created if none existed
before.
The following values can be provided. All of the values can be
or'ed (or added) together to get information about all of them in one query.
=over 2
=item * 0x1: information about the specification the TPM implementation followed
=item * 0x2: information about the manufacturer, model and version of the TPM
=item * 0x4: lists supported RSA and Camellia key sizes
=item * 0x8: describes supported and enabled algorithms
=item * 0x10: describes supported and enabled commands
=item * 0x20: describes the active profile
=item * 0x40: lists all built-in profiles
=item * 0x80: describes supported attributes
=back
=item B<-h|--help>
Display usage info.

View File

@ -270,7 +270,7 @@ int capabilities_print_json(bool cusetpm, TPMLIB_TPMVersion tpmversion)
"{ "
"\"type\": \"swtpm\", "
"\"features\": [ "
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
" ], "
"\"profiles\": { %s}, "
"\"version\": \"" VERSION "\" "
@ -293,6 +293,7 @@ int capabilities_print_json(bool cusetpm, TPMLIB_TPMVersion tpmversion)
true ? ", \"cmdarg-profile\"" : "",
true ? ", \"cmdarg-print-profiles\"" : "",
true ? ", \"profile-opt-remove-disabled\"" : "",
true ? ", \"cmdarg-print-info\"" : "",
profiles ? profiles : ""
);

View File

@ -284,7 +284,9 @@ static const char *usage =
" algorithms first\n"
"--print-profiles\n"
" : print all profiles supported by libtpms\n"
"-h|--help : display this help screen and terminate\n"
"--print-info <info flags>\n"
" : print information about the TPM and profiles and exit\n"
"-h|--help : display this help screen and terminate\n"
"\n";
static TPM_RESULT
@ -1594,6 +1596,7 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
{
#endif
int opt, longindex = 0;
enum TPMLIB_InfoFlags infoflags = 0;
static struct option longopts[] = {
{"maj" , required_argument, 0, 'M'},
{"min" , required_argument, 0, 'm'},
@ -1619,16 +1622,19 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
{"print-states" , no_argument, 0, 'e'},
{"profile" , required_argument, 0, 'I'},
{"print-profiles", no_argument, 0, 'N'},
{"print-info" , required_argument, 0, 'x'},
{NULL , 0 , 0, 0 },
};
struct cuse_info cinfo;
struct cuse_param param = {
.startupType = _TPM_ST_NONE,
};
g_autofree gchar *jsoninfo = NULL;
const char *devname = NULL;
char *cinfo_argv[1] = { 0 };
unsigned int num;
const char *uri = NULL;
char *end_ptr = NULL;
int n, tpmfd;
char path[PATH_MAX];
int ret = 0;
@ -1753,6 +1759,16 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
case 'N': /* --print-profiles */
printprofiles = true;
break;
case 'x': /* --print-info */
errno = 0;
infoflags = strtoul(optarg, &end_ptr, 0);
if (infoflags != (unsigned int)infoflags || errno || end_ptr[0] != '\0') {
logprintf(STDERR_FILENO,
"Cannot parse info value '%s'.\n", optarg);
ret = -1;
goto exit;
}
break;
case 'v': /* version */
fprintf(stdout, "TPM emulator CUSE interface version %d.%d.%d, "
"Copyright (c) 2014-2015 IBM Corp.\n",
@ -1898,7 +1914,7 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
g_mutex_lock(FILE_OPS_LOCK);
if (!need_init_cmd) {
if (!need_init_cmd || (infoflags && tpmstate_get_backend_uri())) {
if (tpm_start(0, tpmversion, g_json_profile, &res) < 0) {
ret = -1;
goto err_unlock;
@ -1907,6 +1923,13 @@ int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *ifac
SWTPM_G_FREE(g_json_profile);
}
if (infoflags) {
/* returns more information with tpmstate active */
jsoninfo = TPMLIB_GetInfo(infoflags);
printf("%s\n", jsoninfo);
goto err_unlock;
}
if (param.startupType != _TPM_ST_NONE) {
if (ptm_send_startup(param.startupType, tpmversion) < 0) {
ret = -1;

View File

@ -205,6 +205,8 @@ static void usage(FILE *file, const char *prgname, const char *iface)
" algorithms first\n"
"--print-profiles\n"
" : print all profiles supported by libtpms\n"
"--print-info <info flags>\n"
" : print information about the TPM and profiles and exit\n"
"-h|--help : display this help screen and terminate\n"
"\n",
prgname, iface);
@ -239,6 +241,7 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
.incoming_migration = false,
.storage_locked = false,
};
g_autofree gchar *jsoninfo = NULL;
struct server *server = NULL;
unsigned long val;
char *end_ptr;
@ -266,6 +269,7 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
bool printstates = false;
bool printprofiles = false;
bool tpm_running = false;
enum TPMLIB_InfoFlags infoflags = 0;
static struct option longopts[] = {
{"daemon" , no_argument, 0, 'd'},
{"help" , no_argument, 0, 'h'},
@ -293,6 +297,7 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
{"print-states", no_argument, 0, 'e'},
{"profile" , required_argument, 0, 'I'},
{"print-profiles", no_argument, 0, 'N'},
{"print-info", required_argument, 0, 'x'},
{NULL , 0 , 0, 0 },
};
@ -447,6 +452,16 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
printprofiles = true;
break;
case 'x': /* --print-info */
errno = 0;
infoflags = strtoul(optarg, &end_ptr, 0);
if (infoflags != (unsigned int)infoflags || errno || end_ptr[0] != '\0') {
logprintf(STDERR_FILENO,
"Cannot parse info value '%s'.\n", optarg);
exit(EXIT_FAILURE);
}
break;
default:
usage(stderr, prgname, iface);
exit(EXIT_FAILURE);
@ -565,7 +580,7 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
if ((rc = tpmlib_register_callbacks(&callbacks)))
goto error_no_tpm;
if (!need_init_cmd) {
if (!need_init_cmd || (infoflags && tpmstate_get_backend_uri())) {
mlp.storage_locked = !mlp.incoming_migration;
if ((rc = tpmlib_start(0, mlp.tpmversion, mlp.storage_locked,
@ -575,6 +590,13 @@ int swtpm_main(int argc, char **argv, const char *prgname, const char *iface)
SWTPM_G_FREE(mlp.json_profile);
}
if (infoflags) {
/* returns more information with tpmstate active */
jsoninfo = TPMLIB_GetInfo(infoflags);
printf("%s\n", jsoninfo);
goto error_no_sighandlers;
}
if (install_sighandlers(notify_fd, sigterm_handler) < 0)
goto error_no_sighandlers;

View File

@ -226,6 +226,8 @@ static void usage(FILE *file, const char *prgname, const char *iface)
" algorithms first\n"
"--print-profiles\n"
" : print all profiles supported by libtpms\n"
"--print-info <info flags>\n"
" : print information about the TPM and profiles and exit\n"
"-h|--help : display this help screen and terminate\n"
"\n",
prgname, iface);
@ -297,6 +299,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i
.incoming_migration = false,
.storage_locked = false,
};
g_autofree gchar *jsoninfo = NULL;
unsigned long val;
char *end_ptr;
char *keydata = NULL;
@ -324,6 +327,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i
bool printstates = false;
bool printprofiles = false;
bool tpm_running = false;
enum TPMLIB_InfoFlags infoflags = 0;
static struct option longopts[] = {
{"daemon" , no_argument, 0, 'd'},
{"help" , no_argument, 0, 'h'},
@ -352,6 +356,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i
{"print-states", no_argument, 0, 'e'},
{"profile" , required_argument, 0, 'I'},
{"print-profiles", no_argument, 0, 'N'},
{"print-info", required_argument, 0, 'x'},
{NULL , 0 , 0, 0 },
};
@ -497,6 +502,18 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i
printprofiles = true;
break;
case 'x': /* --print-info */
errno = 0;
infoflags = strtoul(optarg, &end_ptr, 0);
if (infoflags != (unsigned int)infoflags || errno || end_ptr[0] != '\0') {
logprintf(STDERR_FILENO,
"Cannot parse info value '%s'.\n", optarg);
exit(EXIT_FAILURE);
}
if (mlp.fd < 0)
mlp.fd = open("/dev/zero", O_RDWR);
break;
default:
usage(stderr, prgname, iface);
exit(EXIT_FAILURE);
@ -613,7 +630,7 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i
if ((rc = tpmlib_register_callbacks(&callbacks)))
goto error_no_tpm;
if (!need_init_cmd) {
if (!need_init_cmd || (infoflags && tpmstate_get_backend_uri())) {
mlp.storage_locked = !mlp.incoming_migration;
if ((rc = tpmlib_start(0, mlp.tpmversion, mlp.storage_locked,
@ -623,6 +640,13 @@ int swtpm_chardev_main(int argc, char **argv, const char *prgname, const char *i
SWTPM_G_FREE(mlp.json_profile);
}
if (infoflags) {
/* returns more information with tpmstate active */
jsoninfo = TPMLIB_GetInfo(infoflags);
printf("%s\n", jsoninfo);
goto error_no_sighandlers;
}
if (install_sighandlers(notify_fd, sigterm_handler) < 0)
goto error_no_sighandlers;

View File

@ -29,8 +29,8 @@ exp='\{ "type": "swtpm", '\
'"flags-opt-disable-auto-shutdown", "ctrl-opt-terminate", '${seccomp}'"cmdarg-key-fd", '\
'"cmdarg-pwd-fd", "cmdarg-print-states", "cmdarg-chroot", "cmdarg-migration", '\
'"nvram-backend-dir", "nvram-backend-file", "cmdarg-profile", '\
'"cmdarg-print-profiles", "profile-opt-remove-disabled" \],'\
'( "profiles": \{ \},)? '\
'"cmdarg-print-profiles", "profile-opt-remove-disabled", "cmdarg-print-info" \], '\
'"profiles": \{ \}, '\
'"version": "[^"]*" \}'
if ! [[ ${msg} =~ ${exp} ]]; then
echo "Unexpected response from ${SWTPM_IFACE} TPM to --print-capabilities:"
@ -53,8 +53,8 @@ exp='\{ "type": "swtpm_setup", '\
'"tpm12-not-need-root", "cmdarg-write-ek-cert-files", "cmdarg-create-config-files", '\
'"cmdarg-reconfigure-pcr-banks"'\
'(, "tpm2-rsa-keysize-2048")?(, "tpm2-rsa-keysize-3072")?, "cmdarg-profile", '\
'"cmdarg-profile-remove-disabled" \],'\
'( "profiles": \[ [^]]*\],)? '\
'"cmdarg-profile-remove-disabled" \], '\
'"profiles": \[ [^]]*\], '\
'"version": "[^"]*" \}'
if ! [[ ${msg} =~ ${exp} ]]; then
echo "Unexpected response from ${SWTPM_SETUP} to --print-capabilities:"

View File

@ -31,8 +31,8 @@ exp='\{ "type": "swtpm", '\
'"cmdarg-pwd-fd", "cmdarg-print-states", "cmdarg-chroot", "cmdarg-migration", '\
'"nvram-backend-dir", "nvram-backend-file"'\
'(, "rsa-keysize-1024")?(, "rsa-keysize-2048")?(, "rsa-keysize-3072")?, "cmdarg-profile", '\
'"cmdarg-print-profiles", "profile-opt-remove-disabled" \],'\
'( "profiles": \{ "names": \[ [^]]*\], "algorithms": \{ [^\}]*\}, "commands": \{ [^\}]*\} },)? '\
'"cmdarg-print-profiles", "profile-opt-remove-disabled", "cmdarg-print-info" \], '\
'"profiles": \{ "names": \[ [^]]*\], "algorithms": \{ [^\}]*\}, "commands": \{ [^\}]*\} }, '\
'"version": "[^"]*" \}'
if ! [[ ${msg} =~ ${exp} ]]; then
echo "Unexpected response from ${SWTPM_IFACE} TPM to --print-capabilities:"
@ -54,8 +54,8 @@ exp='\{ "type": "swtpm_setup", '\
'"features": \[( "tpm-1.2",)? "tpm-2.0", "cmdarg-keyfile-fd", "cmdarg-pwdfile-fd", '\
'"tpm12-not-need-root", "cmdarg-write-ek-cert-files", "cmdarg-create-config-files", '\
'"cmdarg-reconfigure-pcr-banks"(, "tpm2-rsa-keysize-2048")?(, "tpm2-rsa-keysize-3072")?, '\
'"cmdarg-profile", "cmdarg-profile-remove-disabled" \],'\
'( "profiles": \[ [^]]*\],)? '\
'"cmdarg-profile", "cmdarg-profile-remove-disabled" \], '\
'"profiles": \[ [^]]*\], '\
'"version": "[^"]*" \}'
if ! [[ ${msg} =~ ${exp} ]]; then
echo "Unexpected response from ${SWTPM_SETUP} to --print-capabilities:"

View File

@ -128,6 +128,20 @@ test_swtpm_setup_profile()
echo "Error: ${SWTPM_INTERFACE} TPM should not be running anymore."
exit 1
fi
# Expecting same results from swtpm directly
if [ -n "${exp_response}" ]; then
response=$(${SWTPM_EXE} socket \
--tpmstate "dir=${workdir}" \
--tpm2 \
--print-info 0x20)
if ! [[ "${response}" =~ ${exp_response} ]]; then
echo "Error: Response does not match expected response regular expression (swtpm)"
echo "Actual : ${response}"
echo "Expected : ${exp_response}"
exit 1
fi
fi
}
# Get available profiles and algorithms that are implemented and those that can be disabled