xref: /netbsd-src/crypto/external/cpl/trousers/dist/src/tddl/tddl.c (revision 2d5f7628c5531eb583b9313ac2fd1cf8582b4479)
1 
2 /*
3  * Licensed Materials - Property of IBM
4  *
5  * trousers - An open source TCG Software Stack
6  *
7  * (C) Copyright International Business Machines Corp. 2004, 2005
8  *
9  */
10 
11 
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <sys/ioctl.h>
18 
19 #include "trousers/tss.h"
20 #include "trousers_types.h"
21 #include "linux/tpm.h"
22 #include "tcslog.h"
23 #include "tddl.h"
24 
25 struct tpm_device_node tpm_device_nodes[] = {
26 	{"/dev/tpm0", TDDL_UNDEF, TDDL_UNDEF},
27 	{"/udev/tpm0", TDDL_UNDEF, TDDL_UNDEF},
28 	{"/dev/tpm", TDDL_UNDEF, TDDL_UNDEF},
29 	{NULL, 0, 0}
30 };
31 
32 struct tpm_device_node *opened_device = NULL;
33 
34 BYTE txBuffer[TDDL_TXBUF_SIZE];
35 TSS_BOOL use_in_socket = FALSE;
36 struct tcsd_config *_tcsd_options = NULL;
37 
38 #include <sys/socket.h>
39 #include <sys/un.h>
40 #include <netinet/in.h>
41 #include <sys/types.h>
42 #include <netdb.h>
43 #include <fcntl.h>
44 
45 
46 int
open_device()47 open_device()
48 {
49 	int i = 0, fd = -1, tcp_device_port;
50 	char *tcp_device_hostname = NULL;
51 	char *un_socket_device_path = NULL;
52 	char *tcp_device_port_string = NULL;
53 
54 	if (getenv("TCSD_USE_TCP_DEVICE")) {
55 		if ((tcp_device_hostname = getenv("TCSD_TCP_DEVICE_HOSTNAME")) == NULL)
56 			tcp_device_hostname = "localhost";
57 		if ((un_socket_device_path = getenv("TCSD_UN_SOCKET_DEVICE_PATH")) == NULL)
58 			un_socket_device_path = "/var/run/tpm/tpmd_socket:0";
59 		if ((tcp_device_port_string = getenv("TCSD_TCP_DEVICE_PORT")) != NULL)
60 			tcp_device_port = atoi(tcp_device_port_string);
61 		else
62 			tcp_device_port = 6545;
63 
64 
65 		fd = socket(AF_INET, SOCK_STREAM, 0);
66 		if (fd > 0) {
67 			struct hostent *host = gethostbyname(tcp_device_hostname);
68 			if (host != NULL) {
69 				struct sockaddr_in addr;
70 				memset(&addr, 0x0, sizeof(addr));
71 				addr.sin_family = host->h_addrtype;
72 				addr.sin_port   = htons(tcp_device_port);
73 				memcpy(&addr.sin_addr,
74 						host->h_addr,
75 						host->h_length);
76 				if (connect(fd,	(struct sockaddr *)&addr,
77 					    sizeof(addr)) < 0) {
78 					close(fd);
79 					fd = -1;
80 				} else
81 					use_in_socket = TRUE;
82 			} else {
83 				close (fd);
84 				fd = -1;
85 			}
86 		}
87 
88 		if (fd < 0) {
89 			struct sockaddr_un addr;
90 
91 			fd = socket(AF_UNIX, SOCK_STREAM, 0);
92 			if (fd >= 0) {
93 				addr.sun_family = AF_UNIX;
94 				strncpy(addr.sun_path, un_socket_device_path,
95 						sizeof(addr.sun_path));
96 				if (connect(fd, (void *)&addr, sizeof(addr)) < 0) {
97 					close(fd);
98 					fd = -1;
99 				}
100 			}
101 		}
102 	}
103 
104 	if (fd < 0) {
105 		/* tpm_device_paths is filled out in tddl.h */
106 		for (i = 0; tpm_device_nodes[i].path != NULL; i++) {
107 			errno = 0;
108 			if ((fd = open(tpm_device_nodes[i].path, O_RDWR)) >= 0)
109 				break;
110 		}
111 	}
112 
113 	if (fd > 0) {
114 		opened_device = &(tpm_device_nodes[i]);
115 		tpm_device_nodes[i].fd = fd;
116 	}
117 	return fd;
118 }
119 
120 TSS_RESULT
Tddli_Open()121 Tddli_Open()
122 {
123 	int rc;
124 
125 	if (opened_device != NULL) {
126 		LogDebug("attempted to re-open the TPM driver!");
127 		return TDDLERR(TDDL_E_ALREADY_OPENED);
128 	}
129 
130 	rc = open_device();
131 	if (rc < 0) {
132 		LogError("Could not find a device to open!");
133 		if (errno == ENOENT) {
134 			/* File DNE */
135 			return TDDLERR(TDDL_E_COMPONENT_NOT_FOUND);
136 		}
137 
138 		return TDDLERR(TDDL_E_FAIL);
139 	}
140 
141 	return TSS_SUCCESS;
142 }
143 
144 TSS_RESULT
Tddli_Close()145 Tddli_Close()
146 {
147 	if (opened_device == NULL) {
148 		LogDebug("attempted to re-close the TPM driver!");
149 		return TDDLERR(TDDL_E_ALREADY_CLOSED);
150 	}
151 
152 	close(opened_device->fd);
153 	opened_device->fd = TDDL_UNDEF;
154 	opened_device = NULL;
155 
156 	return TSS_SUCCESS;
157 }
158 
159 TSS_RESULT
Tddli_TransmitData(BYTE * pTransmitBuf,UINT32 TransmitBufLen,BYTE * pReceiveBuf,UINT32 * pReceiveBufLen)160 Tddli_TransmitData(BYTE * pTransmitBuf, UINT32 TransmitBufLen, BYTE * pReceiveBuf,
161 		   UINT32 * pReceiveBufLen)
162 {
163 	int sizeResult;
164 
165 	if (TransmitBufLen > TDDL_TXBUF_SIZE) {
166 		LogError("buffer size handed to TDDL is too large! (%u bytes)", TransmitBufLen);
167 		return TDDLERR(TDDL_E_FAIL);
168 	}
169 
170 	memcpy(txBuffer, pTransmitBuf, TransmitBufLen);
171 	LogDebug("Calling write to driver");
172 
173 	if (use_in_socket) {
174 		Tddli_Close();
175 		if (Tddli_Open())
176 			return TDDLERR(TDDL_E_IOERROR);
177 	}
178 
179 	switch (opened_device->transmit) {
180 		case TDDL_UNDEF:
181 			/* fall through */
182 		case TDDL_TRANSMIT_IOCTL:
183 			errno = 0;
184 			if ((sizeResult = ioctl(opened_device->fd, TPMIOC_TRANSMIT, txBuffer)) != -1) {
185 				opened_device->transmit = TDDL_TRANSMIT_IOCTL;
186 				break;
187 			}
188 			LogWarn("ioctl: (%d) %s", errno, strerror(errno));
189 			LogInfo("Falling back to Read/Write device support.");
190 			/* fall through */
191 		case TDDL_TRANSMIT_RW:
192 			if ((sizeResult = write(opened_device->fd,
193 						txBuffer,
194 						TransmitBufLen)) == (int)TransmitBufLen) {
195 				opened_device->transmit = TDDL_TRANSMIT_RW;
196 				sizeResult = read(opened_device->fd, txBuffer,
197 						  TDDL_TXBUF_SIZE);
198 				break;
199 			} else {
200 				if (sizeResult == -1) {
201 					LogError("write to device %s failed: %s",
202 						 opened_device->path,
203 						 strerror(errno));
204 				} else {
205 					LogError("wrote %d bytes to %s (tried "
206 						 "to write %d)", sizeResult,
207 						 opened_device->path,
208 						 TransmitBufLen);
209 				}
210 			}
211 			/* fall through */
212 		default:
213 			return TDDLERR(TDDL_E_IOERROR);
214 	}
215 
216 	if (sizeResult < 0) {
217 		LogError("read from device %s failed: %s", opened_device->path, strerror(errno));
218 		return TDDLERR(TDDL_E_IOERROR);
219 	} else if (sizeResult == 0) {
220 		LogError("Zero bytes read from device %s", opened_device->path);
221 		return TDDLERR(TDDL_E_IOERROR);
222 	}
223 
224 	if ((unsigned)sizeResult > *pReceiveBufLen) {
225 		LogError("read %d bytes from device %s, (only room for %d)", sizeResult,
226 				opened_device->path, *pReceiveBufLen);
227 		return TDDLERR(TDDL_E_INSUFFICIENT_BUFFER);
228 	}
229 
230 	*pReceiveBufLen = sizeResult;
231 
232 	memcpy(pReceiveBuf, txBuffer, *pReceiveBufLen);
233 	return TSS_SUCCESS;
234 }
235 
236 TSS_RESULT
Tddli_GetStatus(UINT32 ReqStatusType,UINT32 * pStatus)237 Tddli_GetStatus(UINT32 ReqStatusType, UINT32 *pStatus)
238 {
239 	return TDDLERR(TSS_E_NOTIMPL);
240 }
241 
242 TSS_RESULT
Tddli_SetCapability(UINT32 CapArea,UINT32 SubCap,BYTE * pSetCapBuf,UINT32 SetCapBufLen)243 Tddli_SetCapability(UINT32 CapArea, UINT32 SubCap,
244 		    BYTE *pSetCapBuf, UINT32 SetCapBufLen)
245 {
246 	return TDDLERR(TSS_E_NOTIMPL);
247 }
248 
249 TSS_RESULT
Tddli_GetCapability(UINT32 CapArea,UINT32 SubCap,BYTE * pCapBuf,UINT32 * pCapBufLen)250 Tddli_GetCapability(UINT32 CapArea, UINT32 SubCap,
251 		    BYTE *pCapBuf, UINT32 *pCapBufLen)
252 {
253 	return TDDLERR(TSS_E_NOTIMPL);
254 }
255 
Tddli_Cancel(void)256 TSS_RESULT Tddli_Cancel(void)
257 {
258 	int rc;
259 
260 	if (opened_device->transmit == TDDL_TRANSMIT_IOCTL) {
261 		if ((rc = ioctl(opened_device->fd, TPMIOC_CANCEL, NULL)) == -1) {
262 			LogError("ioctl: (%d) %s", errno, strerror(errno));
263 			return TDDLERR(TDDL_E_FAIL);
264 		} else if (rc == -EIO) {
265 			/* The driver timed out while trying to tell the chip to cancel */
266 			return TDDLERR(TDDL_E_COMMAND_COMPLETED);
267 		}
268 
269 		return TSS_SUCCESS;
270 	} else {
271 		return TDDLERR(TSS_E_NOTIMPL);
272 	}
273 }
274