1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2024 Hans Rosenfeld
5 * Author: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
6 */
7
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <sys/un.h>
11
12 #include <err.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <malloc_np.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <strings.h>
19 #include <unistd.h>
20
21 #include "config.h"
22 #include "tpm_device.h"
23 #include "tpm_emul.h"
24
25 struct tpm_swtpm {
26 int fd;
27 };
28
29 struct tpm_resp_hdr {
30 uint16_t tag;
31 uint32_t len;
32 uint32_t errcode;
33 } __packed;
34
35 static int
tpm_swtpm_init(void ** sc,nvlist_t * nvl)36 tpm_swtpm_init(void **sc, nvlist_t *nvl)
37 {
38 struct tpm_swtpm *tpm;
39 const char *path;
40 struct sockaddr_un tpm_addr;
41
42 tpm = calloc(1, sizeof (struct tpm_swtpm));
43 if (tpm == NULL) {
44 warnx("%s: failed to allocate tpm_swtpm", __func__);
45 return (ENOMEM);
46 }
47
48 path = get_config_value_node(nvl, "path");
49 if (path == NULL) {
50 warnx("%s: no socket path specified", __func__);
51 return (ENOENT);
52 }
53
54 tpm->fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
55 if (tpm->fd < 0) {
56 warnx("%s: unable to open tpm socket", __func__);
57 return (ENOENT);
58 }
59
60 bzero(&tpm_addr, sizeof (tpm_addr));
61 tpm_addr.sun_family = AF_UNIX;
62 strlcpy(tpm_addr.sun_path, path, sizeof (tpm_addr.sun_path) - 1);
63
64 if (connect(tpm->fd, (struct sockaddr *)&tpm_addr, sizeof (tpm_addr)) ==
65 -1) {
66 warnx("%s: unable to connect to tpm socket \"%s\"", __func__,
67 path);
68 return (ENOENT);
69 }
70
71 *sc = tpm;
72
73 return (0);
74 }
75
76 static int
tpm_swtpm_execute_cmd(void * sc,void * cmd,uint32_t cmd_size,void * rsp,uint32_t rsp_size)77 tpm_swtpm_execute_cmd(void *sc, void *cmd, uint32_t cmd_size, void *rsp,
78 uint32_t rsp_size)
79 {
80 struct tpm_swtpm *tpm;
81 ssize_t len;
82
83 if (rsp_size < (ssize_t)sizeof(struct tpm_resp_hdr)) {
84 warn("%s: rsp_size of %u is too small", __func__, rsp_size);
85 return (EINVAL);
86 }
87
88 tpm = sc;
89
90 len = send(tpm->fd, cmd, cmd_size, MSG_NOSIGNAL|MSG_DONTWAIT);
91 if (len == -1)
92 err(1, "%s: cmd send failed, is swtpm running?", __func__);
93 if (len != cmd_size) {
94 warn("%s: cmd write failed (bytes written: %zd / %d)", __func__,
95 len, cmd_size);
96 return (EFAULT);
97 }
98
99 len = recv(tpm->fd, rsp, rsp_size, 0);
100 if (len == -1)
101 err(1, "%s: rsp recv failed, is swtpm running?", __func__);
102 if (len < (ssize_t)sizeof(struct tpm_resp_hdr)) {
103 warn("%s: rsp read failed (bytes read: %zd / %d)", __func__,
104 len, rsp_size);
105 return (EFAULT);
106 }
107
108 return (0);
109 }
110
111 static void
tpm_swtpm_deinit(void * sc)112 tpm_swtpm_deinit(void *sc)
113 {
114 struct tpm_swtpm *tpm;
115
116 tpm = sc;
117 if (tpm == NULL)
118 return;
119
120 if (tpm->fd >= 0)
121 close(tpm->fd);
122
123 free(tpm);
124 }
125
126 static const struct tpm_emul tpm_emul_swtpm = {
127 .name = "swtpm",
128 .init = tpm_swtpm_init,
129 .deinit = tpm_swtpm_deinit,
130 .execute_cmd = tpm_swtpm_execute_cmd,
131 };
132 TPM_EMUL_SET(tpm_emul_swtpm);
133