File not Found, Invalid path, Invalid Delimiter PTS errors case checks implemented
[strongswan.git] / src / libimcv / plugins / imc_attestation / imc_attestation.c
index 64b3fe1..58fb178 100644 (file)
 #include <pa_tnc/pa_tnc_msg.h>
 #include <ietf/ietf_attr.h>
 #include <ietf/ietf_attr_pa_tnc_error.h>
+#include <ietf/ietf_attr_product_info.h>
+
+#include <libpts.h>
+
+#include <pts/pts_error.h>
 
 #include <tcg/tcg_pts_attr_proto_caps.h>
 #include <tcg/tcg_pts_attr_meas_algo.h>
 #include <pen/pen.h>
 #include <debug.h>
 #include <utils/linked_list.h>
-#include <crypto/hashers/hasher.h>
-#include <dirent.h>
-#include <errno.h>
-
-#include <trousers/tss.h>
-#include <trousers/trousers.h>
-
 
 /* IMC definitions */
 
@@ -52,7 +50,6 @@ static const char imc_name[] = "Attestation";
 
 #define IMC_VENDOR_ID                          PEN_TCG
 #define IMC_SUBTYPE                                    PA_SUBTYPE_TCG_PTS
-#define IMC_ATTESTATION_BUF_SIZE       32768
 
 static imc_agent_t *imc_attestation;
 
@@ -60,37 +57,6 @@ static imc_agent_t *imc_attestation;
  * Supported PTS measurement algorithms
  */
 static pts_meas_algorithms_t supported_algorithms = 0;
-
-/**
- * PTS Protocol capabilities
- */
-static pts_proto_caps_flag_t proto_caps;
-
-/**
- * Selected PTS measurement algorithm after attribute exchange
- */
-static pts_meas_algorithms_t selected_algorithm = PTS_MEAS_ALGO_SHA256;
-
-/**
- * List of files and directories to measure
- */
-static linked_list_t *file_list, *directory_list;
-
-/**
- * List of file measurements
- */
-static linked_list_t *file_measurements;
-
-/* TODO: Move the struct to some header file? Duplicate with imv_attestation*/
-/**
- * Struct to hold file or directory name with the request ID for Request File Measurement attribute
- */
-typedef struct measurement_req_entry_t measurement_req_entry_t;
-
-struct measurement_req_entry_t {
-       char *path;
-       u_int16_t request_id;
-};
  
 /**
  * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
@@ -105,12 +71,19 @@ TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
                DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
                return TNC_RESULT_ALREADY_INITIALIZED;
        }
+       if (!pts_meas_probe_algorithms(&supported_algorithms))
+       {
+               return TNC_RESULT_FATAL;
+       }
        imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
-                                                               imc_id, actual_version);
-       if (!imc_attestation || !pts_meas_probe_algorithms(&supported_algorithms))
+                                                                          imc_id, actual_version);
+       if (!imc_attestation)
        {
                return TNC_RESULT_FATAL;
        }
+
+       libpts_init();
+
        if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
        {
                DBG1(DBG_IMC, "no common IF-IMC version");
@@ -151,306 +124,52 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
        }
 }
 
-/**
- * Get the TPM Version Information
- */
-static TSS_RESULT get_tpm_version_info(BYTE *tpm_version_info)
-{
-       TSS_HCONTEXT    hContext;
-       TSS_HTPM        hTPM;
-       TSS_RESULT uiResult;
-       UINT32 uiResultLen;
-       /* TODO: Needed for parsing version info on IMV side */
-       //TPM_CAP_VERSION_INFO versionInfo;
-       //UINT64 offset = 0;
-
-       uiResult = Tspi_Context_Create(&hContext);
-       if (uiResult != TSS_SUCCESS) {
-               DBG1(DBG_IMC,"Error 0x%x on Tspi_Context_Create\n", uiResult);
-               return uiResult;
-       }
-       uiResult = Tspi_Context_Connect(hContext, NULL);
-       if (uiResult != TSS_SUCCESS) {
-               DBG1(DBG_IMC,"Error 0x%x on Tspi_Context_Connect\n", uiResult);
-               return uiResult;
-       }
-       uiResult = Tspi_Context_GetTpmObject (hContext, &hTPM);
-       if (uiResult != TSS_SUCCESS) {
-               DBG1(DBG_IMC,"Error 0x%x on Tspi_Context_GetTpmObject\n", uiResult);
-               return uiResult;
-       }
-
-       uiResult = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL,  0, NULL, &uiResultLen,
-                                         &tpm_version_info);
-       if (uiResult != TSS_SUCCESS) {
-               DBG1(DBG_IMC,"Error 0x%x on Tspi_TPM_GetCapability\n", uiResult);
-               return uiResult;
-       }
-}
 
 /**
- * Get Hash Measurement of a file
+ * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
  */
