/src/ibmswtpm2/src/TcpServerPosix.c
Line | Count | Source |
1 | | /********************************************************************************/ |
2 | | /* */ |
3 | | /* Socket Interface to a TPM Simulator */ |
4 | | /* Written by Ken Goldman */ |
5 | | /* IBM Thomas J. Watson Research Center */ |
6 | | /* $Id: TcpServerPosix.c 1332 2018-09-07 14:20:51Z kgoldman $ */ |
7 | | /* */ |
8 | | /* Licenses and Notices */ |
9 | | /* */ |
10 | | /* 1. Copyright Licenses: */ |
11 | | /* */ |
12 | | /* - Trusted Computing Group (TCG) grants to the user of the source code in */ |
13 | | /* this specification (the "Source Code") a worldwide, irrevocable, */ |
14 | | /* nonexclusive, royalty free, copyright license to reproduce, create */ |
15 | | /* derivative works, distribute, display and perform the Source Code and */ |
16 | | /* derivative works thereof, and to grant others the rights granted herein. */ |
17 | | /* */ |
18 | | /* - The TCG grants to the user of the other parts of the specification */ |
19 | | /* (other than the Source Code) the rights to reproduce, distribute, */ |
20 | | /* display, and perform the specification solely for the purpose of */ |
21 | | /* developing products based on such documents. */ |
22 | | /* */ |
23 | | /* 2. Source Code Distribution Conditions: */ |
24 | | /* */ |
25 | | /* - Redistributions of Source Code must retain the above copyright licenses, */ |
26 | | /* this list of conditions and the following disclaimers. */ |
27 | | /* */ |
28 | | /* - Redistributions in binary form must reproduce the above copyright */ |
29 | | /* licenses, this list of conditions and the following disclaimers in the */ |
30 | | /* documentation and/or other materials provided with the distribution. */ |
31 | | /* */ |
32 | | /* 3. Disclaimers: */ |
33 | | /* */ |
34 | | /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ |
35 | | /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ |
36 | | /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ |
37 | | /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ |
38 | | /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ |
39 | | /* information on specification licensing rights available through TCG */ |
40 | | /* membership agreements. */ |
41 | | /* */ |
42 | | /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ |
43 | | /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ |
44 | | /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ |
45 | | /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ |
46 | | /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ |
47 | | /* */ |
48 | | /* - Without limitation, TCG and its members and licensors disclaim all */ |
49 | | /* liability, including liability for infringement of any proprietary */ |
50 | | /* rights, relating to use of information in this specification and to the */ |
51 | | /* implementation of this specification, and TCG disclaims all liability for */ |
52 | | /* cost of procurement of substitute goods or services, lost profits, loss */ |
53 | | /* of use, loss of data or any incidental, consequential, direct, indirect, */ |
54 | | /* or special damages, whether under contract, tort, warranty or otherwise, */ |
55 | | /* arising in any way out of use or reliance upon this specification or any */ |
56 | | /* information herein. */ |
57 | | /* */ |
58 | | /* (c) Copyright IBM Corp. and others, 2012-2018 */ |
59 | | /* */ |
60 | | /********************************************************************************/ |
61 | | |
62 | | // D.3 TcpServer.c |
63 | | // D.3.1. Description |
64 | | // This file contains the socket interface to a TPM simulator. |
65 | | // D.3.2. Includes, Locals, Defines and Function Prototypes |
66 | | |
67 | | #include <stdio.h> |
68 | | /* FIXME need Posix TCP socket code */ |
69 | | #include <unistd.h> |
70 | | #include <sys/types.h> |
71 | | #include <sys/socket.h> |
72 | | #include <netinet/in.h> |
73 | | #include <pthread.h> |
74 | | |
75 | | #include "string.h" |
76 | | #include <stdlib.h> |
77 | | #include <stdint.h> |
78 | | #include <errno.h> |
79 | | |
80 | | #include "Implementation.h" /* kgold */ |
81 | | #include "TpmTcpProtocol.h" |
82 | | #include "TcpServerPosix_fp.h" |
83 | | #include "Simulator_fp.h" |
84 | | |
85 | 0 | #define IPVER(len) ((len) == sizeof(struct sockaddr_in6) ? 6 : \ |
86 | 0 | ((len) == sizeof(struct sockaddr_in) ? 4 : 0)) |
87 | | |
88 | | #ifndef __IGNORE_STATE__ |
89 | | static UINT32 ServerVersion = 1; |
90 | 20.2k | #define MAX_BUFFER 1048576 |
91 | | char InputBuffer[MAX_BUFFER]; //The input data buffer for the simulator. |
92 | | char OutputBuffer[MAX_BUFFER]; //The output data buffer for the simulator. |
93 | | |
94 | | struct { |
95 | | UINT32 largestCommandSize; |
96 | | UINT32 largestCommand; |
97 | | UINT32 largestResponseSize; |
98 | | UINT32 largestResponse; |
99 | | } CommandResponseSizes = {0}; |
100 | | |
101 | | #endif // __IGNORE_STATE___ |
102 | | |
103 | | // D.3.3. Functions |
104 | | // D.3.3.1. CreateSocket() |
105 | | // This function creates a socket listening on PortNumber. |
106 | | |
107 | | static int |
108 | | CreateSocket( |
109 | | int PortNumber, |
110 | | SOCKET *listenSocket, |
111 | | socklen_t *addr_len, |
112 | | int domain // AF_INET or AF_INET6 |
113 | | ) |
114 | 0 | { |
115 | 0 | struct sockaddr_storage MyAddress; |
116 | 0 | int opt; |
117 | | |
118 | 0 | int res; |
119 | | |
120 | | // create listening socket |
121 | 0 | *listenSocket = socket(domain, SOCK_STREAM, 0); |
122 | 0 | if(*listenSocket == -1) |
123 | 0 | { |
124 | 0 | printf("Warning: Cannot create server listen %s socket\nWarning is %d %s\n", |
125 | 0 | domain == AF_INET6 ? "IPv6" : |
126 | 0 | (domain == AF_INET) ? "IPv4" : "?", errno, strerror(errno)); |
127 | 0 | printf("Ignore the IPv6 warning if the platform doesn't support IPv6\n"); |
128 | 0 | return -1; |
129 | 0 | } |
130 | | |
131 | | // bind the listening socket to the specified port, any address (0s) |
132 | 0 | memset((char *)&MyAddress, 0, sizeof(MyAddress)); |
133 | |
|
134 | 0 | MyAddress.ss_family = domain; |
135 | 0 | switch (domain) { |
136 | 0 | case AF_INET: |
137 | 0 | ((struct sockaddr_in *)&MyAddress)->sin_port = |
138 | 0 | htons((short) PortNumber); |
139 | 0 | *addr_len = sizeof(struct sockaddr_in); |
140 | 0 | break; |
141 | 0 | case AF_INET6: |
142 | 0 | ((struct sockaddr_in6 *)&MyAddress)->sin6_port = |
143 | 0 | htons((short) PortNumber); |
144 | 0 | *addr_len = sizeof(struct sockaddr_in6); |
145 | |
|
146 | 0 | opt = 1; |
147 | | // Set IPPROTO_IPV6 so that it's just for IPv6 and not both IPv4/IPv6. |
148 | 0 | res = setsockopt(*listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, &opt, |
149 | 0 | sizeof(opt)); |
150 | 0 | if (res != 0) { |
151 | 0 | printf("setsockopt IPV6_V6ONLY error. Error is %d %s\n", |
152 | 0 | errno, strerror(errno)); |
153 | 0 | return -1; |
154 | 0 | } |
155 | 0 | break; |
156 | 0 | default: |
157 | 0 | printf("Address family %d not supported\n", domain); |
158 | 0 | return -1; |
159 | 0 | } |
160 | | |
161 | 0 | opt = 1; |
162 | | /* Set SO_REUSEADDR before calling bind() for servers that bind to a fixed port number. */ |
163 | 0 | res = setsockopt(*listenSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); |
164 | 0 | if (res != 0) { |
165 | 0 | printf("setsockopt error. Error is %d %s\n", errno, strerror(errno)); |
166 | 0 | return -1; |
167 | 0 | } |
168 | | |
169 | 0 | res= bind(*listenSocket,(struct sockaddr*) &MyAddress, *addr_len); |
170 | 0 | if(res != 0) |
171 | 0 | { |
172 | 0 | close(*listenSocket); |
173 | 0 | *listenSocket = -1; |
174 | 0 | printf("Bind error. Error is %d %s\n", errno, strerror(errno)); |
175 | 0 | return -1; |
176 | 0 | } |
177 | | |
178 | | // listen/wait for server connections |
179 | 0 | res= listen(*listenSocket,3); |
180 | 0 | if(res != 0) |
181 | 0 | { |
182 | 0 | close(*listenSocket); |
183 | 0 | *listenSocket = -1; |
184 | 0 | printf("Listen error. Error is %d %s\n", errno, strerror(errno)); |
185 | 0 | return -1; |
186 | 0 | } |
187 | | |
188 | 0 | return 0; |
189 | 0 | } |
190 | | |
191 | | // D.3.3.2. PlatformServer() |
192 | | // This function processes incoming platform requests. |
193 | | |
194 | | BOOL |
195 | | PlatformServer( |
196 | | SOCKET s |
197 | | ) |
198 | 0 | { |
199 | 0 | BOOL ok = TRUE; |
200 | | // UINT32 length = 0; kgold - unused |
201 | 0 | UINT32 Command; |
202 | | |
203 | 0 | for(;;) |
204 | 0 | { |
205 | 0 | ok = ReadBytes(s, (char*) &Command, 4); |
206 | | // client disconnected (or other error). We stop processing this client |
207 | | // and return to our caller who can stop the server or listen for another |
208 | | // connection. |
209 | 0 | if(!ok) return TRUE; |
210 | 0 | Command = ntohl(Command); |
211 | 0 | switch(Command) |
212 | 0 | { |
213 | 0 | case TPM_SIGNAL_POWER_ON: |
214 | 0 | _rpc__Signal_PowerOn(FALSE); |
215 | 0 | break; |
216 | | |
217 | 0 | case TPM_SIGNAL_POWER_OFF: |
218 | 0 | _rpc__Signal_PowerOff(); |
219 | 0 | break; |
220 | | |
221 | 0 | case TPM_SIGNAL_RESET: |
222 | 0 | _rpc__Signal_PowerOn(TRUE); |
223 | 0 | break; |
224 | | |
225 | 0 | case TPM_SIGNAL_PHYS_PRES_ON: |
226 | 0 | _rpc__Signal_PhysicalPresenceOn(); |
227 | 0 | break; |
228 | | |
229 | 0 | case TPM_SIGNAL_PHYS_PRES_OFF: |
230 | 0 | _rpc__Signal_PhysicalPresenceOff(); |
231 | 0 | break; |
232 | | |
233 | 0 | case TPM_SIGNAL_CANCEL_ON: |
234 | 0 | _rpc__Signal_CancelOn(); |
235 | 0 | break; |
236 | | |
237 | 0 | case TPM_SIGNAL_CANCEL_OFF: |
238 | 0 | _rpc__Signal_CancelOff(); |
239 | 0 | break; |
240 | | |
241 | 0 | case TPM_SIGNAL_NV_ON: |
242 | 0 | _rpc__Signal_NvOn(); |
243 | 0 | break; |
244 | | |
245 | 0 | case TPM_SIGNAL_NV_OFF: |
246 | 0 | _rpc__Signal_NvOff(); |
247 | 0 | break; |
248 | | |
249 | 0 | case TPM_SESSION_END: |
250 | | // Client signaled end-of-session |
251 | 0 | return TRUE; |
252 | | |
253 | 0 | case TPM_STOP: |
254 | | // Client requested the simulator to exit |
255 | 0 | return FALSE; |
256 | | |
257 | 0 | case TPM_TEST_FAILURE_MODE: |
258 | 0 | _rpc__ForceFailureMode(); |
259 | 0 | break; |
260 | | |
261 | 0 | case TPM_GET_COMMAND_RESPONSE_SIZES: |
262 | 0 | ok = WriteVarBytes(s, (char *)&CommandResponseSizes, |
263 | 0 | sizeof(CommandResponseSizes)); |
264 | 0 | memset(&CommandResponseSizes, 0, sizeof(CommandResponseSizes)); |
265 | 0 | if(!ok) |
266 | 0 | return TRUE; |
267 | 0 | break; |
268 | | |
269 | 0 | default: |
270 | 0 | printf("Unrecognized platform interface command %08x\n", Command); |
271 | 0 | WriteUINT32(s, 1); |
272 | 0 | return TRUE; |
273 | 0 | } |
274 | 0 | WriteUINT32(s,0); |
275 | 0 | } |
276 | 0 | return FALSE; |
277 | 0 | } |
278 | | |
279 | | // D.3.3.3. PlatformSvcRoutine() |
280 | | // This function is called to set up the socket interfaces to listen for commands. |
281 | | |
282 | | int |
283 | | PlatformSvcRoutine( |
284 | | void *port |
285 | | ) |
286 | 0 | { |
287 | 0 | int PortNumber = *(int *)port; |
288 | |
|
289 | 0 | SOCKET listenSocket[2], maxListenSocket, serverSocket; |
290 | 0 | struct sockaddr_storage HerAddress; |
291 | 0 | fd_set sockSet; |
292 | 0 | int res, i; |
293 | 0 | int nSock = 0; |
294 | 0 | socklen_t length[2]; |
295 | 0 | BOOL continueServing; |
296 | |
|
297 | 0 | if (CreateSocket(PortNumber, &listenSocket[nSock], &length[nSock], |
298 | 0 | AF_INET) == 0) { |
299 | 0 | nSock++; |
300 | |
|
301 | 0 | } |
302 | 0 | if (CreateSocket(PortNumber, &listenSocket[nSock], &length[nSock], |
303 | 0 | AF_INET6) == 0) { |
304 | 0 | nSock++; |
305 | 0 | } |
306 | 0 | if (nSock == 0) { |
307 | 0 | printf("Create platform service socket fail\n"); |
308 | 0 | return -1; |
309 | 0 | } |
310 | | |
311 | 0 | maxListenSocket = listenSocket[0]; |
312 | 0 | if ((nSock == 2) && (listenSocket[1] > maxListenSocket)) { |
313 | 0 | maxListenSocket = listenSocket[1]; |
314 | 0 | } |
315 | | |
316 | | // Loop accepting connections one-by-one until we are killed or asked to stop |
317 | | // Note the platform service is single-threaded so we don't listen for a new |
318 | | // connection until the prior connection drops. |
319 | 0 | do { |
320 | 0 | printf("Platform server listening on port %d\n", PortNumber); |
321 | | |
322 | | // Select both IPv4 and IPv6 sockets or whatever is available |
323 | 0 | FD_ZERO(&sockSet); |
324 | 0 | FD_SET(listenSocket[0], &sockSet); |
325 | 0 | if (nSock == 2) |
326 | 0 | FD_SET(listenSocket[1], &sockSet); |
327 | 0 | do { |
328 | 0 | res = select(maxListenSocket + 1, &sockSet, NULL, NULL, NULL); |
329 | 0 | } |
330 | 0 | while ((res == -1) && (errno == EINTR)); |
331 | 0 | if (res == -1) { |
332 | 0 | printf("Platform server select error. Error is %d %s\n", |
333 | 0 | errno, strerror(errno)); |
334 | 0 | return -1; |
335 | 0 | } |
336 | | |
337 | 0 | for (i = 0; i < nSock; i++) { |
338 | 0 | int ipver = IPVER(length[i]); |
339 | |
|
340 | 0 | if (!FD_ISSET(listenSocket[i], &sockSet)) |
341 | 0 | { |
342 | 0 | continue; |
343 | 0 | } |
344 | | // blocking accept |
345 | 0 | serverSocket = accept(listenSocket[i], |
346 | 0 | (struct sockaddr*) &HerAddress, |
347 | 0 | &length[i]); |
348 | 0 | if(serverSocket < 0) |
349 | 0 | { |
350 | 0 | printf("Platform server IPv%d Accept error. Error is %d %s\n", |
351 | 0 | ipver, errno, strerror(errno)); |
352 | 0 | return -1; |
353 | 0 | }; |
354 | 0 | printf("Platform IPv%d client accepted\n", ipver); |
355 | | |
356 | | // normal behavior on client disconnection is to wait for a new |
357 | | // client to connect |
358 | 0 | continueServing = PlatformServer(serverSocket); |
359 | 0 | close(serverSocket); |
360 | 0 | serverSocket = -1; |
361 | 0 | } |
362 | 0 | } |
363 | 0 | while(continueServing); |
364 | | |
365 | 0 | return 0; |
366 | 0 | } |
367 | | |
368 | | // D.3.3.4. PlatformSignalService() |
369 | | |
370 | | // This function starts a new thread waiting for platform signals. Platform signals are processed |
371 | | // one at a time in the order in which they are received. |
372 | | |
373 | | int |
374 | | PlatformSignalService( |
375 | | int *PortNumberPlatform |
376 | | ) |
377 | 0 | { |
378 | 0 | unsigned long thread; |
379 | 0 | int irc = 0; |
380 | 0 | pthread_t *pthread = (pthread_t *)&thread; |
381 | |
|
382 | 0 | irc = pthread_create(pthread, |
383 | 0 | NULL, |
384 | 0 | (void * (*)(void *))PlatformSvcRoutine, /* thread entry function */ |
385 | 0 | (void *)PortNumberPlatform); /* thread function parameters */ |
386 | 0 | if (irc != 0) { |
387 | 0 | printf("Thread Creation failed\n"); |
388 | 0 | return -1; |
389 | 0 | } |
390 | 0 | return 0; |
391 | | |
392 | |
|
393 | | #if 0 |
394 | | int ThreadId; |
395 | | HANDLE hPlatformSvc; |
396 | | // Create service thread for platform signals |
397 | | hPlatformSvc = CreateThread(NULL, 0, |
398 | | (LPTHREAD_START_ROUTINE)PlatformSvcRoutine, |
399 | | (LPVOID) (INT_PTR) port, 0, (LPDWORD)&ThreadId); |
400 | | if(hPlatformSvc == NULL) |
401 | | { |
402 | | printf("Thread Creation failed\n"); |
403 | | return -1; |
404 | | } |
405 | | |
406 | | return 0; |
407 | | |
408 | | |
409 | | #endif |
410 | 0 | } |
411 | | |
412 | | // D.3.3.5. RegularCommandService() |
413 | | // This funciton services regular commands. |
414 | | |
415 | | int |
416 | | RegularCommandService( |
417 | | int *PortNumber |
418 | | ) |
419 | 0 | { |
420 | 0 | SOCKET listenSocket[2], maxListenSocket; |
421 | 0 | SOCKET serverSocket; |
422 | 0 | struct sockaddr_storage HerAddress; |
423 | 0 | fd_set sockSet; |
424 | 0 | int res, i; |
425 | 0 | int nSock = 0; |
426 | 0 | socklen_t length[2]; |
427 | 0 | BOOL continueServing; |
428 | | |
429 | 0 | if (CreateSocket(*PortNumber, &listenSocket[nSock], &length[nSock], |
430 | 0 | AF_INET) == 0) { |
431 | 0 | nSock++; |
432 | |
|
433 | 0 | } |
434 | 0 | if (CreateSocket(*PortNumber, &listenSocket[nSock], &length[nSock], |
435 | 0 | AF_INET6) == 0) { |
436 | 0 | nSock++; |
437 | 0 | } |
438 | 0 | if (nSock == 0) { |
439 | 0 | printf("Create TPM command service socket fail\n"); |
440 | 0 | return -1; |
441 | 0 | } |
442 | 0 | maxListenSocket = listenSocket[0]; |
443 | 0 | if (nSock == 2 && listenSocket[1] > maxListenSocket) { |
444 | 0 | maxListenSocket = listenSocket[1]; |
445 | 0 | } |
446 | | |
447 | | // Loop accepting connections one-by-one until we are killed or asked to stop |
448 | | // Note the TPM command service is single-threaded so we don't listen for |
449 | | // a new connection until the prior connection drops. |
450 | 0 | do |
451 | 0 | { |
452 | 0 | printf("TPM command server listening on port %d\n", *PortNumber); |
453 | | |
454 | | // Select both IPv4 and IPv6 sockets or whatever is available |
455 | 0 | FD_ZERO(&sockSet); |
456 | 0 | FD_SET(listenSocket[0], &sockSet); |
457 | 0 | if (nSock == 2) |
458 | 0 | FD_SET(listenSocket[1], &sockSet); |
459 | 0 | do { |
460 | 0 | res = select(maxListenSocket + 1, &sockSet, NULL, NULL, NULL); |
461 | 0 | } while ((res == -1) && (errno == EINTR)); |
462 | 0 | if (res == -1) { |
463 | 0 | printf("TPM command server select error. Error is %d %s\n", errno, |
464 | 0 | strerror(errno)); |
465 | 0 | return -1; |
466 | 0 | } |
467 | | |
468 | 0 | for (i = 0; i < nSock; i++) { |
469 | 0 | int ipver = IPVER(length[i]); |
470 | |
|
471 | 0 | if (!FD_ISSET(listenSocket[i], &sockSet)) |
472 | 0 | continue; |
473 | | // blocking accept |
474 | 0 | serverSocket = accept(listenSocket[i], |
475 | 0 | (struct sockaddr*) &HerAddress, |
476 | 0 | &length[i]); |
477 | 0 | if(serverSocket < 0) |
478 | 0 | { |
479 | 0 | printf("TPM server IPv%d Accept error. Error is %d %s\n", |
480 | 0 | ipver, errno, strerror(errno)); |
481 | 0 | return -1; |
482 | 0 | }; |
483 | 0 | printf("Command IPv%d client accepted\n", ipver); |
484 | | |
485 | | // normal behavior on client disconnection is to wait for a new |
486 | | // client to connect |
487 | 0 | continueServing = TpmServer(serverSocket); |
488 | 0 | close(serverSocket); |
489 | 0 | serverSocket = -1; |
490 | 0 | } |
491 | 0 | } |
492 | 0 | while(continueServing); |
493 | | |
494 | 0 | return 0; |
495 | 0 | } |
496 | | |
497 | | // D.3.3.6. StartTcpServer() |
498 | | |
499 | | // Main entry-point to the TCP server. The server listens on port specified. Note that there is no |
500 | | // way to specify the network interface in this implementation. |
501 | | |
502 | | int |
503 | | StartTcpServer( |
504 | | int *PortNumber, |
505 | | int *PortNumberPlatform |
506 | | ) |
507 | 0 | { |
508 | 0 | int res; |
509 | | |
510 | | // Start Platform Signal Processing Service |
511 | 0 | res = PlatformSignalService(PortNumberPlatform); |
512 | 0 | if (res != 0) |
513 | 0 | { |
514 | 0 | printf("PlatformSignalService failed\n"); |
515 | 0 | return res; |
516 | 0 | } |
517 | | |
518 | | // Start Regular/DRTM TPM command service |
519 | 0 | res = RegularCommandService(PortNumber); |
520 | 0 | if (res != 0) |
521 | 0 | { |
522 | 0 | printf("RegularCommandService failed\n"); |
523 | 0 | return res; |
524 | 0 | } |
525 | | |
526 | 0 | return 0; |
527 | 0 | } |
528 | | |
529 | | // D.3.3.7. ReadBytes() |
530 | | // This function reads the indicated number of bytes (NumBytes) into buffer from the indicated |
531 | | // socket. |
532 | | |
533 | | BOOL |
534 | | ReadBytes( |
535 | | SOCKET s, |
536 | | char *buffer, |
537 | | int NumBytes |
538 | | ) |
539 | 46.7k | { |
540 | 46.7k | int res; |
541 | 46.7k | int numGot = 0; |
542 | | |
543 | 89.5k | while(numGot<NumBytes) |
544 | 42.9k | { |
545 | 42.9k | res = read(s, buffer+numGot, NumBytes-numGot); |
546 | 42.9k | if(res <= 0) |
547 | 196 | { |
548 | 196 | printf("read() error. Error is %d %s\n", errno, strerror(errno)); |
549 | 196 | return FALSE; |
550 | 196 | } |
551 | 42.7k | if(res==0) |
552 | 0 | { |
553 | 0 | return FALSE; |
554 | 0 | } |
555 | 42.7k | numGot+=res; |
556 | 42.7k | } |
557 | 46.5k | return TRUE; |
558 | 46.7k | } |
559 | | |
560 | | // D.3.3.8. WriteBytes() |
561 | | // This function will send the indicated number of bytes (NumBytes) to the indicated socket |
562 | | |
563 | | BOOL |
564 | | WriteBytes( |
565 | | SOCKET s, |
566 | | char *buffer, |
567 | | int NumBytes |
568 | | ) |
569 | 0 | { |
570 | 0 | int res; |
571 | 0 | int numSent = 0; |
572 | 0 | while(numSent<NumBytes) |
573 | 0 | { |
574 | 0 | res = write(s, buffer+numSent, NumBytes-numSent); |
575 | 0 | if(res == 0) |
576 | 0 | { |
577 | 0 | printf("write() error. Error is %d %s\n", errno, strerror(errno)); |
578 | 0 | return FALSE; |
579 | 0 | } |
580 | 0 | numSent+=res; |
581 | 0 | } |
582 | 0 | return TRUE; |
583 | 0 | } |
584 | | |
585 | | // D.3.3.9. WriteUINT32() |
586 | | // Send 4 bytes containing hton(1) |
587 | | |
588 | | BOOL |
589 | | WriteUINT32( |
590 | | SOCKET s, |
591 | | UINT32 val |
592 | | ) |
593 | 0 | { |
594 | 0 | UINT32 netVal = htonl(val); |
595 | 0 | return WriteBytes(s, (char*) &netVal, 4); |
596 | 0 | } |
597 | | |
598 | | // D.3.3.10. ReadVarBytes() |
599 | | // Get a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte |
600 | | // order (big-endian). |
601 | | |
602 | | BOOL |
603 | | ReadVarBytes( |
604 | | SOCKET s, |
605 | | char *buffer, |
606 | | UINT32 *BytesReceived, |
607 | | int MaxLen |
608 | | ) |
609 | 10.4k | { |
610 | 10.4k | int length; |
611 | 10.4k | BOOL res; |
612 | | |
613 | 10.4k | res = ReadBytes(s, (char*) &length, 4); |
614 | 10.4k | if(!res) return res; |
615 | 10.4k | length = ntohl(length); |
616 | 10.4k | *BytesReceived = length; |
617 | 10.4k | if(length>MaxLen) |
618 | 4 | { |
619 | 4 | printf("Buffer too big. Client says %d\n", length); |
620 | 4 | return FALSE; |
621 | 4 | } |
622 | 10.4k | if(length==0) return TRUE; |
623 | 9.74k | res = ReadBytes(s, buffer, length); |
624 | 9.74k | if(!res) return res; |
625 | 9.71k | return TRUE; |
626 | 9.74k | } |
627 | | |
628 | | // D.3.3.11. WriteVarBytes() |
629 | | // Send a UINT32-length-prepended binary array. Note that the 4-byte length is in network byte |
630 | | // order (big-endian). |
631 | | |
632 | | BOOL |
633 | | WriteVarBytes( |
634 | | SOCKET s, |
635 | | char *buffer, |
636 | | int BytesToSend |
637 | | ) |
638 | 0 | { |
639 | 0 | UINT32 netLength = htonl(BytesToSend); |
640 | 0 | BOOL res; |
641 | | |
642 | 0 | res = WriteBytes(s, (char*) &netLength, 4); |
643 | 0 | if(!res) return res; |
644 | 0 | res = WriteBytes(s, buffer, BytesToSend); |
645 | 0 | if(!res) return res; |
646 | 0 | return TRUE; |
647 | 0 | } |
648 | | |
649 | | // D.3.3.12. TpmServer() |
650 | | // Processing incoming TPM command requests using the protocol / interface defined above. |
651 | | |
652 | | BOOL |
653 | | TpmServer( |
654 | | SOCKET s |
655 | | ) |
656 | 254 | { |
657 | 254 | UINT32 length; |
658 | 254 | UINT32 Command; |
659 | 254 | BYTE locality; |
660 | 254 | BOOL ok; |
661 | 254 | int result; |
662 | 254 | int clientVersion; |
663 | 254 | _IN_BUFFER InBuffer; |
664 | 254 | _OUT_BUFFER OutBuffer; |
665 | | |
666 | 254 | for(;;) |
667 | 16.3k | { |
668 | 16.3k | ok = ReadBytes(s, (char*) &Command, 4); |
669 | | // client disconnected (or other error). We stop processing this client |
670 | | // and return to our caller who can stop the server or listen for another |
671 | | // connection. |
672 | 16.3k | if(!ok) |
673 | 130 | return TRUE; |
674 | 16.2k | Command = ntohl(Command); |
675 | 16.2k | switch(Command) |
676 | 16.2k | { |
677 | 3.05k | case TPM_SIGNAL_HASH_START: |
678 | 3.05k | _rpc__Signal_Hash_Start(); |
679 | 3.05k | break; |
680 | | |
681 | 2.34k | case TPM_SIGNAL_HASH_END: |
682 | 2.34k | _rpc__Signal_HashEnd(); |
683 | 2.34k | break; |
684 | | |
685 | 606 | case TPM_SIGNAL_HASH_DATA: |
686 | 606 | ok = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER); |
687 | 606 | if(!ok) return TRUE; |
688 | 602 | InBuffer.Buffer = (BYTE*) InputBuffer; |
689 | 602 | InBuffer.BufferSize = length; |
690 | 602 | _rpc__Signal_Hash_Data(InBuffer); |
691 | 602 | break; |
692 | | |
693 | 9.84k | case TPM_SEND_COMMAND: |
694 | 9.84k | ok = ReadBytes(s, (char*) &locality, 1); |
695 | 9.84k | if(!ok) |
696 | 8 | return TRUE; |
697 | | |
698 | 9.84k | ok = ReadVarBytes(s, InputBuffer, &length, MAX_BUFFER); |
699 | 9.84k | if(!ok) |
700 | 58 | return TRUE; |
701 | 9.78k | InBuffer.Buffer = (BYTE*) InputBuffer; |
702 | 9.78k | InBuffer.BufferSize = length; |
703 | 9.78k | OutBuffer.BufferSize = MAX_BUFFER; |
704 | 9.78k | OutBuffer.Buffer = (_OUTPUT_BUFFER) OutputBuffer; |
705 | | // record the number of bytes in the command if it is the largest |
706 | | // we have seen so far. |
707 | 9.78k | if(InBuffer.BufferSize > CommandResponseSizes.largestCommandSize) |
708 | 5 | { |
709 | 5 | CommandResponseSizes.largestCommandSize = InBuffer.BufferSize; |
710 | 5 | memcpy(&CommandResponseSizes.largestCommand, |
711 | 5 | &InputBuffer[6], sizeof(UINT32)); |
712 | 5 | } |
713 | | |
714 | 9.78k | _rpc__Send_Command(locality, InBuffer, &OutBuffer); |
715 | | // record the number of bytes in the response if it is the largest |
716 | | // we have seen so far. |
717 | 9.78k | if(OutBuffer.BufferSize > CommandResponseSizes.largestResponseSize) |
718 | 1 | { |
719 | 1 | CommandResponseSizes.largestResponseSize |
720 | 1 | = OutBuffer.BufferSize; |
721 | 1 | memcpy(&CommandResponseSizes.largestResponse, |
722 | 1 | &OutputBuffer[6], sizeof(UINT32)); |
723 | 1 | } |
724 | | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
725 | | ok = WriteVarBytes(s, |
726 | | (char*) OutBuffer.Buffer, |
727 | | OutBuffer.BufferSize); |
728 | | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ |
729 | 9.78k | if(!ok) |
730 | 0 | return TRUE; |
731 | 9.78k | break; |
732 | | |
733 | 9.78k | case TPM_REMOTE_HANDSHAKE: |
734 | 177 | ok = ReadBytes(s, (char*)&clientVersion, 4); |
735 | 177 | if(!ok) |
736 | 0 | return TRUE; |
737 | 177 | if( clientVersion == 0 ) |
738 | 1 | { |
739 | 1 | printf("Unsupported client version (0).\n"); |
740 | 1 | return TRUE; |
741 | 1 | } |
742 | | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
743 | | ok &= WriteUINT32(s, ServerVersion); |
744 | | ok &= WriteUINT32(s, |
745 | | tpmInRawMode | tpmPlatformAvailable | tpmSupportsPP); |
746 | | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ |
747 | 176 | break; |
748 | | |
749 | 176 | case TPM_SET_ALTERNATIVE_RESULT: |
750 | 176 | ok = ReadBytes(s, (char*)&result, 4); |
751 | 176 | if(!ok) |
752 | 0 | return TRUE; |
753 | | // Alternative result is not applicable to the simulator. |
754 | 176 | break; |
755 | | |
756 | 176 | case TPM_SESSION_END: |
757 | | // Client signaled end-of-session |
758 | 0 | return TRUE; |
759 | | |
760 | 0 | case TPM_STOP: |
761 | | // Client requested the simulator to exit |
762 | 0 | return FALSE; |
763 | 53 | default: |
764 | 53 | printf("Unrecognized TPM interface command %08x\n", Command); |
765 | 53 | return TRUE; |
766 | 16.2k | } |
767 | | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
768 | | ok = WriteUINT32(s,0); |
769 | | #endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ |
770 | 16.1k | if(!ok) |
771 | 0 | return TRUE; |
772 | 16.1k | } |
773 | 0 | return FALSE; |
774 | 254 | } |