swtpm: Implement CMD_GETINFO to retrieve TPM specification info

We quetry the swtpm for TPM specification info that goes into the
certificate for the EK.

Update the test cases that now see more capabilties being returned
by the swtpm.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
Stefan Berger 2018-04-21 21:44:31 -04:00
parent d40700020b
commit 2b8a668dbb
6 changed files with 123 additions and 7 deletions

View File

@ -191,6 +191,30 @@ struct ptm_setbuffersize {
} u;
};
#define PTM_GETINFO_SIZE (3 * 1024)
/*
* PTM_GET_INFO: Get info about the TPM implementation (from libtpms)
*
* This request allows to indirectly call TPMLIB_GetInfo(flags) and
* retrieve information from libtpms.
* Only one transaction is currently necessary for returning results
* to a client. Therefore, totlength and length will be the same if
* offset is 0.
*/
struct ptm_getinfo {
union {
struct {
uint64_t flags;
uint32_t offset; /* offset from where to read */
} req; /* request */
struct {
ptm_res tpm_result;
uint32_t totlength;
uint32_t length;
char buffer[PTM_GETINFO_SIZE];
} resp; /* response */
} u;
};
typedef uint64_t ptm_cap;
typedef struct ptm_est ptm_est;
@ -202,6 +226,7 @@ typedef struct ptm_getstate ptm_getstate;
typedef struct ptm_setstate ptm_setstate;
typedef struct ptm_getconfig ptm_getconfig;
typedef struct ptm_setbuffersize ptm_setbuffersize;
typedef struct ptm_getinfo ptm_getinfo;
/* capability flags returned by PTM_GET_CAPABILITY */
#define PTM_CAP_INIT (1)
@ -218,6 +243,7 @@ typedef struct ptm_setbuffersize ptm_setbuffersize;
#define PTM_CAP_GET_CONFIG (1 << 11)
#define PTM_CAP_SET_DATAFD (1 << 12)
#define PTM_CAP_SET_BUFFERSIZE (1 << 13)
#define PTM_CAP_GET_INFO (1 << 14)
enum {
PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap),
@ -237,6 +263,7 @@ enum {
PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig),
PTM_SET_DATAFD = _IOR('P', 15, ptm_res),
PTM_SET_BUFFERSIZE = _IOWR('P', 16, ptm_setbuffersize),
PTM_GET_INFO = _IOWR('P', 17, ptm_getinfo),
};
/*
@ -267,6 +294,7 @@ enum {
CMD_GET_CONFIG, /* 0x0f */
CMD_SET_DATAFD, /* 0x10 */
CMD_SET_BUFFERSIZE, /* 0x11 */
CMD_GET_INFO, /* 0x12 */
};
#endif /* _TPM_IOCTL_H */

View File

