]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
libimcv: Support symlinks introduced by usrmerge
authorAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 30 Dec 2020 09:16:57 +0000 (10:16 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 8 Jan 2021 10:00:15 +0000 (11:00 +0100)
Debian, Ubuntu, Fedora et. al. started to apply usrmerge to their
latest Linux distributions, i.e.  /bin, /sbin, and /lib are now
symbolical links to /usr/bin, /usr/sbin, and /usr/lib, respectively.
Since executables and libraries are contained only once in Linux
packages (e.g. /bin/cp in coreutils but not /usr/bin/cp) this leads
to missing file measurments due to the symlinks when doing remote
attestation.

The new ita_attr_symlinks PA-TNC attribute fixes this problem by
collecting symbolic links pointing to directories on the client
platform.

14 files changed:
src/libimcv/Android.mk
src/libimcv/Makefile.am
src/libimcv/ita/ita_attr.c
src/libimcv/ita/ita_attr.h
src/libimcv/ita/ita_attr_symlinks.c [new file with mode: 0644]
src/libimcv/ita/ita_attr_symlinks.h [new file with mode: 0644]
src/libimcv/plugins/imc_attestation/imc_attestation.c
src/libimcv/plugins/imv_attestation/imv_attestation_agent.c
src/libimcv/plugins/imv_attestation/imv_attestation_build.c
src/libimcv/pts/components/ita/ita_comp_ima.c
src/libimcv/pts/pts.c
src/libimcv/pts/pts.h
src/libimcv/pts/pts_symlinks.c [new file with mode: 0644]
src/libimcv/pts/pts_symlinks.h [new file with mode: 0644]

index cde6ce23f961a6f46daedbf8efb16debf67b76a7..8549175aace340522b09be32759458110265f6bc 100644 (file)
@@ -42,6 +42,7 @@ libimcv_la_SOURCES := \
        ita/ita_attr_get_settings.h ita/ita_attr_get_settings.c \
        ita/ita_attr_settings.h ita/ita_attr_settings.c \
        ita/ita_attr_angel.h ita/ita_attr_angel.c \
+       ita/ita_attr_symlinks.h ita/ita_attr_symlinks.c \
        os_info/os_info.h os_info/os_info.c \
        pa_tnc/pa_tnc_attr.h \
        pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
@@ -60,6 +61,7 @@ libimcv_la_SOURCES := \
        pts/pts_ima_bios_list.h pts/pts_ima_bios_list.c \
        pts/pts_ima_event_list.h pts/pts_ima_event_list.c \
        pts/pts_meas_algo.h pts/pts_meas_algo.c \
+       pts/pts_symlinks.h pts/pts_symlinks.c \
        pts/components/pts_component.h \
        pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
        pts/components/pts_comp_evidence.h pts/components/pts_comp_evidence.c \
index 444de3f425aa9d8363d83934ee67646637635ed1..f44ab52b8191296bb167b7733808f001bf064619 100644 (file)
@@ -63,6 +63,7 @@ libimcv_la_SOURCES = \
        ita/ita_attr_get_settings.h ita/ita_attr_get_settings.c \
        ita/ita_attr_settings.h ita/ita_attr_settings.c \
        ita/ita_attr_angel.h ita/ita_attr_angel.c \
+       ita/ita_attr_symlinks.h ita/ita_attr_symlinks.c \
        os_info/os_info.h os_info/os_info.c \
        pa_tnc/pa_tnc_attr.h \
        pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
@@ -81,6 +82,7 @@ libimcv_la_SOURCES = \
        pts/pts_ima_bios_list.h pts/pts_ima_bios_list.c \
        pts/pts_ima_event_list.h pts/pts_ima_event_list.c \
        pts/pts_meas_algo.h pts/pts_meas_algo.c \
+       pts/pts_symlinks.h pts/pts_symlinks.c \
        pts/components/pts_component.h \
        pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
        pts/components/pts_comp_evidence.h pts/components/pts_comp_evidence.c \
index 1d8db71cbcede3c65157b919862bf3fe60d5ade8..788bb775f1050900f97c7e158bc5e57eb0215e58 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2020 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
 #include "ita/ita_attr_get_settings.h"
 #include "ita/ita_attr_settings.h"
 #include "ita/ita_attr_angel.h"
+#include "ita/ita_attr_symlinks.h"
 #include "generic/generic_attr_string.h"
 
-ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_DEVICE_ID,
+ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_SYMLINKS,
        "Command",
        "Dummy",
        "Get Settings",
@@ -29,7 +30,9 @@ ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_DEVICE_ID,
        "Start Angel",
        "Stop Angel",
        "Echo",
-       "Device ID"
+       "Device ID",
+       "Get Symlinks",
+       "Symlinks"
 );
 
 /**
@@ -55,6 +58,11 @@ pa_tnc_attr_t* ita_attr_create_from_data(uint32_t type, size_t length,
                case ITA_ATTR_DEVICE_ID:
                        return generic_attr_string_create_from_data(length, value,
                                                                        pen_type_create(PEN_ITA, type));
+               case ITA_ATTR_GET_SYMLINKS:
+                       return generic_attr_string_create_from_data(length, value,
+                                                                       pen_type_create(PEN_ITA, type));
+               case ITA_ATTR_SYMLINKS:
+                       return ita_attr_symlinks_create_from_data(length, value);
                default:
                        return NULL;
        }
index 726537420addded2ecb609b71cbc215790bae8b2..2bd18ce42ea83e9934a5ade3b8474df19a7a2114 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2020 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -38,7 +38,9 @@ enum ita_attr_t {
        ITA_ATTR_START_ANGEL = 5,
        ITA_ATTR_STOP_ANGEL = 6,
        ITA_ATTR_ECHO = 7,
-       ITA_ATTR_DEVICE_ID = 8
+       ITA_ATTR_DEVICE_ID = 8,
+       ITA_ATTR_GET_SYMLINKS = 9,
+       ITA_ATTR_SYMLINKS = 10
 };
 
 /**
diff --git a/src/libimcv/ita/ita_attr_symlinks.c b/src/libimcv/ita/ita_attr_symlinks.c
new file mode 100644 (file)
index 0000000..f8c59c9
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2020 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "ita_attr_symlinks.h"
+
+#include <pa_tnc/pa_tnc_msg.h>
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <collections/linked_list.h>
+#include <utils/debug.h>
+
+typedef struct private_ita_attr_symlinks_t private_ita_attr_symlinks_t;
+
+/**
+ * List of Symbolic Links pointing to Directories
+ *
+ *                                        1                               2                               3
+ *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                      Number of Symlinks                       |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |       Symlink #1 Length       |  Symlink #1 Path (Var Len)    ~
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                Symlink #1 Path (Variable Length)              |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |       Directory #1 Length     |  Directory #1 Path (Var Len)  ~
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |              Directory #1 Path (Variable Length)              |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |       Symlink #2 Length       |  Symlink #2 Path (Var Len)    ~
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                Symlink #2 Path (Variable Length)              |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |       Directory #2 Length     |  Directory #2 Path (Var Len)  ~
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |              Directory #2 Path (Variable Length)              |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *                                      ...........................
+ */
+
+#define ITA_ATTR_SYMLINKS_SIZE         4
+
+/**
+ * Private data of an ita_attr_symlinks_t object.
+ */
+struct private_ita_attr_symlinks_t {
+
+       /**
+        * Public members of ita_attr_symlinks_t
+        */
+       ita_attr_symlinks_t public;
+
+       /**
+        * Vendor-specific attribute type
+        */
+       pen_type_t type;
+
+       /**
+        * Length of attribute value
+        */
+       size_t length;
+
+       /**
+        * Offset up to which attribute value has been processed
+        */
+       size_t offset;
+
+       /**
+        * Current position of attribute value pointer
+        */
+       chunk_t value;
+
+       /**
+        * Contains complete attribute or current segment
+        */
+       chunk_t segment;
+
+       /**
+        * Noskip flag
+        */
+       bool noskip_flag;
+
+       /**
+        * Number of symbolic link entries
+        */
+       uint32_t count;
+
+       /**
+        * List of symbolic links
+        */
+       pts_symlinks_t *symlinks;
+
+       /**
+        * Reference count
+        */
+       refcount_t ref;
+};
+
+METHOD(pa_tnc_attr_t, get_type, pen_type_t,
+       private_ita_attr_symlinks_t *this)
+{
+       return this->type;
+}
+
+METHOD(pa_tnc_attr_t, get_value, chunk_t,
+       private_ita_attr_symlinks_t *this)
+{
+       return this->value;
+}
+
+METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
+       private_ita_attr_symlinks_t *this)
+{
+       return this->noskip_flag;
+}
+
+METHOD(pa_tnc_attr_t, set_noskip_flag,void,
+       private_ita_attr_symlinks_t *this, bool noskip)
+{
+       this->noskip_flag = noskip;
+}
+
+METHOD(pa_tnc_attr_t, build, void,
+       private_ita_attr_symlinks_t *this)
+{
+       bio_writer_t *writer;
+       enumerator_t *enumerator;
+       chunk_t symlink, dir;
+
+       if (this->value.ptr)
+       {
+               return;
+       }
+       this->count = this->symlinks->get_count(this->symlinks);
+
+       writer = bio_writer_create(ITA_ATTR_SYMLINKS_SIZE);
+       writer->write_uint32(writer, this->count);
+
+       enumerator = this->symlinks->create_enumerator(this->symlinks);
+       while (enumerator->enumerate(enumerator, &symlink, &dir))
+       {
+               writer->write_data16(writer, symlink);
+               writer->write_data16(writer, dir);
+       }
+       enumerator->destroy(enumerator);
+
+       this->value = writer->extract_buf(writer);
+       this->segment = this->value;
+       this->length = this->value.len;
+       writer->destroy(writer);
+}
+
+METHOD(pa_tnc_attr_t, process, status_t,
+       private_ita_attr_symlinks_t *this, uint32_t *offset)
+{
+       bio_reader_t *reader;
+       chunk_t symlink, dir;
+       status_t status = NEED_MORE;
+
+       if (this->offset == 0)
+       {
+               if (this->length < ITA_ATTR_SYMLINKS_SIZE)
+               {
+                       DBG1(DBG_TNC, "insufficient data for %N/%N", pen_names, PEN_ITA,
+                                                  ita_attr_names, this->type.type);
+                       *offset = this->offset;
+                       return FAILED;
+               }
+               if (this->value.len < ITA_ATTR_SYMLINKS_SIZE)
+               {
+                       return NEED_MORE;
+               }
+               reader = bio_reader_create(this->value);
+               reader->read_uint32(reader, &this->count);
+               this->offset = ITA_ATTR_SYMLINKS_SIZE;
+               this->value = reader->peek(reader);
+               reader->destroy(reader);
+       }
+
+       this->symlinks = pts_symlinks_create();
+       reader = bio_reader_create(this->value);
+
+       while (this->count)
+       {
+               if (!reader->read_data16(reader, &symlink) ||
+                       !reader->read_data16(reader, &dir))
+               {
+                       goto end;
+               }
+               this->offset += this->value.len - reader->remaining(reader);
+               this->value = reader->peek(reader);
+               this->symlinks->add(this->symlinks, symlink, dir);
+               this->count--;
+       }
+
+       status = SUCCESS;
+
+       if (this->length != this->offset)
+       {
+               DBG1(DBG_TNC, "inconsistent length for %N/%N", pen_names, PEN_ITA,
+                                          ita_attr_names, this->type.type);
+               *offset = this->offset;
+               status = FAILED;
+       }
+
+end:
+       reader->destroy(reader);
+       return status;
+}
+
+METHOD(pa_tnc_attr_t, add_segment, void,
+       private_ita_attr_symlinks_t *this, chunk_t segment)
+{
+       this->value = chunk_cat("cc", this->value, segment);
+       chunk_free(&this->segment);
+       this->segment = this->value;
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+       private_ita_attr_symlinks_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public.pa_tnc_attribute;
+}
+
+METHOD(pa_tnc_attr_t, destroy, void,
+       private_ita_attr_symlinks_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               DESTROY_IF(this->symlinks);
+               free(this->segment.ptr);
+               free(this);
+       }
+}
+
+METHOD(ita_attr_symlinks_t, get_symlinks, pts_symlinks_t*,
+       private_ita_attr_symlinks_t *this)
+{
+       return this->symlinks;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *ita_attr_symlinks_create(pts_symlinks_t *symlinks)
+{
+       private_ita_attr_symlinks_t *this;
+
+       INIT(this,
+               .public = {
+                       .pa_tnc_attribute = {
+                               .get_type = _get_type,
+                               .get_value = _get_value,
+                               .get_noskip_flag = _get_noskip_flag,
+                               .set_noskip_flag = _set_noskip_flag,
+                               .build = _build,
+                               .process = _process,
+                               .add_segment = _add_segment,
+                               .get_ref = _get_ref,
+                               .destroy = _destroy,
+                       },
+                       .get_symlinks = _get_symlinks,
+               },
+               .type = { PEN_ITA, ITA_ATTR_SYMLINKS },
+               .symlinks = symlinks->get_ref(symlinks),
+               .ref = 1,
+       );
+
+       return &this->public.pa_tnc_attribute;
+}
+
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *ita_attr_symlinks_create_from_data(size_t length, chunk_t data)
+{
+       private_ita_attr_symlinks_t *this;
+
+       INIT(this,
+               .public = {
+                       .pa_tnc_attribute = {
+                               .get_type = _get_type,
+                               .get_value = _get_value,
+                               .get_noskip_flag = _get_noskip_flag,
+                               .set_noskip_flag = _set_noskip_flag,
+                               .build = _build,
+                               .process = _process,
+                               .add_segment = _add_segment,
+                               .get_ref = _get_ref,
+                               .destroy = _destroy,
+                       },
+                       .get_symlinks = _get_symlinks,
+               },
+               .type = { PEN_ITA, ITA_ATTR_SYMLINKS },
+               .length = length,
+               .segment = chunk_clone(data),
+               .ref = 1,
+       );
+
+       /* received either complete attribute value or first segment */
+       this->value = this->segment;
+
+       return &this->public.pa_tnc_attribute;
+}
diff --git a/src/libimcv/ita/ita_attr_symlinks.h b/src/libimcv/ita/ita_attr_symlinks.h
new file mode 100644 (file)
index 0000000..458e6f5
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup ita_attr_sysmlinks ita_attr_sysmlinks
+ * @{ @ingroup ita_attr
+ */
+
+#ifndef ITA_ATTR_SYMLINKS_H_
+#define ITA_ATTR_SYMLINKS_H_
+
+typedef struct ita_attr_symlinks_t ita_attr_symlinks_t;
+
+#include "ita/ita_attr.h"
+#include "pa_tnc/pa_tnc_attr.h"
+#include "pts/pts_symlinks.h"
+
+/**
+ * Class implementing the ITA Symlinks attribute
+ *
+ */
+struct ita_attr_symlinks_t {
+
+       /**
+        * Public PA-TNC attribute interface
+        */
+       pa_tnc_attr_t pa_tnc_attribute;
+
+       /**
+        * Get list of symbolic links
+        *
+        * @return                              List of symbolic links pointing to directories
+        */
+       pts_symlinks_t* (*get_symlinks)(ita_attr_symlinks_t *this);
+
+};
+
+/**
+ * Creates an ita_attr_sysmlinks_t object
+ */
+pa_tnc_attr_t* ita_attr_symlinks_create(pts_symlinks_t *symlinks);
+
+/**
+ * Creates an ita_attr_sysmlinks_t object from received data
+ *
+ * @param length                       Total length of attribute value
+ * @param value                                Unparsed attribute value (might be a segment)
+ */
+pa_tnc_attr_t* ita_attr_symlinks_create_from_data(size_t length, chunk_t value);
+
+#endif /** ITA_ATTR_SYMLINKS_H_ @}*/
index f592a5134554d081eac665fb4df1aec6083c89c2..c58e5238bc456467ed64b76e9d1520a7f1e0bf91 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011-2012 Sansar Choinyambuu
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2020 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 #include <ietf/ietf_attr_product_info.h>
 #include <ietf/ietf_attr_string_version.h>
 #include <ietf/ietf_attr_assess_result.h>
+#include <ita/ita_attr_symlinks.h>
 #include <tcg/pts/tcg_pts_attr_proto_caps.h>
 #include <tcg/pts/tcg_pts_attr_meas_algo.h>
 #include <os_info/os_info.h>
@@ -200,6 +201,25 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
                                break;
                        }
                }
