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);
416 /* Collector --> Verifier */
419 if ((ctx->conf->pubkey != NULL) && (ctx->conf->pubkey_length > 0)) {
421 length = ctx->conf->pubkey_length;
422 buf = getTlvBuffer(type, length);
424 LOG(LOG_ERR, "getTlvBuffer() is null");
429 memcpy(&buf[12], ctx->conf->pubkey, ctx->conf->pubkey_length);
432 /* PUB key is missing */
433 LOG(LOG_ERR, "writePtsTlvToSock - PUBKEY blob is missing\n");
434 ctx->ifm_errno = PTS_FATAL;
435 ctx->ifm_strerror = smalloc_assert("Public key is missing");
442 /* Collector --> Verifier */
445 /* open/read RM files */
446 length = 4; // for RM num
447 for (i = 0; i < conf->rm_num; i++) {
449 fd[i] = open(ctx->conf->rm_filename[i], O_RDONLY);
451 // 20101124 SM must be a fullpath for Daemon
452 LOG(LOG_ERR, "Can't open RM[%d] files, %s\n",
453 i, ctx->conf->rm_filename[i]);
454 /* send Error massage */
455 ctx->ifm_errno = PTS_FATAL;
457 smalloc_assert("Manifest not found, initialize the collector");
461 if (-1 == fstat(fd[i], &st[i])) {
462 LOG(LOG_ERR, "fstat failed with errno %d\n", errno);
465 fsize[i] = st[i].st_size;
466 length += 4 + fsize[i];
468 DEBUG_IFM("writePtsTlv - RIMM_SET, length = %d", length);
470 buf = getTlvBuffer(type, length);
471 if (buf == NULL) goto error;
475 num = htonl(conf->rm_num);
476 memcpy(&buf[ptr], (BYTE *)&num, 4);
479 for (i = 0; i< conf->rm_num; i++) {
481 num = htonl(fsize[i]);
482 // rc = wrapWrite(fdout, (BYTE *)&num, 4);
483 memcpy(&buf[ptr], (BYTE *)&num, 4);
486 count[i] = copyfile(&buf[ptr], fd[i], fsize[i]);
487 if (count[i] != fsize[i]) {
488 LOG(LOG_ERR, "copyfile() faild %d != %d\n", count[i], fsize[i]);
495 DEBUG_IFM("RM[%d] len = %d\n", i, count[i]);
500 /* Collector --> Verifier */
504 if (conf->newrm_num == 0) {
505 /* New RM is missing => send Error massage */
506 DEBUG_IFM("New RM is missing. send Error massage\n");
507 ctx->ifm_errno = PTS_FATAL;
508 ctx->ifm_strerror = smalloc_assert("New Manifest not found, check the collector");
512 /* setup TLV header (2/2) */
513 length = 16 + 4; // UUID + num
514 for (i = 0; i < conf->newrm_num; i++) {
515 fd[i] = open(ctx->conf->newrm_filename[i], O_RDONLY);
517 // 20101124 SM must be a fullpath for Daemon
518 LOG(LOG_ERR, "Error RM file, %s not found\n", ctx->conf->newrm_filename[i]);
519 /* send Error massage */
520 ctx->ifm_errno = PTS_FATAL;
522 smalloc_assert("New Manifest file not found, check the collector");
526 if (-1 == fstat(fd[i], &st[i])) {
527 LOG(LOG_ERR, "fstat failed with errno %d\n", errno);
530 fsize[i] = st[i].st_size;
531 length += 4 + fsize[i];
535 DEBUG_IFM("writePtsTlv - NEW_RIMM_SET, length = %d", length);
537 buf = getTlvBuffer(type, length);
539 LOG(LOG_ERR, "getTlvBuffer() is null");
546 memcpy(&buf[ptr], ctx->conf->newrm_uuid->uuid, 16);
550 num = htonl(conf->newrm_num);
551 memcpy(&buf[ptr], (BYTE *)&num, 4);
554 for (i = 0; i< conf->newrm_num; i++) {
556 num = htonl(fsize[i]);
557 memcpy(&buf[ptr], (BYTE *)&num, 4);
560 count[i] = copyfile(&buf[ptr], fd[i], fsize[i]);
565 DEBUG_IFM("RM[%d] len = %d\n", i, count[i]);
572 length = ctx->nonce->nonce_length;
573 buf = getTlvBuffer(type, length);
575 LOG(LOG_ERR, "getTlvBuffer() is null");
578 memcpy(&buf[12], ctx->nonce->nonce, length);
582 case INTEGRITY_REPORT:
584 /* generate new IR, giving us a file descriptor corresponding
585 to an already deleted file for added security - once the file
586 gets closed you lose the IR! */
587 rc = genIr(ctx, &fd[0]);
588 if (rc != PTS_SUCCESS) {
589 LOG(LOG_ERR, "writePtsTlvToSock - gen IR failed\n");
590 /* send Error massage */
591 ctx->ifm_errno = PTS_FATAL;
592 ctx->ifm_strerror = smalloc_assert("Generation of IR failed");
596 /* check the IR size */
597 if (-1 == fstat(fd[0], &st[0])) {
598 LOG(LOG_ERR, "fstat failed with errno %d\n", errno);
601 fsize[0] = st[0].st_size;
604 buf = getTlvBuffer(type, length);
606 LOG(LOG_ERR, "getTlvBuffer() is null");
611 if (-1 == lseek(fd[0], 0, SEEK_SET)) {
612 LOG(LOG_ERR, "Could not seek to start of %s (fd '%d')\n", ctx->conf->ir_filename, fd[0]);
616 count[0] = copyfile(&buf[ptr], fd[0], fsize[0]);
617 if (count[0] != fsize[0]) {
618 LOG(LOG_ERR, "copyfile() faild %d != %d\n", count[0], fsize[0]);
629 case AIDE_DATABASE: /* AIDE DATABASE: C -> V */
631 /* setup TLV header (2/2) */
633 if (ctx->conf->aide_database_filename == NULL) {
635 DEBUG("writePtsTlvToSock - Error AIDE DB file is not configured\n");
636 ctx->ifm_errno = PTS_FATAL;
637 ctx->ifm_strerror = smalloc_assert("AIDE DB file is not configured");
640 fd[0] = open(ctx->conf->aide_database_filename, O_RDONLY);
642 /* AIDE file is missing, erorr */
643 LOG(LOG_ERR, "writePtsTlvToSock - Error AIDE DB file, %s not found\n",
644 ctx->conf->aide_database_filename);
645 /* send Error massage */
646 ctx->ifm_errno = PTS_FATAL;
647 ctx->ifm_strerror = smalloc_assert("AIDE file not found");
651 if (-1 == fstat(fd[0], &st[0])) {
652 LOG(LOG_ERR, "fstat failed with errno %d\n", errno);
655 fsize[0] = st[0].st_size;
660 buf = getTlvBuffer(type, length);
662 LOG(LOG_ERR, "getTlvBuffer() is null");
670 count[0] = copyfile(&buf[ptr], fd[0], fsize[0]);
671 if (count[0] != fsize[0]) {
672 LOG(LOG_ERR, "copyfile() faild %d != %d\n", count[0], fsize[0]);
679 DEBUG_IFM("writePtsTlv - AIDE_DATABASE, file = %s\n",
680 ctx->conf->aide_database_filename);
681 // DEBUG_IFM("AIDE DATABASE len = %d\n", count[0]);
683 DEBUG_IFM("writePtsTlv - AIDE_DATABASE, length = %d", length);
686 #endif // CONFIG_AIDE
689 case DH_NONCE_PARAMETERS_REQUEST: /* DH: Initiator -> Respondor */
691 /* setup TLV header (2/2) */
693 buf = getTlvBuffer(type, length);
700 buf[0] = ctx->nonce->req->reserved;
701 buf[1] = ctx->nonce->req->min_nonce_len;
702 memcpy(&buf[ptr], buf, 2);
705 nbou16 = htons(ctx->nonce->req->dh_group_set);
706 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
709 DEBUG_IFM("writePtsTlv - DH_NONCE_PARAMETERS_REQUEST, length = %d", length);
713 case DH_NONCE_PARAMETORS_RESPONSE: /* DH: IRespondor -> Initiator */
715 /* setup TLV header (2/2) */
718 ctx->nonce->respondor_nonce_length +
719 ctx->nonce->pubkey_length;
721 buf = getTlvBuffer(type, length);
723 LOG(LOG_ERR, "getTlvBuffer() is null");
729 buf[0] = ctx->nonce->res->reserved[0];
730 buf[1] = ctx->nonce->res->reserved[1];
731 buf[2] = ctx->nonce->res->reserved[2];
732 buf[3] = ctx->nonce->res->nonce_length;
733 memcpy(&buf[ptr], buf, 4);
736 nbou16 = htons(ctx->nonce->res->selected_dh_group);
737 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
740 nbou16 = htons(ctx->nonce->res->hash_alg_set);
741 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
747 ctx->nonce->respondor_nonce,
748 ctx->nonce->respondor_nonce_length);
749 ptr += ctx->nonce->respondor_nonce_length;
751 /* send dh_respondor_public */
755 ctx->nonce->pubkey_length);
756 ptr += ctx->nonce->pubkey_length;
758 DEBUG_IFM("writePtsTlv - DH_NONCE_PARAMETORS_RESPONSE, length = %d", length);
762 case DH_NONCE_FINISH: /* DH: Initiator -> Respondor */
764 /* setup TLV header (2/2) */
767 ctx->nonce->initiator_nonce_length +
768 ctx->nonce->pubkey_length;
770 buf = getTlvBuffer(type, length);
772 LOG(LOG_ERR, "getTlvBuffer() is null");
777 /* Send IF-M TLV header */
780 buf[0] = ctx->nonce->fin->reserved = 0;
781 buf[1] = ctx->nonce->fin->nonce_length = ctx->nonce->initiator_nonce_length;
782 memcpy(&buf[ptr], (BYTE *)&buf, 2);
785 nbou16 = htons(ctx->nonce->fin->selected_hash_alg);
786 memcpy(&buf[ptr], (BYTE *)&nbou16, 2);
789 /* send dh_initiator_pubkey */
790 memcpy(&buf[ptr], ctx->nonce->pubkey, ctx->nonce->pubkey_length);
791 ptr += ctx->nonce->pubkey_length;
793 /* send dh_initiator_nonce */
796 ctx->nonce->initiator_nonce,
797 ctx->nonce->initiator_nonce_length);
798 ptr += ctx->nonce->initiator_nonce_length;
800 DEBUG_IFM("writePtsTlv - DH_NONCE_FINISH, length = %d", length);
806 /* setup TLV header (2/2) */
808 if (ctx->ifm_strerror != NULL) {
809 length = 4 + 4 + strlen(ctx->ifm_strerror);
814 buf = getTlvBuffer(type, length);
816 LOG(LOG_ERR, "getTlvBuffer() is null");
825 /* send error code */
826 ifm_errno = htonl(ctx->ifm_errno);
827 memcpy(&buf[ptr], (BYTE *)&ifm_errno, 4);
832 if (ctx->ifm_strerror != NULL) {
833 len = strlen(ctx->ifm_strerror);
835 memcpy(&buf[ptr], (BYTE *)&size, 4);
838 memcpy(&buf[ptr], (BYTE *)&ctx->ifm_strerror, len);
841 xfree(ctx->ifm_strerror);
844 memcpy(&buf[ptr], (BYTE *)&size, 4);
849 DEBUG_IFM("writePtsTlv - OPENPTS_ERROR, length = %d", length);
855 LOG(LOG_ERR, "BAD IF-M OPENPTS MESSAGE TYPE, type=0x%x\n", type);
859 DEBUG_IFM("IF-M message, type=0x%x, length=%d\n",
861 DEBUG("writePtsTlvToSock - done\n");
868 for (i = 0; i < MAX_RM_NUM; i++) {
869 if (fd[i] >= 0) close(fd[i]);
877 * write IF-M PTS message ()
879 * we are using sendfile() here and send the data steb by step.
880 * but IF-M of IMC/IMV version need to create whole blob to send.
882 * v0.2.4 - sendfile() not work with ptsc. use my_sendfile()
885 * length of write data
888 int writePtsTlv(OPENPTS_CONTEXT *ctx, int fdout, int type) {
894 DEBUG_CAL("writePtsTlvToSock - start\n");
898 LOG(LOG_ERR, "null input");
902 message = getPtsTlvMessage(ctx, type, &length);
903 if (message != NULL) {
904 rc = wrapWrite(fdout, message, length);
905 DEBUG_IFM("writePtsTlv - type=%d, length = %d", type, length);
907 DEBUG_IFM("getPtsTlvMessage() is null");
911 DEBUG_CAL("writePtsTlvToSock - done\n");
918 DEBUG_IFM("writePtsTlvToSock() fail, send error mgs\n");
921 len = writePtsTlv(ctx, fdout, OPENPTS_ERROR);
923 LOG(LOG_ERR, "send OPENPTS_ERROR was faild");