-static TNC_Result hash_file(char *path, char *out)
+TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
+                                                                 TNC_ConnectionID connection_id)
 {
-       BYTE buffer[IMC_ATTESTATION_BUF_SIZE];
-       FILE *file;
-       int bytes_read;
-       hasher_t *hasher;
-       hash_algorithm_t hash_alg;
-       
-       /* Create a hasher */
-       hash_alg = pts_meas_to_hash_algorithm(selected_algorithm);
-       hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
-       if (!hasher)
-       {
-               DBG1(DBG_IMC, "hasher %N not available", hash_algorithm_names, hash_alg);
-               return TNC_RESULT_FATAL;
-       }
-
-       file = fopen(path, "rb");
-       if (!file)
-       {
-               DBG1(DBG_IMC,"file '%s' can not be opened", path);
-               hasher->destroy(hasher);
-               return TNC_RESULT_FATAL;
-       }
-       while (TRUE)
-       {
-               bytes_read = fread(buffer, 1, sizeof(buffer), file);
-               if (bytes_read > 0)
-               {
-                       hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL);
-               }
-               else
-               {
-                       hasher->get_hash(hasher, chunk_empty, out);
-                       break;
-               }
-       }
-       fclose(file);
-       hasher->destroy(hasher);
-
-       return TNC_RESULT_SUCCESS;
-}
+       imc_state_t *state;
+       imc_attestation_state_t *attestation_state;
+       pts_t *pts;
+       char *platform_info;
+       TNC_Result result = TNC_RESULT_SUCCESS;
 