+               else if (type.vendor_id == PEN_ITA)
+               {
+                       if (type.type == ITA_ATTR_GET_SYMLINKS)
+                       {
+                               pts_symlinks_t *symlinks;
+                               chunk_t dir;
+                               pts_t *pts;
+
+                               dir = attr->get_value(attr);
+                               attestation_state = (imc_attestation_state_t*)state;
+                               pts = attestation_state->get_pts(attestation_state);
+                               symlinks = pts->extract_symlinks(pts, dir);
+                               if (symlinks)
+                               {
+                                       attr = ita_attr_symlinks_create(symlinks);
+                                       out_msg->add_attribute(out_msg, attr);
+                               }
+                       }
+               }
        }
        enumerator->destroy(enumerator);
 
index a1fc6466dc29847c6cc55cbf43159bbf1cedccc5..4d17f1ee458d6a2f2899e7f70e0190b4738b7551 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011-2012 Sansar Choinyambuu
- * Copyright (C) 2011-2015 Andreas Steffen
+ * Copyright (C) 2011-2020 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -34,6 +34,7 @@
 #include <ietf/ietf_attr_product_info.h>
 #include <ietf/ietf_attr_string_version.h>
 #include <ita/ita_attr.h>
+#include <ita/ita_attr_symlinks.h>
 #include <tcg/tcg_attr.h>
 #include <tcg/pts/tcg_pts_attr_meas_algo.h>
 #include <tcg/pts/tcg_pts_attr_proto_caps.h>
