KEYSYNC: Added arbitrary hard coded sync message expiry (10m), and made special case when receiving groupKeys message so that they are not consumed giving a chance to other devices in the group to receive it as well.
authorEdouard Tisserant <edouard@pep-project.org>
Wed, 05 Oct 2016 18:18:41 +0200
changeset 1248c332c47fe26e
parent 1247 998021d725a1
child 1249 8d96a89bedb0
child 1250 1c9cab3267ac
child 1251 070a7a80a6c9
KEYSYNC: Added arbitrary hard coded sync message expiry (10m), and made special case when receiving groupKeys message so that they are not consumed giving a chance to other devices in the group to receive it as well.
asn.1/devicegroup.asn1
src/map_asn1.c
src/map_asn1.h
src/sync_impl.c
     1.1 --- a/asn.1/devicegroup.asn1	Wed Oct 05 15:38:42 2016 +0200
     1.2 +++ b/asn.1/devicegroup.asn1	Wed Oct 05 18:18:41 2016 +0200
     1.3 @@ -27,8 +27,9 @@
     1.4          sequence    INTEGER,  /* always increases */
     1.5          me          Identity, /* identity of the sender */
     1.6          state       INTEGER,  /* state the sender is in */
     1.7 -        devicegroup BOOLEAN
     1.8 +        devicegroup BOOLEAN,
     1.9              /* signals if this message is coming from a device group member */
    1.10 +        expiry      GeneralizedTime
    1.11      },
    1.12  
    1.13      payload CHOICE {
     2.1 --- a/src/map_asn1.c	Wed Oct 05 15:38:42 2016 +0200
     2.2 +++ b/src/map_asn1.c	Wed Oct 05 18:18:41 2016 +0200
     2.3 @@ -178,3 +178,35 @@
     2.4      return NULL;
     2.5  }
     2.6  
     2.7 +timestamp *GeneralizedTime_to_timestamp(GeneralizedTime_t * asntime, timestamp *result)
     2.8 +{
     2.9 +    assert(asntime);
    2.10 +    if (!asntime)
    2.11 +        return NULL;
    2.12 +
    2.13 +    time_t smpltime = asn_GT2time(asntime, NULL, 0);
    2.14 +
    2.15 +    if (!result){
    2.16 +        result = new_timestamp(smpltime);
    2.17 +    }
    2.18 +    else
    2.19 +        gmtime_r(&smpltime, result);
    2.20 +
    2.21 +
    2.22 +    return result;
    2.23 +}
    2.24 +
    2.25 +time_t GeneralizedTime_to_time_t(GeneralizedTime_t * asntime)
    2.26 +{
    2.27 +    return asn_GT2time(asntime, NULL, 0);
    2.28 +}
    2.29 +
    2.30 +GeneralizedTime_t *timestamp_to_GeneralizedTime(timestamp * ts, GeneralizedTime_t *result)
    2.31 +{
    2.32 +    assert(ts);
    2.33 +    if (!ts)
    2.34 +        return NULL;
    2.35 +
    2.36 +    GeneralizedTime_t *asntime = asn_time2GT(result, ts, 0);
    2.37 +    return asntime;
    2.38 +}
     3.1 --- a/src/map_asn1.h	Wed Oct 05 15:38:42 2016 +0200
     3.2 +++ b/src/map_asn1.h	Wed Oct 05 18:18:41 2016 +0200
     3.3 @@ -4,6 +4,7 @@
     3.4  #include "identity_list.h"
     3.5  #include "../asn.1/Identity.h"
     3.6  #include "../asn.1/IdentityList.h"
     3.7 +#include "../asn.1/GeneralizedTime.h"
     3.8  
     3.9  #ifdef __cplusplus
    3.10  extern "C" {
    3.11 @@ -74,6 +75,44 @@
    3.12  
    3.13  identity_list *IdentityList_to_identity_list(IdentityList_t *list, identity_list *result);
    3.14  
    3.15 +// GeneralizedTime_to_timestamp() - convert ASN.1 GeneralizedTime to timestamp
    3.16 +//
    3.17 +//  params:
    3.18 +//      asntime (in)        ASN.1 GeneralizedTime to convert
    3.19 +//      result (inout)      timestamp to update or NULL to alloc a new one
    3.20 +//
    3.21 +//  return value:
    3.22 +//      pointer to allocated timestamp
    3.23 +//
    3.24 +//  caveat:
    3.25 +//      if a new timestamp is allocated, the ownership goes to the caller
    3.26 +
    3.27 +timestamp *GeneralizedTime_to_timestamp(GeneralizedTime_t * asntime, timestamp *result);
    3.28 +
    3.29 +// GeneralizedTime_to_time_t() - convert ASN.1 GeneralizedTime to time_t
    3.30 +//
    3.31 +//  params:
    3.32 +//      asntime (in)        ASN.1 GeneralizedTime to convert
    3.33 +//
    3.34 +//  return value:
    3.35 +//      resulting time_t
    3.36 +//
    3.37 +
    3.38 +time_t GeneralizedTime_to_time_t(GeneralizedTime_t * asntime);
    3.39 +
    3.40 +// timestamp_GeneralizedTime_to() - convert ASN.1 timestamp to GeneralizedTime
    3.41 +//
    3.42 +//  params:
    3.43 +//      ts (in)             timestam to convert
    3.44 +//      result (inout)      GeneralizedTime_t to update or NULL to alloc a new one
    3.45 +//
    3.46 +//  return value:
    3.47 +//      pointer to allocated ASN.1 GeneralizedTime
    3.48 +//
    3.49 +//  caveat:
    3.50 +//      if a new GeneralizedTime is allocated, the ownership goes to the caller
    3.51 +
    3.52 +GeneralizedTime_t *timestamp_to_GeneralizedTime(timestamp * ts, GeneralizedTime_t *result);
    3.53  
    3.54  #ifdef __cplusplus
    3.55  }
     4.1 --- a/src/sync_impl.c	Wed Oct 05 15:38:42 2016 +0200
     4.2 +++ b/src/sync_impl.c	Wed Oct 05 18:18:41 2016 +0200
     4.3 @@ -175,6 +175,9 @@
     4.4          return PEP_ILLEGAL_VALUE;
     4.5  
     4.6      bool found = false;
     4.7 +    bool expired = false;
     4.8 +    bool discarded = false;
     4.9 +    bool force_keep_msg = false;
    4.10      
    4.11      bloblist_t *last = NULL;
    4.12      for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
    4.13 @@ -183,9 +186,9 @@
    4.14              DeviceGroup_Protocol_t *msg = NULL;
    4.15              uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **)
    4.16                      &msg, bl->value, bl->size);
    4.17 +
    4.18              if (msg) {
    4.19  
    4.20 -                int32_t value = (int32_t) msg->header.sequence;
    4.21                  char *user_id = strndup((char *) msg->header.me.user_id->buf,
    4.22                          msg->header.me.user_id->size);
    4.23                  assert(user_id);
    4.24 @@ -194,79 +197,105 @@
    4.25                      return PEP_OUT_OF_MEMORY;
    4.26                  }
    4.27  
    4.28 -                switch (msg->payload.present) {
    4.29 -                    // HandshakeRequest needs encryption
    4.30 -                    case DeviceGroup_Protocol__payload_PR_handshakeRequest:
    4.31 -                        if (rating < PEP_rating_reliable ||
    4.32 -                            strncmp(session->sync_uuid,
    4.33 -                                    (const char *)msg->payload.choice.handshakeRequest.partner.user_id->buf,
    4.34 -                                    msg->payload.choice.handshakeRequest.partner.user_id->size) != 0){
    4.35 -                            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    4.36 -                            free(user_id);
    4.37 -                            return PEP_MESSAGE_DISCARDED;
    4.38 -                        }
    4.39 -                        break;
    4.40 -                    // accepting GroupKeys needs encryption and trust
    4.41 -                    case DeviceGroup_Protocol__payload_PR_groupKeys:
    4.42 -                        if (!keylist || rating < PEP_rating_reliable ||
    4.43 -                            strncmp(session->sync_uuid,
    4.44 -                                    (const char *)msg->payload.choice.groupKeys.partner.user_id->buf,
    4.45 -                                    msg->payload.choice.groupKeys.partner.user_id->size) != 0){
    4.46 -                            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    4.47 -                            free(user_id);
    4.48 -                            return PEP_MESSAGE_DISCARDED;
    4.49 -                        }
    4.50 -
    4.51 -                        // check trust of identity with the right user_id
    4.52 -                        pEp_identity *_from = new_identity(src->from->address, 
    4.53 -                                                           keylist->value,
    4.54 -                                                           user_id,
    4.55 -                                                           src->from->username);
    4.56 -                        if (_from == NULL){
    4.57 -                            free(user_id);
    4.58 -                            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    4.59 -                            return PEP_OUT_OF_MEMORY;
    4.60 -                        }
    4.61 -                        PEP_rating this_user_id_rating = PEP_rating_undefined;
    4.62 -                        identity_rating(session, _from, &this_user_id_rating);
    4.63 -                        free_identity(_from);
    4.64 -
    4.65 -                        if (this_user_id_rating < PEP_rating_trusted ) {
    4.66 -                            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    4.67 -                            free(user_id);
    4.68 -                            return PEP_MESSAGE_DISCARDED;
    4.69 -                        }
    4.70 -                        break;
    4.71 -                    default:
    4.72 -                        break;
    4.73 +                // check message expiry 
    4.74 +                time_t expiry = GeneralizedTime_to_time_t(&msg->header.expiry);
    4.75 +                time_t now = time(NULL);
    4.76 +                if(expiry != 0 && now != 0 && expiry < now){
    4.77 +                    expired = true;
    4.78 +                    goto flush;
    4.79                  }
    4.80  
    4.81 -
    4.82 +                int32_t value = (int32_t) msg->header.sequence;
    4.83                  PEP_STATUS status = sequence_value(session, (char *) user_id,
    4.84                          &value);
    4.85  
    4.86                  if (status == PEP_STATUS_OK) {
    4.87 +                    switch (msg->payload.present) {
    4.88 +                        // HandshakeRequest needs encryption
    4.89 +                        case DeviceGroup_Protocol__payload_PR_handshakeRequest:
    4.90 +                            if (rating < PEP_rating_reliable ||
    4.91 +                                strncmp(session->sync_uuid,
    4.92 +                                        (const char *)msg->payload.choice.handshakeRequest.partner.user_id->buf,
    4.93 +                                        msg->payload.choice.handshakeRequest.partner.user_id->size) != 0){
    4.94 +                                discarded = true;
    4.95 +                                goto flush;
    4.96 +                            }
    4.97 +                            break;
    4.98 +                        // accepting GroupKeys needs encryption and trust
    4.99 +                        case DeviceGroup_Protocol__payload_PR_groupKeys:
   4.100 +                            if (!keylist || rating < PEP_rating_reliable ||
   4.101 +                                // if header.state is HandshakingSole, then
   4.102 +                                // group is just forming in between 2 devices
   4.103 +                                // message must be addressed to that instance
   4.104 +                                // to be consumed
   4.105 +                                (msg->header.state == HandshakingSole && 
   4.106 +                                 strncmp(session->sync_uuid,
   4.107 +                                        (const char *)msg->payload.choice.groupKeys.partner.user_id->buf,
   4.108 +                                        msg->payload.choice.groupKeys.partner.user_id->size) != 0)){
   4.109 +                                discarded = true;
   4.110 +                                goto flush;
   4.111 +                            }
   4.112 +
   4.113 +                            // otherwise, when group keys are sent from a 
   4.114 +                            // pre-existing group, inject message but flag is 
   4.115 +                            // as discarded to prevent app to delete it, so 
   4.116 +                            // that other group members can also be updated
   4.117 +                            if(msg->header.state != HandshakingSole){
   4.118 +                                force_keep_msg = true;
   4.119 +                            }
   4.120 +
   4.121 +                            // check trust of identity with the right user_id
   4.122 +                            pEp_identity *_from = new_identity(src->from->address, 
   4.123 +                                                               keylist->value,
   4.124 +                                                               user_id,
   4.125 +                                                               src->from->username);
   4.126 +                            if (_from == NULL){
   4.127 +                                status = PEP_OUT_OF_MEMORY;
   4.128 +                                goto flush;
   4.129 +                            }
   4.130 +                            PEP_rating this_user_id_rating = PEP_rating_undefined;
   4.131 +                            identity_rating(session, _from, &this_user_id_rating);
   4.132 +                            free_identity(_from);
   4.133 +
   4.134 +                            if (this_user_id_rating < PEP_rating_trusted ) {
   4.135 +                                discarded = true;
   4.136 +                                goto flush;
   4.137 +                            }
   4.138 +                            break;
   4.139 +                        default:
   4.140 +                            break;
   4.141 +                    }
   4.142 +
   4.143 +
   4.144                      found = true;
   4.145                      sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
   4.146                      if(sync_msg == NULL){
   4.147 -                        ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   4.148 -                        return PEP_OUT_OF_MEMORY;
   4.149 +                        status = PEP_OUT_OF_MEMORY;
   4.150 +                        goto flush;
   4.151                      }
   4.152                      sync_msg->is_a_message = true;
   4.153                      sync_msg->u.message = msg;
   4.154                      status = call_inject_sync_msg(session, sync_msg);
   4.155                      if (status != PEP_STATUS_OK){
   4.156 -                        ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   4.157                          if (status == PEP_SYNC_NO_INJECT_CALLBACK){
   4.158                              free(sync_msg);
   4.159                          }
   4.160 -                        return status;
   4.161 +                        goto flush;
   4.162                      }
   4.163                  }
   4.164                  else if (status == PEP_OWN_SEQUENCE) {
   4.165 -                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   4.166 -                    return PEP_MESSAGE_DISCARDED;
   4.167 +                    status = PEP_STATUS_OK;
   4.168 +                    discarded = true;
   4.169 +                    goto flush;
   4.170                  }
   4.171 +
   4.172 +            flush:
   4.173 +                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   4.174 +                free(user_id);
   4.175 +
   4.176 +                if (status != PEP_STATUS_OK)
   4.177 +                    return status;
   4.178 +
   4.179              }
   4.180  
   4.181              if (!session->keep_sync_msg) {
   4.182 @@ -288,7 +317,11 @@
   4.183          }
   4.184      }
   4.185  
   4.186 -    if (found && !session->keep_sync_msg) {
   4.187 +    if (force_keep_msg) {
   4.188 +        return PEP_MESSAGE_DISCARDED;
   4.189 +    }
   4.190 +
   4.191 +    if ((expired || found) && !session->keep_sync_msg) {
   4.192          for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
   4.193                  spl = spl->next) {
   4.194              if (spl->value->key &&
   4.195 @@ -298,8 +331,12 @@
   4.196                      return PEP_MESSAGE_CONSUMED;
   4.197              }
   4.198          }
   4.199 +        return PEP_MESSAGE_DISCARDED;
   4.200      }
   4.201  
   4.202 +    if(discarded)
   4.203 +        return PEP_MESSAGE_DISCARDED;
   4.204 +
   4.205      return PEP_STATUS_OK;
   4.206  }
   4.207  
   4.208 @@ -319,6 +356,9 @@
   4.209      ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   4.210  }
   4.211  
   4.212 +// Ten minutes
   4.213 +#define SYNC_MSG_EXPIRE_DELTA (60 * 10)
   4.214 +
   4.215  PEP_STATUS unicast_msg(
   4.216          PEP_SESSION session,
   4.217          const Identity partner,
   4.218 @@ -382,6 +422,13 @@
   4.219      else
   4.220          msg->header.devicegroup = 0;
   4.221  
   4.222 +    timestamp *expiry = new_timestamp(time(NULL) + SYNC_MSG_EXPIRE_DELTA);
   4.223 +    if(timestamp_to_GeneralizedTime(expiry, &msg->header.expiry) == NULL){
   4.224 +        free_timestamp(expiry);
   4.225 +        goto enomem;
   4.226 +    }
   4.227 +    free_timestamp(expiry);
   4.228 +
   4.229      if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) {
   4.230          status = PEP_CONTRAINTS_VIOLATED;
   4.231          goto error;