-/**
- * Get hash of all the files in a directory
- */
-static TNC_Result hash_directory(char *path)
-{
-       DIR *dir;
-       struct dirent *ent;
-       linked_list_t *file_measurements;
-       file_meas_entry_t *entry;
-       
-       file_measurements = linked_list_create();
-       entry = malloc_thing(file_meas_entry_t);
-       
-       dir = opendir(path);
-       if (dir == NULL)
-       {
-               DBG1(DBG_IMC, "opening directory '%s' failed: %s", path, strerror(errno));
-               return TNC_RESULT_FATAL;
-       }
-       while ((ent = readdir(dir)))
+       if (!imc_attestation)
        {
-               char *file_hash;
-               
-               if(hash_file(ent->d_name,file_hash) != TNC_RESULT_SUCCESS)
-               {
-                       DBG1(DBG_IMC, "Hashing the given file has failed");
-                       return TNC_RESULT_FATAL;
-               }
-               
-               entry->measurement = chunk_create(file_hash,strlen(file_hash));
-               entry->file_name_len = strlen(ent->d_name);
-               entry->file_name = chunk_create(ent->d_name,strlen(ent->d_name));
-               
-               file_measurements->insert_last(file_measurements,entry);
+               DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
+               return TNC_RESULT_NOT_INITIALIZED;
        }
-       closedir(dir);
-       
-       return TNC_RESULT_SUCCESS;
-}
-
-static TNC_Result send_message(TNC_ConnectionID connection_id)
-{
-       pa_tnc_msg_t *msg;
-       pa_tnc_attr_t *attr;
-       imc_state_t *state;
-       imc_attestation_state_t *attestation_state;
-       imc_attestation_handshake_state_t handshake_state;
-       TNC_Result result;
 
+       /* get current IMC state */
        if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
        {
                return TNC_RESULT_FATAL;
        }
        attestation_state = (imc_attestation_state_t*)state;
-       handshake_state = attestation_state->get_handshake_state(attestation_state);
-       
-       /* Switch on the attribute type IMC has received */
-       switch (handshake_state)
-       {
-               case IMC_ATTESTATION_STATE_REQ_PROTO_CAP:
-               {
-                       pts_proto_caps_flag_t flags;
-                       if(proto_caps & PTS_PROTO_CAPS_T)
-                       {
-                               flags = PTS_PROTO_CAPS_T;
-                       }
-                       if(proto_caps & PTS_PROTO_CAPS_V)
-                       {
-                               flags |= PTS_PROTO_CAPS_V;
-                       }
-                       attr = tcg_pts_attr_proto_caps_create(flags, FALSE);
-                       break;
-               }
-               case IMC_ATTESTATION_STATE_REQ_MEAS_ALGO:
-               {
-                       attr = tcg_pts_attr_meas_algo_create(selected_algorithm, TRUE);
-                       break;
-               }
-               case IMC_ATTESTATION_STATE_GET_TPM_INFO:
-               {
-                       TSS_RESULT uiResult;
-                       BYTE *tpm_version_info;
-
-                       uiResult = get_tpm_version_info(tpm_version_info);
-                       if (uiResult != TSS_SUCCESS) {
-                               DBG1(DBG_IMC,"Error 0x%x on get_tpm_version_info\n", uiResult);
-                               return uiResult;
-                       }
-
-                       attr = tcg_pts_attr_tpm_version_info_create(
-                               chunk_create((char *)tpm_version_info,
-                                            strlen(tpm_version_info)));
-                       break;
-               }
-               case IMC_ATTESTATION_STATE_REQ_FILE_MEAS:
-               {
-                       measurement_req_entry_t *entry;
-                       enumerator_t *enumerator;
-                       tcg_pts_attr_file_meas_t *attr_file_meas;
-                       u_int16_t meas_len = HASH_SIZE_SHA1;
-                       
-                       if (selected_algorithm & PTS_MEAS_ALGO_SHA384)
-                       {
-                               meas_len = HASH_SIZE_SHA384;
-                       }
-                       else if(selected_algorithm & PTS_MEAS_ALGO_SHA256) 
-                       {
-                               meas_len = HASH_SIZE_SHA512;
-                       }
+       pts = attestation_state->get_pts(attestation_state);
 
-                       msg = pa_tnc_msg_create();
-                       
-                       /** 
-                        * Hash the files and add them as attribute
-                        */
-                       enumerator = enumerator_create_single(file_list, NULL);
-                       while (enumerator->enumerate(enumerator, &entry))
-                       {
-                               char * file_hash;
-                               
-                               attr = tcg_pts_attr_file_meas_create(1, 
-                                               entry->request_id, meas_len);
-                               attr->set_noskip_flag(attr, TRUE);
-                               attr_file_meas = (tcg_pts_attr_file_meas_t*)attr;
-                               
-                               if(hash_file(entry->path,file_hash) != TNC_RESULT_SUCCESS)
-                               {
-                                       DBG1(DBG_IMC, "Hashing the given file has failed");
-                                       return TNC_RESULT_FATAL;
-                               }
-                               attr_file_meas->add_file_meas(attr_file_meas, 
-                                               chunk_create(file_hash,strlen(file_hash)),
-                                               chunk_create(entry->path,strlen(entry->path)));
-                               
-                               msg->add_attribute(msg, attr);
-                       }
-                       
-                       /** 
-                        * Hash the files in each directory and add them as attribute
-                        */
-                       enumerator = enumerator_create_single(directory_list, NULL);
-                       while (enumerator->enumerate(enumerator, &entry))
-                       {
-                               enumerator_t *meas_enumerator;
-                               file_meas_entry_t *meas_entry;
-                               u_int64_t num_of_files = 0 ;
-                               
-                               if(hash_directory(entry->path) != TNC_RESULT_SUCCESS)
-                               {
-                                       DBG1(DBG_IMC, "Hashing the files in a given directory has failed");
-                                       return TNC_RESULT_FATAL;
-                               }
-                               
-                               attr = tcg_pts_attr_file_meas_create(0, 
-                                               entry->request_id, meas_len);
-                               attr->set_noskip_flag(attr, TRUE);
-                               attr_file_meas = (tcg_pts_attr_file_meas_t*)attr;
-                               
-                               meas_enumerator = enumerator_create_single(file_measurements, NULL);
-                               while (meas_enumerator->enumerate(meas_enumerator, &meas_entry))
-                               {
-                                       num_of_files++;
-                                       attr_file_meas->add_file_meas(attr_file_meas,
-                                                                     meas_entry->measurement,
-                                                                     meas_entry->file_name);
-                               }
-                               
-                               attr_file_meas->set_number_of_files(attr_file_meas,
-                                                                   num_of_files);
-                               msg->add_attribute(msg, attr);
-                       }
-                       enumerator->destroy(enumerator);
-                       goto end;
-               }
-               case IMC_ATTESTATION_STATE_GET_AIK:
-                       /* TODO: Implement AIK retrieve */
-               case IMC_ATTESTATION_STATE_REQ_FUNCT_COMP_EVID:
-               case IMC_ATTESTATION_STATE_GEN_ATTEST_EVID:
-               case IMC_ATTESTATION_STATE_REQ_FILE_METADATA:
-               case IMC_ATTESTATION_STATE_REQ_IML:
-               case IMC_ATTESTATION_STATE_INIT:
-                       DBG1(DBG_IMC, "Attestation IMC has nothing to send: \"%s\"", handshake_state);
-                       return TNC_RESULT_FATAL;
-               default:
-                       DBG1(DBG_IMC, "Attestation IMC is in unknown state: \"%s\"", handshake_state);
-                       return TNC_RESULT_FATAL;
+       platform_info = pts->get_platform_info(pts);
+       if (platform_info)
+       {
+               pa_tnc_msg_t *pa_tnc_msg;
+               pa_tnc_attr_t *attr;
+
+               pa_tnc_msg = pa_tnc_msg_create();
+               attr = ietf_attr_product_info_create(0, 0, platform_info);
+               pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
+               pa_tnc_msg->build(pa_tnc_msg);
+               result = imc_attestation->send_message(imc_attestation, connection_id,
+                                                                       pa_tnc_msg->get_encoding(pa_tnc_msg));
+               pa_tnc_msg->destroy(pa_tnc_msg);
        }
-       
-       
-       attr->set_noskip_flag(attr, TRUE);
-       msg = pa_tnc_msg_create();
-       msg->add_attribute(msg, attr);
-       
-end:
-       msg->build(msg);
-       result = imc_attestation->send_message(imc_attestation, connection_id,
-                                                                       msg->get_encoding(msg));        
-       msg->destroy(msg);
 
        return result;
 }
 
 /**
- * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
- */
-TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
-                                                                 TNC_ConnectionID connection_id)
-{
-       if (!imc_attestation)
-       {
-               DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
-               return TNC_RESULT_NOT_INITIALIZED;
-       }
-       return send_message(connection_id);
-}
-
-/**
  * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
  */
 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