@ -475,11 +475,16 @@ int ctrlchannel_process_fd(int fd,
ptm_setstate *pss;
ptm_loc *pl;
ptm_setbuffersize *psbs;
ptm_getinfo *pgi;
size_t out_len = 0;
TPM_RESULT res;
uint32_t remain;
uint32_t buffersize, maxsize, minsize;
uint64_t info_flags;
uint32_t offset;
char *info_data = NULL;
size_t length;
if (fd < 0)
return -1;
@ -515,7 +520,8 @@ int ctrlchannel_process_fd(int fd,
#ifndef __CYGWIN__
PTM_CAP_SET_DATAFD |
#endif
PTM_CAP_SET_BUFFERSIZE
PTM_CAP_SET_BUFFERSIZE |
PTM_CAP_GET_INFO
);
out_len = sizeof(*ptm_caps);
@ -795,6 +801,37 @@ int ctrlchannel_process_fd(int fd,
break;
case CMD_GET_INFO:
pgi = (ptm_getinfo *)input.body;
if (n < (ssize_t)sizeof(pgi->u.req)) /* rw */
goto err_bad_input;
info_flags = be64toh(pgi->u.req.flags);
info_data = TPMLIB_GetInfo(info_flags);
if (!info_data)
goto err_memory;
offset = be32toh(pgi->u.req.offset);
if (offset >= strlen(info_data)) {
free(info_data);
goto err_bad_input;
}
length = min(strlen(info_data) + 1 - offset,
sizeof(pgi->u.resp.buffer));
pgi = (ptm_getinfo *)&output.body;
pgi->u.resp.tpm_result = htobe32(0);
pgi->u.resp.totlength = htobe32(strlen(info_data) + 1);
pgi->u.resp.length = htobe32(length);
strncpy(pgi->u.resp.buffer, &info_data[offset], length);
free(info_data);
out_len = offsetof(ptm_getinfo, u.resp.buffer) + length;
break;
default:
logprintf(STDERR_FILENO,
"Error: Unknown command: 0x%08x\n", be32toh(input.cmd));
@ -840,6 +877,12 @@ err_io:
goto send_resp;
err_memory:
*res_p = htobe32(TPM_SIZE);
out_len = sizeof(ptm_res);
goto send_resp;
err_socket:
close(fd);

View File

@ -1209,6 +1209,39 @@ static void ptm_ioctl(fuse_req_t req, int cmd, void *arg,
}
break;
case PTM_GET_INFO:
if (out_bufsz != sizeof(ptm_getinfo)) {
struct iovec iov = { arg, sizeof(uint32_t) };
fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
} else {
ptm_getinfo *in_pgi = (ptm_getinfo *)in_buf;
ptm_getinfo out_pgi;
char *info_data;
uint32_t length, offset;
info_data = TPMLIB_GetInfo(in_pgi->u.req.flags);
if (!info_data)
goto error_memory;
offset = in_pgi->u.req.offset;
if (offset >= strlen(info_data)) {
free(info_data);
goto error_bad_input;
}
length = min(strlen(info_data) + 1 - offset,
sizeof(out_pgi.u.resp.buffer));
out_pgi.u.resp.tpm_result = 0;
out_pgi.u.resp.totlength = strlen(info_data) + 1;
out_pgi.u.resp.length = length;
strncpy(out_pgi.u.resp.buffer, &info_data[offset], length);
free(info_data);
fuse_reply_ioctl(req, 0, &out_pgi, sizeof(out_pgi));
}
break;
default:
fuse_reply_err(req, EINVAL);
}
@ -1225,11 +1258,23 @@ cleanup:
return;
error_bad_input:
res = TPM_BAD_PARAMETER;
fuse_reply_ioctl(req, 0, &res, sizeof(res));
goto cleanup;
error_running:
error_not_running:
res = TPM_BAD_ORDINAL;
fuse_reply_ioctl(req, 0, &res, sizeof(res));
goto cleanup;
error_memory:
res = TPM_SIZE;
fuse_reply_ioctl(req, 0, &res, sizeof(res));
goto cleanup;
}

View File

@ -64,7 +64,7 @@ def test_get_caps():
# test get capabilities
# CMD_GET_CAPABILITY = 0x00 00 00 01
cmd_get_caps = bytearray([0x00, 0x00, 0x00, 0x01])
expected_caps = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff])
expected_caps = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff])
def toString(arr):
return ' '.join('{:02x}'.format(x) for x in arr)

View File

@ -58,9 +58,9 @@ PID="$(cat $PID_FILE)"
# Get the capability bits: CMD_GET_CAPABILITY = 0x00 00 00 01
res="$(swtpm_ctrl_tx ${SWTPM_INTERFACE} '\x00\x00\x00\x01')"
if [[ "$(uname -s)" =~ (Linux|OpenBSD) ]]; then
exp=" 00 00 00 00 00 00 3f ff"
exp=" 00 00 00 00 00 00 7f ff"
else
exp=" 00 00 00 00 00 00 2f ff"
exp=" 00 00 00 00 00 00 6f ff"
fi
if [ "$res" != "$exp" ]; then
echo "Error: Unexpected response from CMD_GET_CAPABILITY:"
@ -173,9 +173,9 @@ swtpm_open_cmddev ${SWTPM_INTERFACE} 100
# Get the capability bits: CMD_GET_CAPABILITY = 0x00 00 00 01
res="$(swtpm_ctrl_tx ${SWTPM_INTERFACE} '\x00\x00\x00\x01')"
if [[ "$(uname -s)" =~ (Linux|OpenBSD) ]]; then
exp=" 00 00 00 00 00 00 3f ff"
exp=" 00 00 00 00 00 00 7f ff"
else
exp=" 00 00 00 00 00 00 2f ff"
exp=" 00 00 00 00 00 00 6f ff"
fi
if [ "$res" != "$exp" ]; then
echo "Error: Socket TPM: Unexpected response from CMD_GET_CAPABILITY:"

View File

@ -45,7 +45,7 @@ PID="$(cat $PID_FILE)"
# Get the capability bits: CMD_GET_CAPABILITY = 0x00 00 00 01
res="$(swtpm_ctrl_tx ${SWTPM_INTERFACE} '\x00\x00\x00\x01')"
exp=" 00 00 00 00 00 00 3f ff"
exp=" 00 00 00 00 00 00 7f ff"
if [ "$res" != "$exp" ]; then
echo "Error: Unexpected response from CMD_GET_CAPABILITY:"
echo " actual : $res"