2 * This file is part of the OpenPTS project.
4 * The Initial Developer of the Original Code is International
5 * Business Machines Corporation. Portions created by IBM
6 * Corporation are Copyright (C) 2010 International Business
7 * Machines Corporation. All Rights Reserved.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the Common Public License as published by
11 * IBM Corporation; either version 1 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * Common Public License for more details.
19 * You should have received a copy of the Common Public License
20 * along with this program; if not, a copy can be viewed at
21 * http://www.opensource.org/licenses/cpl1.0.php.
26 * \brief TCG IF-M protocol
27 * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
29 * cleanup 2011-04-26 SM
31 * 2011-06-20 SM - do not use sendfile()
32 * IF-M did not work with endfile.
33 * So, we allocate the memory for the whole data.
34 * If platform uses Linux-IMA with HUGE events. this could be a problem.
44 #include <sys/types.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
52 #include <sys/sendfile.h>
58 #define MAX_TLV_MESSAGE_LENGTH 5120000
62 // 2011-02-24 SM make check => pass
63 // 2011-04-01 SM sendfile not work to new ptsc, too fast? <= wrap read/write
64 // 2011-04-07 SM sendfile not work aggain, RIMM_SET
68 #define SENDFILE_BUF_SIZE 4096
70 // http://linux.die.net/man/2/sendfile
71 // sendfile - transfer data between file descriptors
72 ssize_t my_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
73 char buf[SENDFILE_BUF_SIZE];
78 DEBUG_IFM("my_sendfile(), size=%d ############################\n", count);
83 if ((count - sum) > SENDFILE_BUF_SIZE) {
84 read_size = SENDFILE_BUF_SIZE;
86 read_size = count - sum;
90 read_size = wrapRead(in_fd, buf, read_size);
97 write_size = wrapWrite(out_fd, buf, read_size);
104 if (write_size != read_size) {
111 } while (sum < (ssize_t) count);
115 #define sendfile my_sendfile
116 #endif // !HAVE_SENDFILE
119 * Copy file date to given buffer
121 ssize_t copyfile(BYTE *buf, int in_fd, size_t count) {
125 DEBUG_IFM("copyfile(), size=%d ############################\n", count);
130 if ((count - ptr) > SENDFILE_BUF_SIZE) {
131 read_size = SENDFILE_BUF_SIZE;
133 read_size = count - ptr;
137 read_size = wrapRead(in_fd, &buf[ptr], read_size);
143 } while (ptr < (ssize_t) count);
149 * read IF-M PTS message (standalone)
151 * This just fill the PTS_IF_M_Attribute structure.
152 * The received packet is parsed by in ptscd.c
154 * TODO 2011-04-04 socket -> STDIN
156 PTS_IF_M_Attribute *readPtsTlv(int fdin) {
162 PTS_Byte * read_msg = NULL;
163 PTS_IF_M_Attribute *read_tlv = NULL; // Host Byte Order
165 DEBUG_CAL("readPtsTlvFromSock - start\n");
169 /* malloc TLV for read */
170 read_tlv = (PTS_IF_M_Attribute *)malloc(sizeof(PTS_IF_M_Attribute));
171 if (read_tlv == NULL) {
175 memset(read_tlv, 0, sizeof(PTS_IF_M_Attribute));
177 /* read IF-M header */
178 rc = wrapRead(fdin, head, 12);
180 ERROR("sock read fail. probably end of the handshake\n");
184 // copy buf to PTS_IF_M_Attribute (NBO)
185 memcpy(read_tlv, head, 12);
186 // Convert NBO to Host byte order
187 read_tlv->type = ntohl(read_tlv->type);
188 read_tlv->length = ntohl(read_tlv->length);
191 TODO("IF-M type : 0x%02x%02x%02x%02x (NBO)",
192 head[4], head[5], head[6], head[7]);
193 TODO("IF-M length: 0x%02x%02x%02x%02x (NBO) %d",
194 head[8], head[9], head[10], head[11], read_tlv->length);
197 /* check the length */
198 if (read_tlv->length > MAX_TLV_MESSAGE_LENGTH) {
199 ERROR("read_tlv->length = %d (0x%X)> %d\n",
200 read_tlv->length, read_tlv->length, MAX_TLV_MESSAGE_LENGTH);
205 rest = read_tlv->length;
207 read_msg = (PTS_Byte *)malloc(rest + 1);
208 if (read_msg == NULL) {
209 ERROR("no memory (size = %d)\n", rest +1);
214 len = wrapRead(fdin, &read_msg[ptr], rest);
224 // TODO check timeout
227 read_msg[read_tlv->length] = 0;
228 read_tlv->value = read_msg;
230 read_tlv->value = NULL;
234 DEBUG_IFM("IF-M read, type=0x%08x, length=%d\n",
235 read_tlv->type, read_tlv->length);
236 DEBUG_CAL("readPtsTlvFromSock - done\n");
238 // NOTE read_tlv->value may contains MBO structure.
242 // if (read_msg != NULL) free(read_msg);
243 if (read_tlv != NULL) freePtsTlv(read_tlv);
249 * free PTS_IF_M_Attribute
251 void freePtsTlv(PTS_IF_M_Attribute *tlv) {
257 if (tlv->value != NULL) {
270 * malloc TLV buffer and fill the header
271 * return ptr of buffer
273 BYTE *getTlvBuffer(int type, int length) {
275 PTS_IF_M_Attribute *write_tlv;
277 if ((buf = malloc(12 + length)) == NULL) {
281 /* setup TLV header */
282 write_tlv = (PTS_IF_M_Attribute *)buf;
283 write_tlv->flags = 0;
284 write_tlv->vid[0] = (TNC_VENDORID_OPENPTS >> 16) & 0xff;
285 write_tlv->vid[1] = (TNC_VENDORID_OPENPTS >> 8) & 0xff;
286 write_tlv->vid[2] = TNC_VENDORID_OPENPTS & 0xff;
287 write_tlv->type = htonl(type);
288 write_tlv->length = htonl(length);
294 * get IF-M PTS message (TNC)
295 * return *msg (Network Byte Order)
298 BYTE* getPtsTlvMessage(OPENPTS_CONTEXT *ctx, int type, int *len) {
300 OPENPTS_CONFIG *conf;
301 UINT32 length = 0; // endian of host
307 int fsize[MAX_RM_NUM];
309 int count[MAX_RM_NUM];
310 struct stat st[MAX_RM_NUM];
314 DEBUG("writePtsTlvToSock - start\n");
318 ERROR("ctx is NULL\n");
323 ERROR("conf is NULL\n");
328 for (i = 0; i < MAX_RM_NUM; i++) {
336 /* Collector <-- Verifier Simple requests (no value)*/
337 case REQUEST_TPM_PUBKEY:
338 case REQUEST_INTEGRITY_REPORT:
339 case REQUEST_RIMM_SET:
340 case REQUEST_NEW_RIMM_SET:
341 case VERIFICATION_RESULT: // TODO
343 case REQUEST_AIDE_DATABASE:
345 buf = getTlvBuffer(type, 0);
346 if (buf == NULL) goto error;
349 /* Collector <-> Verifier */
350 case OPENPTS_CAPABILITIES:
351 length = sizeof(OPENPTS_IF_M_Capability);
353 buf = getTlvBuffer(type, length);
354 if (buf == NULL) goto error;
358 memcpy(&buf[ptr + 0], &ctx->conf->pts_flag, 4);
359 memcpy(&buf[ptr + 4], &ctx->conf->tpm_version, 4);
360 memcpy(&buf[ptr + 8], &ctx->conf->tss_version, 4);
361 memcpy(&buf[ptr + 12], &ctx->conf->pts_version, 4);
362 /* Send Platform UUID, ctx->uuid */
363 memcpy(&buf[ptr + 16], ctx->conf->uuid->uuid, 16);
366 if (ctx->conf->rm_uuid == NULL) {
367 // TODO verifier does not have Rm UUID. just send Verifier's UUID
368 DEBUG("writePtsTlvToSock() RM uuid is NULL, => send platform UUID\n");
369 memcpy(&buf[ptr + 32], ctx->conf->uuid->uuid, 16);
370 } else if (ctx->conf->rm_uuid->uuid == NULL) {
372 DEBUG("writePtsTlvToSock() RM uuid is NULL, => send platform UUID, file = %s\n",
373 ctx->conf->rm_uuid->filename);
375 memcpy(&buf[ptr + 32], ctx->conf->uuid->uuid, 16);
377 memcpy(&buf[ptr + 32], ctx->conf->rm_uuid->uuid, 16);
383 /* Collector --> Verifier */
385 if ((ctx->conf->pubkey != NULL) && (ctx->conf->pubkey_length > 0)) {
387 length = ctx->conf->pubkey_length;
388 buf = getTlvBuffer(type, length);
389 if (buf == NULL) goto error;
392 memcpy(&buf[12], ctx->conf->pubkey, ctx->conf->pubkey_length);
395 /* PUB key is missing */
396 ERROR("writePtsTlvToSock - PUBKEY blob is missing\n");
397 ctx->ifm_errno = PTS_FATAL;
398 ctx->ifm_strerror = smalloc("Piblic key is missing");
404 /* Collector --> Verifier */
406 /* open/read RM files */
407 length = 4; // for RM num
408 for (i = 0; i < conf->rm_num; i++) {
410 fd[i] = open(ctx->conf->rm_filename[i], O_RDONLY);
412 // 20101124 SM must be a fullpath for Daemon
413 ERROR("Can't open RM[%d] files, %s\n",
414 i, ctx->conf->rm_filename[i]);
415 /* send Error massage */
416 ctx->ifm_errno = PTS_FATAL;
418 smalloc("Manifest not found, initialize the collector");
422 fstat(fd[i], &st[i]);
423 fsize[i] = st[i].st_size;
424 length += 4 + fsize[i];
426 DEBUG_IFM("writePtsTlv - RIMM_SET, length = %d", length);
428 buf = getTlvBuffer(type, length);
429 if (buf == NULL) goto error;
433 num = htonl(conf->rm_num);
434 memcpy(&buf[ptr], (BYTE *)&num, 4);
437 for (i = 0; i< conf->rm_num; i++) {
439 num = htonl(fsize[i]);
440 // rc = wrapWrite(fdout, (BYTE *)&num, 4);
441 memcpy(&buf[ptr], (BYTE *)&num, 4);
444 count[i] = copyfile(&buf[ptr], fd[i], fsize[i]);
445 if (count[i] != fsize[i]) {
446 ERROR("copyfile() faild %d != %d\n", count[i], fsize[i]);
453 DEBUG_IFM("RM[%d] len = %d\n", i, count[i]);
457 /* Collector --> Verifier */
460 if (conf->newrm_num == 0) {
461 /* New RM is missing => send Error massage */
462 ctx->ifm_errno = PTS_FATAL;
463 ctx->ifm_strerror = smalloc("New Manifest not found, check the collector");
467 /* setup TLV header (2/2) */
468 length = 16 + 4; // UUID + num
469 for (i = 0; i < conf->newrm_num; i++) {
470 fd[i] = open(ctx->conf->newrm_filename[i], O_RDONLY);
472 // 20101124 SM must be a fullpath for Daemon
473 ERROR("Error RM file, %s not found\n", ctx->conf->newrm_filename[i]);
474 /* send Error massage */
475 ctx->ifm_errno = PTS_FATAL;
477 smalloc("New Manifest file not found, check the collector");
481 fstat(fd[i], &st[i]);
482 fsize[i] = st[i].st_size;
483 length += 4 + fsize[i];
487 DEBUG_IFM("writePtsTlv - NEW_RIMM_SET, length = %d", length);
489 buf = getTlvBuffer(type, length);
490 if (buf == NULL) goto error;
495 memcpy(&buf[ptr], ctx->conf->newrm_uuid->uuid, 16);
499 num = htonl(conf->newrm_num);
500 memcpy(&buf[ptr], (BYTE *)&num, 4);
503 for (i = 0; i< conf->newrm_num; i++) {
505 num = htonl(fsize[i]);
506 memcpy(&buf[ptr], (BYTE *)&num, 4);
509 count[i] = copyfile(&buf[ptr], fd[i], fsize[i]);
514 DEBUG_IFM("RM[%d] len = %d\n", i, count[i]);
519 length = ctx->nonce->nonce_length;
520 buf = getTlvBuffer(type, length);
521 if (buf == NULL) goto error;
522 memcpy(&buf[12], ctx->nonce->nonce, length);
525 case INTEGRITY_REPORT:
526 /* generate new IR */
528 if (rc != PTS_SUCCESS) {
529 ERROR("writePtsTlvToSock - gen IR failed\n");
530 /* send Error massage */
531 ctx->ifm_errno = PTS_FATAL;
532 ctx->ifm_strerror = smalloc("Generation of IR failed");
536 /* check the IR size */
537 fd[0] = open(ctx->conf->ir_filename, O_RDONLY); // TODO(munetoh)
539 ERROR("Error %s not found\n", ctx->conf->ir_filename);
540 /* send Error massage */
541 ctx->ifm_errno = PTS_FATAL;
542 ctx->ifm_strerror = smalloc("IR file is missing");
546 fstat(fd[0], &st[0]);
547 fsize[0] = st[0].st_size;
554 buf = getTlvBuffer(type, length);
555 if (buf == NULL) goto error;
558 fd[0] = open(ctx->conf->ir_filename, O_RDONLY);
559 count[0] = copyfile(&buf[ptr], fd[0], fsize[0]);
560 if (count[0] != fsize[0]) {
561 ERROR("copyfile() faild %d != %d\n", count[0], fsize[0]);
571 case AIDE_DATABASE: /* AIDE DATABASE: C -> V */
572 /* setup TLV header (2/2) */
574 if (ctx->conf->aide_database_filename == NULL) {
576 DEBUG("writePtsTlvToSock - Error AIDE DB file is not configured\n");
577 ctx->ifm_errno = PTS_FATAL;
578 ctx->ifm_strerror = smalloc("AIDE DB file is not configured");
581 fd[0] = open(ctx->conf->aide_database_filename, O_RDONLY);
583 /* AIDE file is missing, erorr */
584 ERROR("writePtsTlvToSock - Error AIDE DB file, %s not found\n",
585 ctx->conf->aide_database_filename);
586 /* send Error massage */
587 ctx->ifm_errno = PTS_FATAL;
588 ctx->ifm_strerror = smalloc("AIDE file not found");
592 fstat(fd[0], &st[0]);
593 fsize[0] = st[0].st_size;
601 buf = getTlvBuffer(type, length);
602 if (buf == NULL) goto error;
608 fd[0] = open(ctx->conf->aide_database_filename, O_RDONLY);
609 count[0] = copyfile(&buf[ptr], fd[0], fsize[0]);
610 if (count[0] != fsize[0]) {
611 ERROR("copyfile() faild %d != %d\n", count[0], fsize[0]);
618 DEBUG_IFM("writePtsTlv - AIDE_DATABASE, file = %s\n",
619 ctx->conf->aide_database_filename);
620 // DEBUG_IFM("AIDE DATABASE len = %d\n", count[0]);
622 DEBUG_IFM("writePtsTlv - AIDE_DATABASE, length = %d", length);
624 #endif // CONFIG_AIDE
627 case DH_NONCE_PARAMETERS_REQUEST: /* DH: Initiator -> Respondor */
628 /* setup TLV header (2/2) */
630 buf = getTlvBuffer(type, length);
631 if (buf == NULL) goto error;
635 buf[0] = ctx->nonce->req->reserved;
636 buf[1] = ctx->nonce->req->min_nonce_len;
637 memcpy(&buf[ptr], buf, 2);
640 nbou16 = htons(ctx->nonce->req->dh_group_set);
641 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
644 DEBUG_IFM("writePtsTlv - DH_NONCE_PARAMETERS_REQUEST, length = %d", length);
647 case DH_NONCE_PARAMETORS_RESPONSE: /* DH: IRespondor -> Initiator */
648 /* setup TLV header (2/2) */
651 ctx->nonce->respondor_nonce_length +
652 ctx->nonce->pubkey_length;
654 buf = getTlvBuffer(type, length);
655 if (buf == NULL) goto error;
659 buf[0] = ctx->nonce->res->reserved[0];
660 buf[1] = ctx->nonce->res->reserved[1];
661 buf[2] = ctx->nonce->res->reserved[2];
662 buf[3] = ctx->nonce->res->nonce_length;
663 memcpy(&buf[ptr], buf, 4);
666 nbou16 = htons(ctx->nonce->res->selected_dh_group);
667 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
670 nbou16 = htons(ctx->nonce->res->hash_alg_set);
671 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
677 ctx->nonce->respondor_nonce,
678 ctx->nonce->respondor_nonce_length);
679 ptr += ctx->nonce->respondor_nonce_length;
681 /* send dh_respondor_public */
685 ctx->nonce->pubkey_length);
686 ptr += ctx->nonce->pubkey_length;
688 DEBUG_IFM("writePtsTlv - DH_NONCE_PARAMETORS_RESPONSE, length = %d", length);
691 case DH_NONCE_FINISH: /* DH: Initiator -> Respondor */
692 /* setup TLV header (2/2) */
695 ctx->nonce->initiator_nonce_length +
696 ctx->nonce->pubkey_length;
698 buf = getTlvBuffer(type, length);
699 if (buf == NULL) goto error;
702 /* Send IF-M TLV header */
705 buf[0] = ctx->nonce->fin->reserved = 0;
706 buf[1] = ctx->nonce->fin->nonce_length = ctx->nonce->initiator_nonce_length;
707 memcpy(&buf[ptr], (BYTE *)&buf, 2);
710 nbou16 = htons(ctx->nonce->fin->selected_hash_alg);
711 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
714 /* send dh_initiator_pubkey */
715 memcpy(&buf[ptr], ctx->nonce->pubkey, ctx->nonce->pubkey_length);
716 ptr += ctx->nonce->pubkey_length;
718 /* send dh_initiator_nonce */
721 ctx->nonce->initiator_nonce,
722 ctx->nonce->initiator_nonce_length);
723 ptr += ctx->nonce->initiator_nonce_length;
725 DEBUG_IFM("writePtsTlv - DH_NONCE_FINISH, length = %d", length);
730 /* setup TLV header (2/2) */
732 if (ctx->ifm_strerror != NULL) {
733 length = 4 + 4 + strlen(ctx->ifm_strerror);
738 buf = getTlvBuffer(type, length);
739 if (buf == NULL) goto error;
746 /* send error code */
747 ifm_errno = htonl(ctx->ifm_errno);
748 memcpy(&buf[ptr], (BYTE *)&ifm_errno, 4);
753 if (ctx->ifm_strerror != NULL) {
754 len = strlen(ctx->ifm_strerror);
756 memcpy(&buf[ptr], (BYTE *)&size, 4);
759 memcpy(&buf[ptr], (BYTE *)&ctx->ifm_strerror, len);
762 free(ctx->ifm_strerror);
765 memcpy(&buf[ptr], (BYTE *)&size, 4);
770 DEBUG_IFM("writePtsTlv - OPENPTS_ERROR, length = %d", length);
775 ERROR("BAD IF-M OPENPTS MESSAGE TYPE, type=0x%x\n", type);
779 DEBUG_IFM("IF-M message, type=0x%x, length=%d\n",
781 DEBUG("writePtsTlvToSock - done\n");
788 for (i = 0; i < MAX_RM_NUM; i++) {
789 if (fd[i] >= 0) close(fd[i]);
797 * write IF-M PTS message ()
799 * we are using sendfile() here and send the data steb by step.
800 * but IF-M of IMC/IMV version need to create whole blob to send.
802 * v0.2.4 - sendfile() not work with ptsc. use my_sendfile()
805 * length of write data
808 int writePtsTlv(OPENPTS_CONTEXT *ctx, int fdout, int type) {
814 OPENPTS_CONFIG *conf;
818 ERROR("ctx is NULL\n");
823 ERROR("conf is NULL\n");
826 if (conf->uuid == NULL) {
827 ERROR("writePtsTlvToSock() - conf->uuid is NULL\n");
831 DEBUG_CAL("writePtsTlvToSock - start\n");
833 message = getPtsTlvMessage(ctx, type, &length);
834 if (message != NULL) {
835 rc = wrapWrite(fdout, message, length);
836 DEBUG_IFM("writePtsTlv - type=%d, length = %d", type, length);
841 DEBUG_CAL("writePtsTlvToSock - done\n");
848 ERROR("writePtsTlvToSock()\n");
851 len = writePtsTlv(ctx, fdout, OPENPTS_ERROR);
853 ERROR("send OPENPTS_ERROR was faild");