@@ -461,9 +180,11 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
 {
        pa_tnc_msg_t *pa_tnc_msg;
        pa_tnc_attr_t *attr;
+       linked_list_t *attr_list;
        imc_state_t *state;
        imc_attestation_state_t *attestation_state;
        enumerator_t *enumerator;
+       pts_t *pts;
        TNC_Result result;
        bool fatal_error = FALSE;
 
@@ -473,7 +194,15 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
                return TNC_RESULT_NOT_INITIALIZED;
        }
 
-       /* parse received PA-TNC message and automatically handle any errors */ 
+       /* get current IMC state */
+       if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
+       {
+               return TNC_RESULT_FATAL;
+       }
+       attestation_state = (imc_attestation_state_t*)state;
+       pts = attestation_state->get_pts(attestation_state);
+
+       /* parse received PA-TNC message and automatically handle any errors */
        result = imc_attestation->receive_message(imc_attestation, connection_id,
                                                                           chunk_create(msg, msg_len), msg_type,
                                                                           &pa_tnc_msg);
@@ -483,6 +212,8 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
        {
                return result;
        }
+       
+       attr_list = linked_list_create();
 
        /* analyze PA-TNC attributes */
        enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
@@ -519,74 +250,96 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
                }
                else if (attr->get_vendor_id(attr) == PEN_TCG)
                {
-                       /**
-                        * Handle TCG PTS attributes
-                        */
-                       
-                       /* get current IMC state */
-                       if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
-                       {
-                               return TNC_RESULT_FATAL;
-                       }
-                       attestation_state = (imc_attestation_state_t*)state;
-
-                       switch(attr->get_type(attr))
+                       switch (attr->get_type(attr))
                        {
                                case TCG_PTS_REQ_PROTO_CAPS:
                                {
-                                       tcg_pts_attr_proto_caps_t *attr_req_proto_caps;
-                                       
-                                       attr_req_proto_caps = (tcg_pts_attr_proto_caps_t*)attr;
-                                       proto_caps = attr_req_proto_caps->get_flags(attr_req_proto_caps);
-                                       
-                                       attestation_state->set_handshake_state(attestation_state,
-                                                                               IMC_ATTESTATION_STATE_REQ_PROTO_CAP);
+                                       tcg_pts_attr_proto_caps_t *attr_cast;
+                                       pts_proto_caps_flag_t imc_flags, imv_flags;
+
+                                       attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
+                                       imv_flags = attr_cast->get_flags(attr_cast);
+                                       imc_flags = pts->get_proto_caps(pts);
+                                       pts->set_proto_caps(pts, imc_flags & imv_flags);
+
+                                       /* Send PTS Protocol Capabilities attribute */
+                                       attr = tcg_pts_attr_proto_caps_create(imc_flags & imv_flags,
+                                                                                                                 FALSE);
+                                       attr_list->insert_last(attr_list, attr);
                                        break;
                                }
                                case TCG_PTS_MEAS_ALGO:
                                {
-                                       tcg_pts_attr_meas_algo_t *attr_meas_algo;
-                                       
-                                       attr_meas_algo = (tcg_pts_attr_meas_algo_t*)attr;
-                                       selected_algorithm = attr_meas_algo->get_algorithms(attr_meas_algo);
+                                       tcg_pts_attr_meas_algo_t *attr_cast;
+                                       pts_meas_algorithms_t selected_algorithm;
+       
+                                       attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
+                                       selected_algorithm = attr_cast->get_algorithms(attr_cast);
 
                                        if ((supported_algorithms & PTS_MEAS_ALGO_SHA384) &&
-                                               (selected_algorithm   & PTS_MEAS_ALGO_SHA384))
+                                               (selected_algorithm & PTS_MEAS_ALGO_SHA384))
                                        {
-                                               selected_algorithm = PTS_MEAS_ALGO_SHA384;
+                                               pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA384);
                                        }
-                                       else if (selected_algorithm & PTS_MEAS_ALGO_SHA256)
+                                       else if ((supported_algorithms & PTS_MEAS_ALGO_SHA256) &&
+                                                        (selected_algorithm & PTS_MEAS_ALGO_SHA256))
                                        {
-                                               selected_algorithm = PTS_MEAS_ALGO_SHA256;
+                                               pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA256);
                                        }