@@ -44,6 +45,7 @@
 #include <pts/pts.h>
 #include <pts/pts_database.h>
 #include <pts/pts_creds.h>
+#include <pts/pts_symlinks.h>
 #include <pts/components/ita/ita_comp_func_name.h>
 
 #include <tncif_pa_subtypes.h>
@@ -287,6 +289,20 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this,
                                        session->set_device_id(session, value);
                                        break;
                                }
+                               case ITA_ATTR_SYMLINKS:
+                               {
+                                       imv_attestation_state_t *attestation_state;
+                                       ita_attr_symlinks_t *attr_cast;
+                                       pts_symlinks_t *symlinks;
+                                       pts_t *pts;
+
+                                       attr_cast = (ita_attr_symlinks_t*)attr;
+                                       symlinks = attr_cast->get_symlinks(attr_cast);
+                                       attestation_state = (imv_attestation_state_t*)state;
+                                       pts = attestation_state->get_pts(attestation_state);
+                                       pts->set_symlinks(pts, symlinks);
+                                       break;
+                               }
                                default:
                                        break;
                        }
index ec54ce0cf5a30902f1c62c364418e40db4358291..9f30020d9a937b2efc7a35e6ba83ee6ee097e975 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011-2012 Sansar Choinyambuu
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2020 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -23,6 +23,8 @@
 #include <tcg/pts/tcg_pts_attr_get_aik.h>
 #include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h>
 #include <tcg/pts/tcg_pts_attr_gen_attest_evid.h>
