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 2012-01-05 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
60 void htoncl(uint8_t *ptr, uint32_t value) {
63 LOG(LOG_ERR, "null input");
66 /* Convert value to network endian */
67 *ptr++ = (uint8_t)(value >> 24);
68 *ptr++ = (uint8_t)(value >> 16);
69 *ptr++ = (uint8_t)(value >> 8);
70 *ptr = (uint8_t)(value);
73 uint32_t nctohl(uint8_t *ptr) {
76 LOG(LOG_ERR, "null input");
80 return ((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) |
81 ((uint32_t)ptr[2] << 8) | ptr[3];
85 // 2011-02-24 SM make check => pass
86 // 2011-04-01 SM sendfile not work to new ptsc, too fast? <= wrap read/write
87 // 2011-04-07 SM sendfile not work aggain, RIMM_SET
91 #define SENDFILE_BUF_SIZE 4096
93 // http://linux.die.net/man/2/sendfile
94 // sendfile - transfer data between file descriptors
96 ssize_t my_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) {
97 char buf[SENDFILE_BUF_SIZE];
102 DEBUG_IFM("my_sendfile(), size=%d ############################\n", count);
106 if ((count - sum) > SENDFILE_BUF_SIZE) {
107 read_size = SENDFILE_BUF_SIZE;
109 read_size = count - sum;
113 read_size = wrapRead(in_fd, buf, read_size);
120 write_size = wrapWrite(out_fd, buf, read_size);
122 if (write_size < 0) {
127 if (write_size != read_size) {
134 } while (sum < (ssize_t) count);
138 #define sendfile my_sendfile
139 #endif // !HAVE_SENDFILE
142 * Copy file date to given buffer
144 ssize_t copyfile(BYTE *buf, int in_fd, size_t count) {
148 DEBUG_IFM("copyfile(), size=%d ############################\n", count);
152 LOG(LOG_ERR, "null input");
158 if ((count - ptr) > SENDFILE_BUF_SIZE) {
159 read_size = SENDFILE_BUF_SIZE;
161 read_size = count - ptr;
165 read_size = wrapRead(in_fd, &buf[ptr], read_size);
171 } while (ptr < (ssize_t) count);
177 * read IF-M PTS message (standalone)
179 * This just fill the PTS_IF_M_Attribute structure.
180 * The received packet is parsed by in ptscd.c
182 * TODO 2011-04-04 socket -> STDIN
184 PTS_IF_M_Attribute *readPtsTlv(int fdin) {
190 PTS_Byte * read_msg = NULL;
191 PTS_IF_M_Attribute *read_tlv = NULL; // Host Byte Order
193 DEBUG_CAL("readPtsTlvFromSock - start\n");
197 /* malloc TLV for read */
198 read_tlv = (PTS_IF_M_Attribute *)xmalloc(sizeof(PTS_IF_M_Attribute));
199 if (read_tlv == NULL) {
200 LOG(LOG_ERR, "no memory");
203 memset(read_tlv, 0, sizeof(PTS_IF_M_Attribute));
205 /* read IF-M header */
206 rc = wrapRead(fdin, head, 12);
208 DEBUG_IFM("sock read fail. probably end of the handshake\n");
212 /* copy buf to PTS_IF_M_Attribute (NBO) */
213 memcpy(read_tlv, head, 12);
214 /* Convert NBO to Host byte order */
215 read_tlv->type = ntohl(read_tlv->type);
216 read_tlv->length = ntohl(read_tlv->length);
218 /* check the length */
219 if (read_tlv->length > MAX_TLV_MESSAGE_LENGTH) {
220 LOG(LOG_ERR, "read_tlv->length = %d (0x%X)> %d\n",
221 read_tlv->length, read_tlv->length, MAX_TLV_MESSAGE_LENGTH);
226 rest = read_tlv->length;
228 read_msg = (PTS_Byte *)xmalloc(rest + 1);
229 if (read_msg == NULL) {
234 len = wrapRead(fdin, &read_msg[ptr], rest);
244 // TODO check timeout
247 read_msg[read_tlv->length] = 0;
248 read_tlv->value = read_msg;
250 read_tlv->value = NULL;
254 DEBUG_IFM("IF-M read, type=0x%08x, length=%d\n",
255 read_tlv->type, read_tlv->length);
256 DEBUG_CAL("readPtsTlvFromSock - done\n");
258 // NOTE read_tlv->value may contains MBO structure.
262 if (read_tlv != NULL) {
263 freePtsTlv(read_tlv);
270 * free PTS_IF_M_Attribute
272 void freePtsTlv(PTS_IF_M_Attribute *tlv) {
275 LOG(LOG_ERR, "null input");
280 if (tlv->value != NULL) {
287 /* TNC, libtnc ---------------------------------------------------------------*/
290 * malloc TLV buffer and fill the header
291 * return ptr of buffer
293 BYTE *getTlvBuffer(int type, int length) {
295 PTS_IF_M_Attribute *write_tlv;
297 if ((buf = xmalloc(12 + length)) == NULL) {
298 LOG(LOG_ERR, "no memory");
301 /* setup TLV header */
302 write_tlv = (PTS_IF_M_Attribute *)buf;
303 write_tlv->flags = 0;
304 write_tlv->vid[0] = (TNC_VENDORID_OPENPTS >> 16) & 0xff;
305 write_tlv->vid[1] = (TNC_VENDORID_OPENPTS >> 8) & 0xff;
306 write_tlv->vid[2] = TNC_VENDORID_OPENPTS & 0xff;
307 write_tlv->type = htonl(type);
308 write_tlv->length = htonl(length);
314 * get IF-M PTS message (TNC)
315 * return *msg (Network Byte Order)
318 BYTE* getPtsTlvMessage(OPENPTS_CONTEXT *ctx, int type, int *len) {
320 OPENPTS_CONFIG *conf;
321 UINT32 length = 0; // endian of host
326 int fsize[MAX_RM_NUM];
328 int count[MAX_RM_NUM];
329 struct stat st[MAX_RM_NUM];
332 DEBUG("writePtsTlvToSock - start\n");
336 LOG(LOG_ERR, "null input");
341 LOG(LOG_ERR, "null input");
346 for (i = 0; i < MAX_RM_NUM; i++) {
354 /* Collector <-- Verifier Simple requests (no value)*/
355 case REQUEST_TPM_PUBKEY:
356 case REQUEST_INTEGRITY_REPORT:
357 case REQUEST_RIMM_SET:
358 case REQUEST_NEW_RIMM_SET:
359 case VERIFICATION_RESULT: // TODO
361 case REQUEST_AIDE_DATABASE:
363 buf = getTlvBuffer(type, 0);
365 LOG(LOG_ERR, "getTlvBuffer() is null");
369 /* Collector <-> Verifier */
370 case OPENPTS_CAPABILITIES:
372 length = sizeof(OPENPTS_IF_M_Capability);
374 buf = getTlvBuffer(type, length);
376 LOG(LOG_ERR, "getTlvBuffer() is null");
382 memcpy(&buf[ptr + 0], &ctx->conf->pts_flag, 4);
383 memcpy(&buf[ptr + 4], &ctx->conf->tpm_version, 4);
384 memcpy(&buf[ptr + 8], &ctx->conf->tss_version, 4);
385 memcpy(&buf[ptr + 12], &ctx->conf->pts_version, 4);
386 /* Send Platform UUID, ctx->uuid */
387 memcpy(&buf[ptr + 16], ctx->conf->uuid->uuid, 16);
390 if (ctx->conf->rm_uuid == NULL) {
391 // TODO verifier does not have Rm UUID. just send Verifier's UUID
392 DEBUG("writePtsTlvToSock() RM uuid is NULL, => send platform UUID\n");
393 memcpy(&buf[ptr + 32], ctx->conf->uuid->uuid, 16);
394 } else if (ctx->conf->rm_uuid->uuid == NULL) {
396 DEBUG("writePtsTlvToSock() RM uuid is NULL, => send platform UUID, file = %s\n",
397 ctx->conf->rm_uuid->filename);
399 memcpy(&buf[ptr + 32], ctx->conf->uuid->uuid, 16);
401 memcpy(&buf[ptr + 32], ctx->conf->rm_uuid->uuid, 16);
404 if (isFlagSet(ctx->conf->pts_flag[0], OPENPTS_FLAG0_NEWRM_EXIST) &&
405 ctx->conf->newrm_uuid != NULL &&
406 ctx->conf->newrm_uuid->uuid != NULL) {
407 memcpy(&buf[ptr + 48], ctx->conf->newrm_uuid->uuid, 16);
409 DEBUG("New RM unavailable -> sending platform UUID");
410 memcpy(&buf[ptr + 48], ctx->conf->uuid->uuid, 16);
415 /* Collector --> Verifier (v0.2.5) */
416 case OPENPTS_CAPABILITIES_025:
418 length = sizeof(OPENPTS_IF_M_Capability_025);
420 buf = getTlvBuffer(OPENPTS_CAPABILITIES, length); // v0.2.5
422 LOG(LOG_ERR, "getTlvBuffer() is null");
428 memcpy(&buf[ptr + 0], &ctx->conf->pts_flag, 4);
429 memcpy(&buf[ptr + 4], &ctx->conf->tpm_version, 4);
430 memcpy(&buf[ptr + 8], &ctx->conf->tss_version, 4);
431 memcpy(&buf[ptr + 12], &ctx->conf->pts_version, 4);
432 /* Send Platform UUID, ctx->uuid */
433 memcpy(&buf[ptr + 16], ctx->conf->uuid->uuid, 16);
436 if (ctx->conf->rm_uuid == NULL) {
437 // TODO verifier does not have Rm UUID. just send Verifier's UUID
438 DEBUG("writePtsTlvToSock() RM uuid is NULL, => send platform UUID\n");
439 memcpy(&buf[ptr + 32], ctx->conf->uuid->uuid, 16);
440 } else if (ctx->conf->rm_uuid->uuid == NULL) {
442 DEBUG("writePtsTlvToSock() RM uuid is NULL, => send platform UUID, file = %s\n",
443 ctx->conf->rm_uuid->filename);
445 memcpy(&buf[ptr + 32], ctx->conf->uuid->uuid, 16);
447 memcpy(&buf[ptr + 32], ctx->conf->rm_uuid->uuid, 16);
451 /* Collector --> Verifier */
454 if ((ctx->conf->pubkey != NULL) && (ctx->conf->pubkey_length > 0)) {
456 length = ctx->conf->pubkey_length;
457 buf = getTlvBuffer(type, length);
459 LOG(LOG_ERR, "getTlvBuffer() is null");
464 memcpy(&buf[12], ctx->conf->pubkey, ctx->conf->pubkey_length);
467 /* PUB key is missing */
468 LOG(LOG_ERR, "writePtsTlvToSock - PUBKEY blob is missing\n");
469 ctx->ifm_errno = PTS_FATAL;
470 ctx->ifm_strerror = smalloc_assert("Public key is missing");
477 /* Collector --> Verifier */
480 /* open/read RM files */
481 length = 4; // for RM num
482 for (i = 0; i < conf->rm_num; i++) {
484 fd[i] = open(ctx->conf->rm_filename[i], O_RDONLY);
486 // 20101124 SM must be a fullpath for Daemon
487 LOG(LOG_ERR, "Can't open RM[%d] files, %s\n",
488 i, ctx->conf->rm_filename[i]);
489 /* send Error massage */
490 ctx->ifm_errno = PTS_FATAL;
492 smalloc_assert("Manifest not found, initialize the collector");
496 if (-1 == fstat(fd[i], &st[i])) {
497 LOG(LOG_ERR, "fstat failed with errno %d\n", errno);
500 fsize[i] = st[i].st_size;
501 length += 4 + fsize[i];
503 DEBUG_IFM("writePtsTlv - RIMM_SET, length = %d", length);
505 buf = getTlvBuffer(type, length);
506 if (buf == NULL) goto error;
510 num = htonl(conf->rm_num);
511 memcpy(&buf[ptr], (BYTE *)&num, 4);
514 for (i = 0; i< conf->rm_num; i++) {
516 num = htonl(fsize[i]);
517 // rc = wrapWrite(fdout, (BYTE *)&num, 4);
518 memcpy(&buf[ptr], (BYTE *)&num, 4);
521 count[i] = copyfile(&buf[ptr], fd[i], fsize[i]);
522 if (count[i] != fsize[i]) {
523 LOG(LOG_ERR, "copyfile() faild %d != %d\n", count[i], fsize[i]);
530 DEBUG_IFM("RM[%d] len = %d\n", i, count[i]);
535 /* Collector --> Verifier */
539 if (conf->newrm_num == 0) {
540 /* New RM is missing => send Error massage */
541 DEBUG_IFM("New RM is missing. send Error massage\n");
542 ctx->ifm_errno = PTS_FATAL;
543 ctx->ifm_strerror = smalloc_assert("New Manifest not found, check the collector");
547 /* setup TLV header (2/2) */
548 length = 16 + 4; // UUID + num
549 for (i = 0; i < conf->newrm_num; i++) {
550 fd[i] = open(ctx->conf->newrm_filename[i], O_RDONLY);
552 // 20101124 SM must be a fullpath for Daemon
553 LOG(LOG_ERR, "Error RM file, %s not found\n", ctx->conf->newrm_filename[i]);
554 /* send Error massage */
555 ctx->ifm_errno = PTS_FATAL;
557 smalloc_assert("New Manifest file not found, check the collector");
561 if (-1 == fstat(fd[i], &st[i])) {
562 LOG(LOG_ERR, "fstat failed with errno %d\n", errno);
565 fsize[i] = st[i].st_size;
566 length += 4 + fsize[i];
570 DEBUG_IFM("writePtsTlv - NEW_RIMM_SET, length = %d", length);
572 buf = getTlvBuffer(type, length);
574 LOG(LOG_ERR, "getTlvBuffer() is null");
581 memcpy(&buf[ptr], ctx->conf->newrm_uuid->uuid, 16);
585 num = htonl(conf->newrm_num);
586 memcpy(&buf[ptr], (BYTE *)&num, 4);
589 for (i = 0; i< conf->newrm_num; i++) {
591 num = htonl(fsize[i]);
592 memcpy(&buf[ptr], (BYTE *)&num, 4);
595 count[i] = copyfile(&buf[ptr], fd[i], fsize[i]);
600 DEBUG_IFM("RM[%d] len = %d\n", i, count[i]);
607 length = ctx->nonce->nonce_length;
608 buf = getTlvBuffer(type, length);
610 LOG(LOG_ERR, "getTlvBuffer() is null");
613 memcpy(&buf[12], ctx->nonce->nonce, length);
617 case INTEGRITY_REPORT:
619 /* generate new IR, giving us a file descriptor corresponding
620 to an already deleted file for added security - once the file
621 gets closed you lose the IR! */
622 rc = genIr(ctx, &fd[0]);
623 if (rc != PTS_SUCCESS) {
624 LOG(LOG_ERR, "writePtsTlvToSock - gen IR failed\n");
625 /* send Error massage */
626 ctx->ifm_errno = PTS_FATAL;
627 ctx->ifm_strerror = smalloc_assert("Generation of IR failed");
631 /* check the IR size */
632 if (-1 == fstat(fd[0], &st[0])) {
633 LOG(LOG_ERR, "fstat failed with errno %d\n", errno);
636 fsize[0] = st[0].st_size;
639 buf = getTlvBuffer(type, length);
641 LOG(LOG_ERR, "getTlvBuffer() is null");
646 if (-1 == lseek(fd[0], 0, SEEK_SET)) {
647 LOG(LOG_ERR, "Could not seek to start of %s (fd '%d')\n", ctx->conf->ir_filename, fd[0]);
651 count[0] = copyfile(&buf[ptr], fd[0], fsize[0]);
652 if (count[0] != fsize[0]) {
653 LOG(LOG_ERR, "copyfile() faild %d != %d\n", count[0], fsize[0]);
664 case AIDE_DATABASE: /* AIDE DATABASE: C -> V */
666 /* setup TLV header (2/2) */
668 if (ctx->conf->aide_database_filename == NULL) {
670 DEBUG("writePtsTlvToSock - Error AIDE DB file is not configured\n");
671 ctx->ifm_errno = PTS_FATAL;
672 ctx->ifm_strerror = smalloc_assert("AIDE DB file is not configured");
675 fd[0] = open(ctx->conf->aide_database_filename, O_RDONLY);
677 /* AIDE file is missing, erorr */
678 LOG(LOG_ERR, "writePtsTlvToSock - Error AIDE DB file, %s not found\n",
679 ctx->conf->aide_database_filename);
680 /* send Error massage */
681 ctx->ifm_errno = PTS_FATAL;
682 ctx->ifm_strerror = smalloc_assert("AIDE file not found");
686 if (-1 == fstat(fd[0], &st[0])) {
687 LOG(LOG_ERR, "fstat failed with errno %d\n", errno);
690 fsize[0] = st[0].st_size;
695 buf = getTlvBuffer(type, length);
697 LOG(LOG_ERR, "getTlvBuffer() is null");
705 count[0] = copyfile(&buf[ptr], fd[0], fsize[0]);
706 if (count[0] != fsize[0]) {
707 LOG(LOG_ERR, "copyfile() faild %d != %d\n", count[0], fsize[0]);
714 DEBUG_IFM("writePtsTlv - AIDE_DATABASE, file = %s\n",
715 ctx->conf->aide_database_filename);
716 // DEBUG_IFM("AIDE DATABASE len = %d\n", count[0]);
718 DEBUG_IFM("writePtsTlv - AIDE_DATABASE, length = %d", length);
721 #endif // CONFIG_AIDE
724 case DH_NONCE_PARAMETERS_REQUEST: /* DH: Initiator -> Respondor */
726 /* setup TLV header (2/2) */
728 buf = getTlvBuffer(type, length);
735 buf[0] = ctx->nonce->req->reserved;
736 buf[1] = ctx->nonce->req->min_nonce_len;
737 memcpy(&buf[ptr], buf, 2);
740 nbou16 = htons(ctx->nonce->req->dh_group_set);
741 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
744 DEBUG_IFM("writePtsTlv - DH_NONCE_PARAMETERS_REQUEST, length = %d", length);
748 case DH_NONCE_PARAMETORS_RESPONSE: /* DH: IRespondor -> Initiator */
750 /* setup TLV header (2/2) */
753 ctx->nonce->respondor_nonce_length +
754 ctx->nonce->pubkey_length;
756 buf = getTlvBuffer(type, length);
758 LOG(LOG_ERR, "getTlvBuffer() is null");
764 buf[0] = ctx->nonce->res->reserved[0];
765 buf[1] = ctx->nonce->res->reserved[1];
766 buf[2] = ctx->nonce->res->reserved[2];
767 buf[3] = ctx->nonce->res->nonce_length;
768 memcpy(&buf[ptr], buf, 4);
771 nbou16 = htons(ctx->nonce->res->selected_dh_group);
772 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
775 nbou16 = htons(ctx->nonce->res->hash_alg_set);
776 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
782 ctx->nonce->respondor_nonce,
783 ctx->nonce->respondor_nonce_length);
784 ptr += ctx->nonce->respondor_nonce_length;
786 /* send dh_respondor_public */
790 ctx->nonce->pubkey_length);
791 ptr += ctx->nonce->pubkey_length;
793 DEBUG_IFM("writePtsTlv - DH_NONCE_PARAMETORS_RESPONSE, length = %d", length);
797 case DH_NONCE_FINISH: /* DH: Initiator -> Respondor */
799 /* setup TLV header (2/2) */
802 ctx->nonce->initiator_nonce_length +
803 ctx->nonce->pubkey_length;
805 buf = getTlvBuffer(type, length);
807 LOG(LOG_ERR, "getTlvBuffer() is null");
812 /* Send IF-M TLV header */
815 buf[0] = ctx->nonce->fin->reserved = 0;
816 buf[1] = ctx->nonce->fin->nonce_length = ctx->nonce->initiator_nonce_length;
817 memcpy(&buf[ptr], (BYTE *)&buf, 2);
820 nbou16 = htons(ctx->nonce->fin->selected_hash_alg);
821 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
824 /* send dh_initiator_pubkey */
825 memcpy(&buf[ptr], ctx->nonce->pubkey, ctx->nonce->pubkey_length);
826 ptr += ctx->nonce->pubkey_length;
828 /* send dh_initiator_nonce */
831 ctx->nonce->initiator_nonce,
832 ctx->nonce->initiator_nonce_length);
833 ptr += ctx->nonce->initiator_nonce_length;
835 DEBUG_IFM("writePtsTlv - DH_NONCE_FINISH, length = %d", length);
841 /* setup TLV header (2/2) */
843 if (ctx->ifm_strerror != NULL) {
844 length = 4 + 4 + strlen(ctx->ifm_strerror);
849 buf = getTlvBuffer(type, length);
851 LOG(LOG_ERR, "getTlvBuffer() is null");
860 /* send error code */
861 ifm_errno = htonl(ctx->ifm_errno);
862 memcpy(&buf[ptr], (BYTE *)&ifm_errno, 4);
867 if (ctx->ifm_strerror != NULL) {
868 len = strlen(ctx->ifm_strerror);
870 memcpy(&buf[ptr], (BYTE *)&size, 4);
873 memcpy(&buf[ptr], (BYTE *)&ctx->ifm_strerror, len);
876 xfree(ctx->ifm_strerror);
879 memcpy(&buf[ptr], (BYTE *)&size, 4);
884 DEBUG_IFM("writePtsTlv - OPENPTS_ERROR, length = %d", length);
890 LOG(LOG_ERR, "BAD IF-M OPENPTS MESSAGE TYPE, type=0x%x\n", type);
894 DEBUG_IFM("IF-M message, type=0x%x, length=%d\n",
896 DEBUG("writePtsTlvToSock - done\n");
903 for (i = 0; i < MAX_RM_NUM; i++) {
904 if (fd[i] >= 0) close(fd[i]);
912 * write IF-M PTS message ()
914 * we are using sendfile() here and send the data steb by step.
915 * but IF-M of IMC/IMV version need to create whole blob to send.
917 * v0.2.4 - sendfile() not work with ptsc. use my_sendfile()
920 * length of write data
923 int writePtsTlv(OPENPTS_CONTEXT *ctx, int fdout, int type) {
929 DEBUG_CAL("writePtsTlvToSock - start\n");
933 LOG(LOG_ERR, "null input");
937 message = getPtsTlvMessage(ctx, type, &length);
938 if (message != NULL) {
939 rc = wrapWrite(fdout, message, length);
940 DEBUG_IFM("writePtsTlv - type=%d, length = %d", type, length);
942 DEBUG_IFM("getPtsTlvMessage() is null");
946 DEBUG_CAL("writePtsTlvToSock - done\n");
953 DEBUG_IFM("writePtsTlvToSock() fail, send error mgs\n");
956 len = writePtsTlv(ctx, fdout, OPENPTS_ERROR);
958 LOG(LOG_ERR, "send OPENPTS_ERROR was faild");