-                                       else if (selected_algorithm & PTS_MEAS_ALGO_SHA1)
+
+                                       else if ((supported_algorithms & PTS_MEAS_ALGO_SHA1) &&
+                                                        (selected_algorithm & PTS_MEAS_ALGO_SHA1))
                                        {
-                                               selected_algorithm = PTS_MEAS_ALGO_SHA1;
+                                               pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA1);
                                        }
                                        else
                                        {
-                                               /* TODO generate an error message */
-                                               selected_algorithm = PTS_MEAS_ALGO_SHA256;
+                                               attr = pts_hash_alg_error_create(supported_algorithms);
+                                               attr_list->insert_last(attr_list, attr);
+                                               break;
                                        }
-                                       DBG2(DBG_IMC, "selected PTS measurement algorithm is %N",
-                                                hash_algorithm_names, 
-                                                pts_meas_to_hash_algorithm(selected_algorithm));
 
-                                       attestation_state->set_handshake_state(attestation_state,
-                                                                               IMC_ATTESTATION_STATE_REQ_MEAS_ALGO);
+                                       /* Send Measurement Algorithm Selection attribute */
+                                       selected_algorithm = pts->get_meas_algorithm(pts);
+                                       attr = tcg_pts_attr_meas_algo_create(selected_algorithm,
+                                                                                                                TRUE);
+                                       attr_list->insert_last(attr_list, attr);
                                        break;
                                }