+#include <generic/generic_attr_string.h>
+#include <ita/ita_attr.h>
 
 #include <utils/debug.h>
 
@@ -138,6 +140,11 @@ bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state,
 
                        if (attr)
                        {
+                               /* Send Get Symlinks attribute */
+                               out_msg->add_attribute(out_msg, generic_attr_string_create(
+                                                       chunk_from_str("/"),
+                                                       pen_type_create(PEN_ITA, ITA_ATTR_GET_SYMLINKS)));
+
                                /* Send Request Functional Component Evidence attribute */
                                out_msg->add_attribute(out_msg, attr);
 
index 752aa267ddce18fc0edc8c77e9de3473fadb69be..b1084e0af6df9efd74157e7d20852756d144d45e 100644 (file)
@@ -13,6 +13,9 @@
  * for more details.
  */
 
+#define _GNU_SOURCE
+#include <stdio.h>
+
 #include "ita_comp_ima.h"
 #include "ita_comp_func_name.h"
 
@@ -497,6 +500,123 @@ static pts_meas_algorithms_t parse_validation_uri(pts_comp_evidence_t *evidence,
        return hash_algo;
 }
 
+/**
+ * Look up all hashes for a given file and OS in the database and check
+ * if one of them matches the IMA measurement
+ */
+static status_t verify_ima_measuremnt(pts_t *pts, pts_database_t *pts_db,
+                                                                         pts_meas_algorithms_t hash_algo,
+                                                                         pts_meas_algorithms_t algo,
+                                                                         bool pcr_padding, chunk_t measurement,
+                                                                         char* ima_algo, char* ima_name,
+                                                                         char *filename)
+{
+       status_t status = NOT_FOUND;
+       pts_meas_algorithms_t meas_algo;
+       uint8_t *hex_digest_buf;
+       uint8_t digest_buf[HASH_SIZE_SHA512];
+       uint8_t hash_buf[HASH_SIZE_SHA512];
+       size_t hash_size;
+       chunk_t hash, digest, hex_digest;
+       enumerator_t *e;
+
+       hash_size = pts_meas_algo_hash_size(algo);
+       hash = chunk_create(hash_buf, hash_size);
+
+       if (pcr_padding)
+       {
+               memset(hash_buf, 0x00, hash_size);
+               meas_algo = PTS_MEAS_ALGO_SHA1;
+       }
+       else
+       {
+               meas_algo = algo;
+       }
+
+       e = pts_db->create_file_meas_enumerator(pts_db, pts->get_platform_id(pts),
+                                                                                       hash_algo, filename);
+       if (!e)
+       {
+               return FAILED;
+       }
+
+       while (e->enumerate(e, &hex_digest_buf))
+       {
+               hex_digest = chunk_from_str(hex_digest_buf);
+               digest = chunk_from_hex(hex_digest, digest_buf);
+
+               if (!pts_ima_event_hash(digest, ima_algo, ima_name,     meas_algo, hash_buf))
+               {
+                       status = FAILED;
+                       break;
+               }
+               if (chunk_equals_const(measurement, hash))
+               {
+                       status = SUCCESS;
+                       break;
+               }
+               else
+               {
+                       status = VERIFY_ERROR;
+               }
+       }
+       e->destroy(e);
+
+       return status;
+}
+
+/**
+ * Generate an alternative pathname based on symbolic link info
+ */
+static char* alternative_pathname(pts_t * pts, char *path)
+{
+       pts_symlinks_t *symlinks;
+       enumerator_t *enumerator;
+       chunk_t prefix1, prefix2;
+       char *alt_path = NULL;
+       size_t path_len = strlen(path);
+       int ret;
+
+       symlinks = pts->get_symlinks(pts);
+       if (!symlinks || symlinks->get_count(symlinks) == 0)
+       {
+               return NULL;
+       }
+
+       enumerator = symlinks->create_enumerator(symlinks);
+       while (enumerator->enumerate(enumerator, &prefix1, &prefix2))
+       {
+               /* replace prefix2 by prefix1*/
+               if (path_len > prefix2.len && path[prefix2.len] == '/' &&
+                       memeq(path, prefix2.ptr, prefix2.len))
+               {
+                       ret = asprintf(&alt_path, "%.*s%s", (int)prefix1.len, prefix1.ptr,
+                                                                                               path + prefix2.len);
+                       if (ret <= 0)
+                       {
+                               alt_path = NULL;
+                       }
+                       break;
+               }
+
+               /* replace prefix1 by prefix2 */
+               if (path_len > prefix1.len && path[prefix1.len] == '/' &&
+                       memeq(path, prefix1.ptr, prefix1.len))
+               {
+                       ret = asprintf(&alt_path, "%.*s%s", (int)prefix2.len, prefix2.ptr,
+                                                                                               path + prefix1.len);
+                       if (ret <= 0)
+                       {
+                               alt_path = NULL;
+                       }
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       return alt_path;
+}
+
 METHOD(pts_component_t, verify, status_t,
        pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
        pts_comp_evidence_t *evidence)
@@ -665,14 +785,8 @@ METHOD(pts_component_t, verify, status_t,
                                break;
                        case IMA_STATE_RUNTIME:
                        {
-                               chunk_t hex_digest, digest, hash;
-                               uint8_t digest_buf[HASH_SIZE_SHA512], *hex_digest_buf;
-                               uint8_t hash_buf[HASH_SIZE_SHA512];
-                               size_t hash_size;
-                               pts_meas_algorithms_t meas_algo;
-                               enumerator_t *e;
-
                                this->count++;
+
                                if (evidence->get_validation(evidence, NULL) !=
                                                        PTS_COMP_EVID_VALIDATION_PASSED)
                                {
@@ -680,50 +794,30 @@ METHOD(pts_component_t, verify, status_t,
                                        this->count_failed++;
                                        return FAILED;
                                }
-                               hash_size = pts_meas_algo_hash_size(algo);
-                               hash = chunk_create(hash_buf, hash_size);
 
-                               if (this->pcr_padding)
-                               {
-                                       memset(hash_buf, 0x00, hash_size);
-                                       meas_algo = PTS_MEAS_ALGO_SHA1;
-                               }
-                               else
-                               {
-                                       meas_algo = algo;
-                               }
+                               status = verify_ima_measuremnt(pts, this->pts_db,
+                                                                                          hash_algo, algo,
+                                                                                          this->pcr_padding, measurement,
+                                                                                          ima_algo, ima_name, ima_name);
 
-                               e = this->pts_db->create_file_meas_enumerator(this->pts_db,
-                                                                                               pts->get_platform_id(pts),
-                                                                                               hash_algo, ima_name);
-                               if (e)
+                               if (status == NOT_FOUND || status == VERIFY_ERROR)
                                {
-                                       while (e->enumerate(e, &hex_digest_buf))
-                                       {
-                                               hex_digest = chunk_from_str(hex_digest_buf);
-                                               digest = chunk_from_hex(hex_digest, digest_buf);
+                                       status_t alt_status;
+                                       char *alt_path;
 
-                                               if (!pts_ima_event_hash(digest, ima_algo, ima_name,
-                                                                                               meas_algo, hash_buf))
-                                               {
-                                                       status = FAILED;
-                                                       break;
-                                               }
-                                               if (chunk_equals_const(measurement, hash))
-                                               {
-                                                       status = SUCCESS;
-                                                       break;
-                                               }
-                                               else
+                                       alt_path = alternative_pathname(pts, ima_name);
+                                       if (alt_path)
+                                       {
+                                               alt_status = verify_ima_measuremnt(pts, this->pts_db,
+                                                                                          hash_algo, algo,
+                                                                                          this->pcr_padding, measurement,
+                                                                                          ima_algo, ima_name, alt_path);
+                                               if (alt_status != NOT_FOUND)
                                                {
-                                                       status = VERIFY_ERROR;
+                                                       status = alt_status;
                                                }
+                                               free(alt_path);
                                        }
-                                       e->destroy(e);
-                               }
-                               else
-                               {
-                                       status = FAILED;
                                }
 
                                switch (status)
index a03703dddc61de4dff870e5198682bec7a9804dd..aeeae607595828db68f2a7099f01d745d4f63a44 100644 (file)
 #include <sys/stat.h>
 #include <libgen.h>
 #include <unistd.h>
+#include <dirent.h>
 #include <errno.h>
 
+
 #ifndef TPM_TAG_QUOTE_INFO2
 #define TPM_TAG_QUOTE_INFO2 0x0036
 #endif
@@ -89,6 +91,11 @@ struct private_pts_t {
         */
        int platform_id;
 
+       /**
+        * List of directory symlinks received from IMC
+        */
+       pts_symlinks_t *symlinks;
+
        /**
         * TRUE if IMC-PTS, FALSE if IMV-PTS
         */
@@ -309,6 +316,104 @@ METHOD(pts_t, set_platform_id, void,
        this->platform_id = pid;
 }
 
+METHOD(pts_t, extract_symlinks, pts_symlinks_t*,
+       private_pts_t *this, chunk_t pathname)
+{
+#ifndef WIN32
+       char path[BUF_LEN], real_path[BUF_LEN];
+       size_t path_len, real_path_len;
+       struct dirent *entry;
+       struct stat st;
+       DIR *dir;
+
+       /* open directory and prepare pathnames */
+       snprintf(path, BUF_LEN-1, "%.*s", (int)pathname.len, pathname.ptr);
+       dir = opendir(path);
+       if (!dir)
+       {
+               DBG1(DBG_PTS, "opening directory '%s' failed: %s", path,
+                                          strerror(errno));
+               return NULL;
+       }
+       if (pathname.len == 1 && path[0] == '/')
+       {
+               path_len = 1;
+       }
+       else
+       {
+               path[pathname.len] = '/';
+               path_len = pathname.len + 1;
+       }
+       real_path[0] = '/';
+
+       /* symlinks object is owned by pts object */
+       DESTROY_IF(this->symlinks);
+       this->symlinks = pts_symlinks_create();
+
+       while (TRUE)
+       {
+
+               entry = readdir(dir);
+               if (!entry)
+               {
+                       /* no more entries -> exit */
+                       break;
+               }
+               if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
+               {
+                       continue;
+               }
+
+               /* assemble absolute path */
+               snprintf(path + path_len, BUF_LEN - path_len, "%s", entry->d_name);
+
+               /* only evaluate symlinks pointing to directories */
+               if (lstat(path, &st) == -1 || !S_ISLNK(st.st_mode) ||
+                        stat(path, &st) == -1 || !S_ISDIR(st.st_mode))
+               {
+                       continue;
+               }
+
+               real_path_len = readlink(path, real_path + 1, BUF_LEN - 1);
+               if (real_path_len <= 0)
+               {
+                       continue;
+               }
+               this->symlinks->add(this->symlinks, chunk_from_str(path),
+                                                       chunk_create(real_path, 1 + real_path_len));
+       }
+       closedir(dir);
+#endif
+
+       return this->symlinks;
+}
+
+
+METHOD(pts_t, get_symlinks, pts_symlinks_t*,
+       private_pts_t *this)
+{
+       return this->symlinks;
+}
+
+METHOD(pts_t, set_symlinks, void,
+       private_pts_t *this, pts_symlinks_t *symlinks)
+{
+       enumerator_t *enumerator;
+       chunk_t symlink, dir;
+
+       DESTROY_IF(this->symlinks);
+       this->symlinks = symlinks->get_ref(symlinks);
+
+       DBG2(DBG_PTS, "adding directory symlinks:");
+       enumerator = symlinks->create_enumerator(symlinks);
+       while (enumerator->enumerate(enumerator, &symlink, &dir))
+       {
+               DBG2(DBG_PTS, "  %.*s -> %.*s", (int)symlink.len, symlink.ptr,
+                                                                               (int)dir.len, dir.ptr);
+       }
+       enumerator->destroy(enumerator);
+}
+
 METHOD(pts_t, get_tpm, tpm_tss_t*,
        private_pts_t *this)
 {
@@ -354,7 +459,7 @@ METHOD(pts_t, set_tpm_version_info, void,
                {
                        DBG2(DBG_PTS, "%s 1.2 rev. %u.%u.%u.%u %.*s", TPM_VERSION_INFO_LABEL,
                                (uint32_t)major, (uint32_t)minor, (uint32_t)rev_major,
-                               (uint32_t)rev_minor, vendor.len, vendor.ptr);
+                               (uint32_t)rev_minor, (int)vendor.len, vendor.ptr);
                }
                else
                {
@@ -377,7 +482,7 @@ METHOD(pts_t, set_tpm_version_info, void,
                {
                        DBG2(DBG_PTS, "%s 2.0 rev. %4.2f %u %.*s - startup locality: %u",
                                 TPM_VERSION_INFO_LABEL, revision/100.0, year,
-                                vendor.len, vendor.ptr, (uint32_t)locality);
+                                (int)vendor.len, vendor.ptr, (uint32_t)locality);
                }
                else
                {
@@ -873,6 +978,7 @@ METHOD(pts_t, destroy, void,
        DESTROY_IF(this->pcrs);
        DESTROY_IF(this->aik_cert);
        DESTROY_IF(this->dh);
+       DESTROY_IF(this->symlinks);
        free(this->initiator_nonce.ptr);
        free(this->responder_nonce.ptr);
        free(this->secret.ptr);
@@ -901,6 +1007,9 @@ pts_t *pts_create(bool is_imc)
                        .calculate_secret = _calculate_secret,
                        .get_platform_id = _get_platform_id,
                        .set_platform_id = _set_platform_id,
+                       .extract_symlinks = _extract_symlinks,
+                       .get_symlinks = _get_symlinks,
+                       .set_symlinks = _set_symlinks,
                        .get_tpm = _get_tpm,
                        .get_tpm_version_info = _get_tpm_version_info,
                        .set_tpm_version_info = _set_tpm_version_info,
index b9fac0a6e5afa6b4d150efe576a346b98e74c778..b2a389045736dac9d39dbeef1f83fcf8ebdbec0d 100644 (file)
@@ -32,6 +32,7 @@ typedef struct pts_t pts_t;
 #include "pts_dh_group.h"
 #include "pts_pcr.h"
 #include "pts_req_func_comp_evid.h"
+#include "pts_symlinks.h"
 #include "components/pts_comp_func_name.h"
 
 #include <tpm_tss_quote_info.h>
@@ -175,6 +176,29 @@ struct pts_t {
         */
        void (*set_platform_id)(pts_t *this, int pid);
 
+       /**
+        * Extract all directory symlinks contained in a directory
+        *
+        * @param pathname                      Absolute pathname of directory
+        * @return                                      List of directory symlinks
+        */
+       pts_symlinks_t* (*extract_symlinks)(pts_t *this, chunk_t pathname);
+
+       /**
+        * Get list of directory symlinks received from IMC
+        *
+        * @return                                      List of symbolic links
+        */
+       pts_symlinks_t* (*get_symlinks)(pts_t *this);
+
+       /**
+        * Set list of directory symlinks received from IMC
+        *
+        * @param symlinks                      List of symbolic links
+        */
+       void (*set_symlinks)(pts_t *this, pts_symlinks_t *symlinks);
+
+
        /**
         * Get TPM object handle
         *
diff --git a/src/libimcv/pts/pts_symlinks.c b/src/libimcv/pts/pts_symlinks.c
new file mode 100644 (file)
index 0000000..152a8b5
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2020 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "pts_symlinks.h"
+
+#include <collections/linked_list.h>
+#include <utils/debug.h>
+
+typedef struct private_pts_symlinks_t private_pts_symlinks_t;
+typedef struct entry_t entry_t;
+
+/**
+ * Private data of a pts_symlinks_t object.
+ *
+ */
+struct private_pts_symlinks_t {
+
+       /**
+        * Public pts_symlinks_t interface.
+        */
+       pts_symlinks_t public;
+
+       /**
+        * List of symbolic links pointing to directories
+        */
+       linked_list_t *list;
+
+       /**
+        * Reference count
+        */
+       refcount_t ref;
+
+};
+
+/**
+ * Symlink entry
+ */
+struct entry_t {
+       chunk_t symlink;
+       chunk_t dir;
+};
+
+/**
+ * Free an entry_t object
+ */
+static void free_entry(entry_t *entry)
+{
+       if (entry)
+       {
+               free(entry->symlink.ptr);
+               free(entry->dir.ptr);
+               free(entry);
+       }
+}
+
+METHOD(pts_symlinks_t, get_count, int,
+       private_pts_symlinks_t *this)
+{
+       return this->list->get_count(this->list);
+}
+
+METHOD(pts_symlinks_t, add, void,
+       private_pts_symlinks_t *this, chunk_t symlink, chunk_t dir)
+{
+       entry_t *entry;
+
+       entry = malloc_thing(entry_t);
+       entry->symlink = chunk_clone(symlink);
+       entry->dir = chunk_clone(dir);
+
+       this->list->insert_last(this->list, entry);
+}
+
+CALLBACK(symlink_filter, bool,
+       void *null, enumerator_t *orig, va_list args)
+{
+       entry_t *entry;
+       chunk_t *symlink;
+       chunk_t *dir;
+
+       VA_ARGS_VGET(args, symlink, dir);
+
+       if (orig->enumerate(orig, &entry))
+       {
+               *symlink = entry->symlink;
+               *dir     = entry->dir;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+METHOD(pts_symlinks_t, create_enumerator, enumerator_t*,
+       private_pts_symlinks_t *this)
+{
+       return enumerator_create_filter(this->list->create_enumerator(this->list),
+                                                                       symlink_filter, NULL, NULL);
+}
+
+METHOD(pts_symlinks_t, get_ref, pts_symlinks_t*,
+       private_pts_symlinks_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public;
+}
+
+METHOD(pts_symlinks_t, destroy, void,
+       private_pts_symlinks_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               this->list->destroy_function(this->list, (void *)free_entry);
+               free(this);
+       }
+}
+
+/**
+ * See header
+ */
+pts_symlinks_t *pts_symlinks_create()
+{
+       private_pts_symlinks_t *this;
+
+       INIT(this,
+               .public = {
+                       .get_count = _get_count,
+                       .add = _add,
+                       .create_enumerator = _create_enumerator,
+                       .get_ref = _get_ref,
+                       .destroy = _destroy,
+               },
+               .list = linked_list_create(),
+               .ref = 1,
+       );
+
+       return &this->public;
+}
+
diff --git a/src/libimcv/pts/pts_symlinks.h b/src/libimcv/pts/pts_symlinks.h
new file mode 100644 (file)
index 0000000..291a7e1
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup pts_symlinks pts_symlinks
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_SYMLINKS_H_
+#define PTS_SYMLINKS_H_
+
+#include <library.h>
+
+typedef struct pts_symlinks_t pts_symlinks_t;
+
+
+/**
+ * Class storing a list of symbolic links pointing to directories
+ */
+struct pts_symlinks_t {
+
+       /**
+        * Get the number of symbolic link entries
+        *
+        * @return                              Number of symbolic links
+        */
+       int (*get_count)(pts_symlinks_t *this);
+
+       /**
+        * Add a symbolic link pointing to a directory
+        *
+        * @param symlink               Pathname of symbolic link
+        * @param dir               Pathname of directory the symlink points to
+        */
+       void (*add)(pts_symlinks_t *this, chunk_t symlink, chunk_t dir);
+
+       /**
+         * Create a symlink enumerator
+         *
+         * @return                             Enumerator returning (chunk_t symlink, chunk_t dir)
+         */
+       enumerator_t* (*create_enumerator)(pts_symlinks_t *this);
+
+       /**
+        * Get a new reference to the list of symbolic links
+        *
+        * @return                      this, with an increased refcount
+        */
+       pts_symlinks_t* (*get_ref)(pts_symlinks_t *this);
+
+
+       /**
+        * Destroys a pts_symlinks_t object.
+        */
+       void (*destroy)(pts_symlinks_t *this);
+
+};
+
+/**
+ * Creates a pts_symlinks_t object
+ */
+pts_symlinks_t* pts_symlinks_create();
+
+#endif /** PTS_SYMLINKS_H_ @}*/