]> git.proxmox.com Git - swtpm.git/commitdiff
swtpm: Implement CMD_GETINFO to retrieve TPM specification info
authorStefan Berger <stefanb@linux.vnet.ibm.com>
Sun, 22 Apr 2018 01:44:31 +0000 (21:44 -0400)
committerStefan Berger <stefanb@linux.vnet.ibm.com>
Mon, 23 Apr 2018 14:00:26 +0000 (10:00 -0400)
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>
include/swtpm/tpm_ioctl.h
src/swtpm/ctrlchannel.c
src/swtpm/cuse_tpm.c
tests/test_clientfds.py
tests/test_ctrlchannel
tests/test_ctrlchannel4

index bad86011b27504d9667b7b0cb37599c05788661c..d6196d4c2557121b3f47bede449ecb1aac39ad32 100644 (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 */
index 7b9aeb47e51172200c7507c915fd35f579c35a7f..1303fb3aa0d68f843756932eca9e96d665041539 100644 (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);
 
index 967c6d5cbd34ec6b3c156417d904d6c5870078b6..e8e79b266617cd672bc2fea6a9c5bd07e603280d 100644 (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;
 }
 
index 7dbbfce9d2fdb32748be8123d07fd14d2e2c10a8..289da09e7963c6519a183b147ab05b2d3537ed7b 100755 (executable)
@@ -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)
index b0a2d884bf18ef5126e31bc9fb050f5c5a3c2790..41328ec45ddc4d1a7561d80f3a1e0385d0902d79 100755 (executable)
@@ -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:"
index 65fa6d31f7d51f5e1860180598ccd925192adc93..ffbcde7407518a56974188a49c632447a01cc019 100755 (executable)
@@ -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"