-                                       
+       
                                case TCG_PTS_GET_TPM_VERSION_INFO:
                                {
-                                       attestation_state->set_handshake_state(attestation_state,
-                                                                               IMC_ATTESTATION_STATE_GET_TPM_INFO);
+                                       chunk_t tpm_version_info, attr_info;
+
+                                       if (!pts->get_tpm_version_info(pts, &tpm_version_info))
+                                       {
+                                               attr_info = attr->get_value(attr);
+                                               attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+                                                                       TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info);
+                                               attr_list->insert_last(attr_list, attr);
+                                               break;
+                                       }
+       
+                                       /* Send TPM Version Info attribute */
+                                       attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
+                                       attr_list->insert_last(attr_list, attr);
                                        break;
                                }
+       
                                case TCG_PTS_GET_AIK:
                                {
-                                       attestation_state->set_handshake_state(attestation_state,
-                                                                               IMC_ATTESTATION_STATE_GET_AIK);
+                                       certificate_t *aik;
+
+                                       aik = pts->get_aik(pts);
+                                       if (!aik)
+                                       {
+                                               DBG1(DBG_IMC, "no AIK certificate or public key available");
+                                               break;
+                                       }
+       
+                                       /* Send AIK attribute */
+                                       attr = tcg_pts_attr_aik_create(aik);
+                                       attr_list->insert_last(attr_list, attr);
                                        break;
                                }
        
@@ -597,27 +350,60 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
                                        break;
                                case TCG_PTS_REQ_FILE_MEAS:
                                {
-                                       tcg_pts_attr_req_file_meas_t *attr_req_file_meas;
-                                       measurement_req_entry_t *entry;
+                                       tcg_pts_attr_req_file_meas_t *attr_cast;
+                                       char *pathname;
+                                       u_int16_t request_id;
+                                       bool is_directory;
                                        u_int32_t delimiter;
+                                       pts_file_meas_t *measurements;
+                                       pts_error_code_t pts_error;
+                                       chunk_t attr_info;
                                        
-                                       attr_req_file_meas = (tcg_pts_attr_req_file_meas_t*)attr;
-                                       file_list = linked_list_create();
-                                       directory_list = linked_list_create();
-                                       delimiter = attr_req_file_meas->get_delimiter(attr_req_file_meas);
-                                       entry = malloc_thing(measurement_req_entry_t);
-                                       entry->request_id = attr_req_file_meas->get_request_id(attr_req_file_meas);
-                                       entry->path = attr_req_file_meas->get_file_path(attr_req_file_meas).ptr;
+                                       attr_info = attr->get_value(attr);
+                                       attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
+                                       is_directory = attr_cast->get_directory_flag(attr_cast);
+                                       request_id = attr_cast->get_request_id(attr_cast);
+                                       delimiter = attr_cast->get_delimiter(attr_cast);
+                                       pathname = attr_cast->get_pathname(attr_cast);
                                        
-                                       (attr_req_file_meas->get_directory_flag(attr_req_file_meas)) ? 
-                                               directory_list->insert_last(directory_list, entry) : 
-                                               file_list->insert_last(file_list, entry); 
+                                       if (pts->is_path_valid(pts, pathname, &pts_error) && pts_error)
+                                       {
+                                               attr_info = attr->get_value(attr);
+                                               attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+                                                                                               pts_error, attr_info);
+                                               attr_list->insert_last(attr_list, attr);
+                                               break;
+                                       }
+                                       else if (!pts->is_path_valid(pts, pathname, &pts_error))
+                                       {
+                                               break;
+                                       }
                                        
