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-2006
8 *
9 */
10
11#include <unistd.h>
12#include <errno.h>
13#include <string.h>
14#include <sys/socket.h>
15#include <sys/types.h>
16#include <netinet/in.h>
17#include <arpa/inet.h>
18#include <netdb.h>
19#include <stdlib.h>
20#include <stdio.h>
21#include <assert.h>
22#include <limits.h>
23
24#include "trousers/tss.h"
25#include "trousers/trousers.h"
26#include "trousers_types.h"
27#include "spi_utils.h"
28#include "capabilities.h"
29#include "tsplog.h"
30#include "hosttable.h"
31#include "tcsd_wrap.h"
32#include "obj.h"
33#include "rpc_tcstp_tsp.h"
34#include "tsp_tcsi_param.h"
35
36
37void
38initData(struct tcsd_comm_data *comm, int parm_count)
39{
40	/* min packet size should be the size of the header */
41	__tspi_memset(&comm->hdr, 0, sizeof(struct tcsd_packet_hdr));
42	comm->hdr.packet_size = sizeof(struct tcsd_packet_hdr);
43	comm->hdr.type_offset = sizeof(struct tcsd_packet_hdr);
44	comm->hdr.parm_offset = comm->hdr.type_offset + (sizeof(TCSD_PACKET_TYPE) * parm_count);
45	comm->hdr.packet_size = comm->hdr.parm_offset;
46
47	__tspi_memset(comm->buf, 0, comm->buf_size);
48}
49
50int
51loadData(UINT64 *offset, TCSD_PACKET_TYPE data_type, void *data, int data_size, BYTE *blob)
52{
53	switch (data_type) {
54		case TCSD_PACKET_TYPE_BYTE:
55			Trspi_LoadBlob_BYTE(offset, *((BYTE *) (data)), blob);
56			break;
57		case TCSD_PACKET_TYPE_BOOL:
58			Trspi_LoadBlob_BOOL(offset, *((TSS_BOOL *) (data)), blob);
59			break;
60		case TCSD_PACKET_TYPE_UINT16:
61			Trspi_LoadBlob_UINT16(offset, *((UINT16 *) (data)), blob);
62			break;
63		case TCSD_PACKET_TYPE_UINT32:
64			Trspi_LoadBlob_UINT32(offset, *((UINT32 *) (data)), blob);
65			break;
66		case TCSD_PACKET_TYPE_PBYTE:
67			Trspi_LoadBlob(offset, data_size, blob, (BYTE *)data);
68			break;
69		case TCSD_PACKET_TYPE_NONCE:
70			Trspi_LoadBlob(offset, 20, blob, ((TCPA_NONCE *)data)->nonce);
71			break;
72		case TCSD_PACKET_TYPE_DIGEST:
73			Trspi_LoadBlob(offset, 20, blob, ((TCPA_DIGEST *)data)->digest);
74			break;
75		case TCSD_PACKET_TYPE_AUTH:
76			LoadBlob_AUTH(offset, blob, ((TPM_AUTH *)data));
77			break;
78		case TCSD_PACKET_TYPE_UUID:
79			Trspi_LoadBlob_UUID(offset, blob, *((TSS_UUID *)data));
80			break;
81		case TCSD_PACKET_TYPE_ENCAUTH:
82			Trspi_LoadBlob(offset, 20, blob, ((TCPA_ENCAUTH *)data)->authdata);
83			break;
84		case TCSD_PACKET_TYPE_VERSION:
85			Trspi_LoadBlob_TCPA_VERSION(offset, blob, *((TCPA_VERSION *)data));
86			break;
87#ifdef TSS_BUILD_PS
88		case TCSD_PACKET_TYPE_LOADKEY_INFO:
89			LoadBlob_LOADKEY_INFO(offset, blob, ((TCS_LOADKEY_INFO *)data));
90			break;
91#endif
92		case TCSD_PACKET_TYPE_PCR_EVENT:
93			Trspi_LoadBlob_PCR_EVENT(offset, blob, ((TSS_PCR_EVENT *)data));
94			break;
95		case TCSD_PACKET_TYPE_COUNTER_VALUE:
96			Trspi_LoadBlob_COUNTER_VALUE(offset, blob, ((TPM_COUNTER_VALUE *)data));
97			break;
98		case TCSD_PACKET_TYPE_SECRET:
99			Trspi_LoadBlob(offset, 20, blob, ((TCPA_SECRET *)data)->authdata);
100			break;
101		default:
102			LogError("TCSD packet type unknown! (0x%x)", data_type & 0xff);
103			return TSPERR(TSS_E_INTERNAL_ERROR);
104	}
105
106	return TSS_SUCCESS;
107}
108
109int
110setData(TCSD_PACKET_TYPE dataType,
111	int index,
112	void *theData,
113	int theDataSize,
114	struct tcsd_comm_data *comm)
115{
116        UINT64 old_offset, offset;
117        TSS_RESULT result;
118        TCSD_PACKET_TYPE *type;
119
120        /* Calculate the size of the area needed (use NULL for blob address) */
121        offset = 0;
122        if ((result = loadData(&offset, dataType, theData, theDataSize, NULL)))
123                return result;
124        if ((comm->hdr.packet_size + offset) > TSS_TPM_TXBLOB_SIZE) {
125                LogError("Too much data to be transmitted!");
126                return TSPERR(TSS_E_INTERNAL_ERROR);
127        }
128        if ((comm->hdr.packet_size + offset) > comm->buf_size) {
129                /* reallocate the buffer */
130                BYTE *buffer;
131                int buffer_size = comm->hdr.packet_size + offset;
132
133                LogDebug("Increasing communication buffer to %d bytes.", buffer_size);
134                buffer = realloc(comm->buf, buffer_size);
135                if (buffer == NULL) {
136                        LogError("realloc of %d bytes failed.", buffer_size);
137                        return TSPERR(TSS_E_INTERNAL_ERROR);
138                }
139                comm->buf_size = buffer_size;
140                comm->buf = buffer;
141        }
142
143        offset = old_offset = comm->hdr.parm_offset + comm->hdr.parm_size;
144        if ((result = loadData(&offset, dataType, theData, theDataSize, comm->buf)))
145                return result;
146        type = (TCSD_PACKET_TYPE *)(comm->buf + comm->hdr.type_offset) + index;
147        *type = dataType;
148        comm->hdr.type_size += sizeof(TCSD_PACKET_TYPE);
149        comm->hdr.parm_size += (offset - old_offset);
150
151        comm->hdr.packet_size = offset;
152        comm->hdr.num_parms++;
153
154        return TSS_SUCCESS;
155}
156
157UINT32
158getData(TCSD_PACKET_TYPE dataType,
159	int index,
160	void *theData,
161	int theDataSize,
162	struct tcsd_comm_data *comm)
163{
164	TSS_RESULT result;
165	UINT64 old_offset, offset;
166	TCSD_PACKET_TYPE *type = (TCSD_PACKET_TYPE *)(comm->buf + comm->hdr.type_offset) + index;
167
168	if ((UINT32)index >= comm->hdr.num_parms || dataType != *type) {
169		LogDebug("Data type of TCS packet element %d doesn't match.", index);
170		return TSS_TCP_RPC_BAD_PACKET_TYPE;
171	}
172	old_offset = offset = comm->hdr.parm_offset;
173	switch (dataType) {
174		case TCSD_PACKET_TYPE_BYTE:
175			Trspi_UnloadBlob_BYTE(&offset, (BYTE *)theData, comm->buf);
176			break;
177		case TCSD_PACKET_TYPE_BOOL:
178			Trspi_UnloadBlob_BOOL(&offset, (TSS_BOOL *)theData, comm->buf);
179			break;
180		case TCSD_PACKET_TYPE_UINT16:
181			Trspi_UnloadBlob_UINT16(&offset, (UINT16 *)theData, comm->buf);
182			break;
183		case TCSD_PACKET_TYPE_UINT32:
184			Trspi_UnloadBlob_UINT32(&offset, (UINT32 *)theData, comm->buf);
185			break;
186		case TCSD_PACKET_TYPE_UINT64:
187			Trspi_UnloadBlob_UINT64(&offset, (UINT64 *)theData, comm->buf);
188			break;
189		case TCSD_PACKET_TYPE_PBYTE:
190			Trspi_UnloadBlob(&offset, theDataSize, comm->buf, (BYTE *)theData);
191			break;
192		case TCSD_PACKET_TYPE_NONCE:
193			Trspi_UnloadBlob_NONCE(&offset, comm->buf, (TPM_NONCE *)theData);
194			break;
195		case TCSD_PACKET_TYPE_DIGEST:
196			Trspi_UnloadBlob(&offset, sizeof(TCPA_DIGEST), comm->buf,
197					 ((TCPA_DIGEST *)theData)->digest);
198			break;
199		case TCSD_PACKET_TYPE_AUTH:
200			UnloadBlob_AUTH(&offset, comm->buf, ((TPM_AUTH *)theData));
201			break;
202		case TCSD_PACKET_TYPE_UUID:
203			Trspi_UnloadBlob_UUID(&offset, comm->buf, ((TSS_UUID *)theData));
204			break;
205		case TCSD_PACKET_TYPE_ENCAUTH:
206			Trspi_UnloadBlob(&offset, sizeof(TCPA_ENCAUTH), comm->buf,
207					 ((TCPA_ENCAUTH *)theData)->authdata);
208			break;
209		case TCSD_PACKET_TYPE_VERSION:
210			Trspi_UnloadBlob_TCPA_VERSION(&offset, comm->buf,
211						      ((TCPA_VERSION *)theData));
212			break;
213		case TCSD_PACKET_TYPE_KM_KEYINFO:
214			if ((result = Trspi_UnloadBlob_KM_KEYINFO(&offset, comm->buf,
215								  ((TSS_KM_KEYINFO *)theData))))
216				return result;
217			break;
218		case TCSD_PACKET_TYPE_KM_KEYINFO2:
219			if ((result = Trspi_UnloadBlob_KM_KEYINFO2(&offset, comm->buf,
220								   ((TSS_KM_KEYINFO2 *)theData))))
221				return result;
222			break;
223#ifdef TSS_BUILD_PS
224		case TCSD_PACKET_TYPE_LOADKEY_INFO:
225			UnloadBlob_LOADKEY_INFO(&offset, comm->buf, ((TCS_LOADKEY_INFO *)theData));
226			break;
227#endif
228		case TCSD_PACKET_TYPE_PCR_EVENT:
229			if ((result = Trspi_UnloadBlob_PCR_EVENT(&offset, comm->buf,
230								 ((TSS_PCR_EVENT *)theData))))
231				return result;
232			break;
233		case TCSD_PACKET_TYPE_COUNTER_VALUE:
234			Trspi_UnloadBlob_COUNTER_VALUE(&offset, comm->buf,
235						       ((TPM_COUNTER_VALUE *)theData));
236			break;
237		case TCSD_PACKET_TYPE_SECRET:
238			Trspi_UnloadBlob(&offset, sizeof(TCPA_SECRET), comm->buf,
239					 ((TCPA_SECRET *)theData)->authdata);
240			break;
241		default:
242			LogError("unknown data type (%d) in TCSD packet!", dataType);
243			return -1;
244	}
245	comm->hdr.parm_offset = offset;
246	comm->hdr.parm_size -= (offset - old_offset);
247
248	return TSS_SUCCESS;
249}
250
251TSS_RESULT
252sendTCSDPacket(struct host_table_entry *hte)
253{
254	TSS_RESULT rc;
255	UINT64 offset = 0;
256
257	Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.packet_size, hte->comm.buf);
258	Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.u.ordinal, hte->comm.buf);
259	Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.num_parms, hte->comm.buf);
260	Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.type_size, hte->comm.buf);
261	Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.type_offset, hte->comm.buf);
262	Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.parm_size, hte->comm.buf);
263	Trspi_LoadBlob_UINT32(&offset, hte->comm.hdr.parm_offset, hte->comm.buf);
264
265#if 0
266	/* ---  Send it */
267	printBuffer(hte->comm.buf, hte->comm.hdr.packet_size);
268	LogInfo("Sending Packet with TCSD ordinal 0x%X", hte->comm.hdr.u.ordinal);
269#endif
270	/* if the ordinal is open context, there are some host table entry
271	 * manipulations that must be done, so call _init
272	 */
273	if (hte->comm.hdr.u.ordinal == TCSD_ORD_OPENCONTEXT) {
274		if ((rc = send_init(hte))) {
275			LogError("Failed to send packet");
276			return rc;
277		}
278	} else {
279		if ((rc = tcs_sendit(hte))) {
280			LogError("Failed to send packet");
281			return rc;
282		}
283	}
284
285	/* create a platform version of the tcsd header */
286	offset = 0;
287	Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.packet_size, hte->comm.buf);
288	Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.u.result, hte->comm.buf);
289	Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.num_parms, hte->comm.buf);
290	Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.type_size, hte->comm.buf);
291	Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.type_offset, hte->comm.buf);
292	Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.parm_size, hte->comm.buf);
293	Trspi_UnloadBlob_UINT32(&offset, &hte->comm.hdr.parm_offset, hte->comm.buf);
294
295	return TSS_SUCCESS;
296}
297
298int
299recv_from_socket(int sock, void *buffer, int size)
300{
301	int recv_size = 0, recv_total = 0;
302
303	while (recv_total < size) {
304		errno = 0;
305		if ((recv_size = recv(sock, buffer+recv_total, size-recv_total, 0)) <= 0) {
306			if (recv_size < 0) {
307				if (errno == EINTR)
308					continue;
309				LogError("Socket receive connection error: %s.", strerror(errno));
310			} else {
311				LogDebug("Socket connection closed.");
312			}
313
314			return -1;
315		}
316		recv_total += recv_size;
317	}
318
319	return recv_total;
320}
321
322int
323send_to_socket(int sock, void *buffer, int size)
324{
325	int send_size = 0, send_total = 0;
326
327	while (send_total < size) {
328		if ((send_size = send(sock, buffer+send_total, size-send_total, 0)) < 0) {
329			LogError("Socket send connection error: %s.", strerror(errno));
330			return -1;
331		}
332		send_total += send_size;
333	}
334
335	return send_total;
336}
337
338TSS_RESULT
339send_init(struct host_table_entry *hte)
340{
341	int sd;
342	int recv_size;
343	BYTE *buffer;
344	TSS_RESULT result;
345
346	result = get_socket(hte, &sd);
347	if (result != TSS_SUCCESS)
348		goto err_exit;
349
350	if (send_to_socket(sd, hte->comm.buf, hte->comm.hdr.packet_size) < 0) {
351		result = TSPERR(TSS_E_COMM_FAILURE);
352		goto err_exit;
353	}
354
355	buffer = hte->comm.buf;
356	recv_size = sizeof(struct tcsd_packet_hdr);
357	if (recv_from_socket(sd, buffer, recv_size) < 0) {
358		result = TSPERR(TSS_E_COMM_FAILURE);
359		goto err_exit;
360	}
361	buffer += sizeof(struct tcsd_packet_hdr);       /* increment the receive buffer pointer */
362
363	/* check the packet size */
364	recv_size = Decode_UINT32(hte->comm.buf);
365	if (recv_size < (int)sizeof(struct tcsd_packet_hdr)) {
366		LogError("Packet to receive from socket %d is too small (%d bytes)",
367				sd, recv_size);
368		result = TSPERR(TSS_E_COMM_FAILURE);
369		goto err_exit;
370	}
371
372	if (recv_size > (int) hte->comm.buf_size ) {
373		BYTE *new_buffer;
374
375		LogDebug("Increasing communication buffer to %d bytes.", recv_size);
376		new_buffer = realloc(hte->comm.buf, recv_size);
377		if (new_buffer == NULL) {
378			LogError("realloc of %d bytes failed.", recv_size);
379			result = TSPERR(TSS_E_OUTOFMEMORY);
380			goto err_exit;
381		}
382		buffer = new_buffer + sizeof(struct tcsd_packet_hdr);
383		hte->comm.buf_size = recv_size;
384		hte->comm.buf = new_buffer;
385	}
386
387	/* get the rest of the packet */
388	recv_size -= sizeof(struct tcsd_packet_hdr);    /* already received the header */
389	if (recv_from_socket(sd, buffer, recv_size) < 0) {
390		result = TSPERR(TSS_E_COMM_FAILURE);
391		goto err_exit;
392	}
393
394	hte->socket = sd;
395
396	return TSS_SUCCESS;
397
398err_exit:
399	close(sd);
400	return result;
401}
402
403TSS_RESULT
404tcs_sendit(struct host_table_entry *hte)
405{
406	int recv_size;
407	BYTE *buffer;
408	TSS_RESULT result;
409
410	if (send_to_socket(hte->socket, hte->comm.buf, hte->comm.hdr.packet_size) < 0) {
411		result = TSPERR(TSS_E_COMM_FAILURE);
412		goto err_exit;
413	}
414
415	buffer = hte->comm.buf;
416	recv_size = sizeof(struct tcsd_packet_hdr);
417	if ((recv_size = recv_from_socket(hte->socket, buffer, recv_size)) < 0) {
418		result = TSPERR(TSS_E_COMM_FAILURE);
419		goto err_exit;
420	}
421	buffer += recv_size;            /* increment the receive buffer pointer */
422
423	/* check the packet size */
424	recv_size = Decode_UINT32(hte->comm.buf);
425	if (recv_size < (int)sizeof(struct tcsd_packet_hdr)) {
426		LogError("Packet to receive from socket %d is too small (%d bytes)",
427				hte->socket, recv_size);
428		result = TSPERR(TSS_E_COMM_FAILURE);
429		goto err_exit;
430	}
431
432	if (recv_size > (int) hte->comm.buf_size ) {
433		BYTE *new_buffer;
434
435		LogDebug("Increasing communication buffer to %d bytes.", recv_size);
436		new_buffer = realloc(hte->comm.buf, recv_size);
437		if (new_buffer == NULL) {
438			LogError("realloc of %d bytes failed.", recv_size);
439			result = TSPERR(TSS_E_OUTOFMEMORY);
440			goto err_exit;
441		}
442		buffer = new_buffer + sizeof(struct tcsd_packet_hdr);
443		hte->comm.buf_size = recv_size;
444		hte->comm.buf = new_buffer;
445	}
446
447	/* get the rest of the packet */
448	recv_size -= sizeof(struct tcsd_packet_hdr);    /* already received the header */
449	if ((recv_size = recv_from_socket(hte->socket, buffer, recv_size)) < 0) {
450		result = TSPERR(TSS_E_COMM_FAILURE);
451		goto err_exit;
452	}
453
454	return TSS_SUCCESS;
455
456err_exit:
457	return result;
458}
459
460/* TODO: Future work - remove socket creation/manipulation from RPC-specific file */
461TSS_RESULT
462get_socket(struct host_table_entry *hte, int *sd)
463{
464	char port_str[TCP_PORT_STR_MAX_LEN]; // To accomodate string 65535
465	struct addrinfo hints, *p, *res=NULL;
466	int rv;
467	TSS_RESULT result = TSS_SUCCESS;
468
469	__tspi_memset(&hints, 0, sizeof(hints));
470	hints.ai_socktype = SOCK_STREAM;
471	hints.ai_flags = AI_NUMERICSERV;
472
473	__tspi_memset(&port_str, 0, sizeof(port_str));
474
475	if (get_tcsd_port(port_str) != TSS_SUCCESS) {
476		LogError("Could not retrieve TCP port information.");
477		goto exit;
478	}
479
480	LogDebug("Retrieving address information from host: %s", (char *)hte->hostname);
481	rv = getaddrinfo((char *)hte->hostname, port_str,
482			&hints, &res);
483	if (rv != 0) {
484		LogError("hostname %s does not resolve to a valid address.", hte->hostname);
485		result = TSPERR(TSS_E_CONNECTION_FAILED);
486		res = NULL;
487		goto exit;
488	}
489
490	LogWarn("Got a list of valid IPs");
491
492	for (p = res; p != NULL; p = p->ai_next) {
493
494		*sd = socket(p->ai_family, SOCK_STREAM, 0);
495		if (*sd == -1)
496			continue;
497
498		if (connect(*sd, p->ai_addr, p->ai_addrlen) != -1)
499			break; // Got a connection
500
501		LogWarn("Could not connect to machine: %s", (char*)hte->hostname);
502
503		close(*sd);
504	}
505
506	if (p == NULL) {
507		LogError("Could not connect to any machine in the list.");
508		result = TSPERR(TSS_E_COMM_FAILURE);
509		goto exit;
510	}
511
512exit:
513	if (res != NULL)
514		freeaddrinfo(res);
515
516	return result;
517}
518