-                                       attestation_state->set_handshake_state(attestation_state,
-                                                                               IMC_ATTESTATION_STATE_REQ_FILE_MEAS);
+                                       if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
+                                       {
+                                               attr_info = attr->get_value(attr);
+                                               attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
+                                                                                               TCG_PTS_INVALID_DELIMITER, attr_info);
+                                               attr_list->insert_last(attr_list, attr);
+                                               break;
+                                       }
+
+                                       /* Do PTS File Measurements and send them to PTS-IMV */
+                                       DBG2(DBG_IMC, "measurement request %d for %s '%s'",
+                                                request_id, is_directory ? "directory" : "file",
+                                                pathname);
+                                       measurements = pts->do_measurements(pts, request_id,
+                                                                                       pathname, is_directory);
+                                       if (!measurements)
+                                       {
+                                               /* TODO handle error codes from measurements */
+                                               return TNC_RESULT_FATAL;
+                                       }
+                                       attr = tcg_pts_attr_file_meas_create(measurements);
+                                       attr->set_noskip_flag(attr, TRUE);
+                                       attr_list->insert_last(attr_list, attr);
                                        break;
                                }
-                               
                                /* TODO: Not implemented yet */
                                case TCG_PTS_DH_NONCE_PARAMS_REQ:
                                case TCG_PTS_DH_NONCE_FINISH:
@@ -634,7 +420,7 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
                                case TCG_PTS_MEAS_ALGO_SELECTION:
                                case TCG_PTS_TPM_VERSION_INFO:
                                case TCG_PTS_TEMPL_REF_MANI_SET_META:
-                               case TCG_PTS_AIK:                               
+                               case TCG_PTS_AIK:
                                case TCG_PTS_SIMPLE_COMP_EVID:
                                case TCG_PTS_SIMPLE_EVID_FINAL:
                                case TCG_PTS_VERIFICATION_RESULT:
@@ -647,15 +433,32 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
                                                tcg_attr_names, attr->get_type(attr));
                                        break;
                        }
-                       
-                       
                }
        }
        enumerator->destroy(enumerator);
        pa_tnc_msg->destroy(pa_tnc_msg);
 
-       /* if no error occurred then always return the same response */
-       return fatal_error ? TNC_RESULT_FATAL : send_message(connection_id);
+       result = TNC_RESULT_SUCCESS;
+       
+       if (attr_list->get_count(attr_list))
+       {
+               pa_tnc_msg = pa_tnc_msg_create();
+
+               enumerator = attr_list->create_enumerator(attr_list);
+               while (enumerator->enumerate(enumerator, &attr))
+               {
+                       pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
+               }
+               enumerator->destroy(enumerator);
+
+               pa_tnc_msg->build(pa_tnc_msg);
+               result = imc_attestation->send_message(imc_attestation, connection_id,
+                                                       pa_tnc_msg->get_encoding(pa_tnc_msg));
+               pa_tnc_msg->destroy(pa_tnc_msg);
+       }
+       attr_list->destroy(attr_list);
+
+       return result;
 }
 
 /**
@@ -682,6 +485,9 @@ TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
                DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
                return TNC_RESULT_NOT_INITIALIZED;
        }
+
+       libpts_deinit();
+
        imc_attestation->destroy(imc_attestation);
        imc_attestation = NULL;