src/sync_impl.c
author Volker Birk <vb@pep.foundation>
Wed, 31 Aug 2016 12:51:52 +0200
branchkeysync
changeset 1105 3fbdd80f0e52
parent 1104 81cabcd37300
child 1110 d37d730fa8e5
permissions -rw-r--r--
adding check for PEP_SYNC_NO_INJECT_CALLBACK
     1 #include "../asn.1/DeviceGroup-Protocol.h"
     2 #include "sync_impl.h"
     3 #include "pEp_internal.h"
     4 #include "keymanagement.h"
     5 #include "message_api.h"
     6 #include "map_asn1.h"
     7 #include "baseprotocol.h"
     8 
     9 #define SYNC_VERSION_MAJOR 1
    10 #define SYNC_VERSION_MINOR 0
    11 
    12 PEP_STATUS receive_sync_msg(
    13         PEP_SESSION session,
    14         DeviceGroup_Protocol_t *msg
    15     )
    16 {
    17     assert(session && msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING);
    18     if (!(session && msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING))
    19         return PEP_ILLEGAL_VALUE;
    20 
    21     void *extra = NULL;
    22     Identity partner = NULL;
    23     DeviceState_event event = DeviceState_event_NONE;
    24 
    25     switch (msg->payload.present) {
    26         case DeviceGroup_Protocol__payload_PR_beacon:
    27             partner = Identity_to_Struct(&msg->header.me, NULL);
    28             if (!partner)
    29                 return PEP_OUT_OF_MEMORY;
    30             event = Beacon;
    31             break;
    32 
    33         case DeviceGroup_Protocol__payload_PR_handshakeRequest:
    34             partner = Identity_to_Struct(&msg->header.me, NULL);
    35             if (!partner)
    36                 return PEP_OUT_OF_MEMORY;
    37             event = HandshakeRequest;
    38             break;
    39 
    40         case DeviceGroup_Protocol__payload_PR_groupKeys:
    41             partner = Identity_to_Struct(&msg->header.me, NULL);
    42             if (!partner)
    43                 return PEP_OUT_OF_MEMORY;
    44             identity_list *group_keys = IdentityList_to_identity_list(
    45                     &msg->payload.choice.groupKeys.ownIdentities, NULL);
    46             if (!group_keys) {
    47                 free_identity(partner);
    48                 return PEP_OUT_OF_MEMORY;
    49             }
    50             extra = (void *) group_keys;
    51             event = GroupKeys;
    52             break;
    53 
    54         default:
    55             return PEP_SYNC_ILLEGAL_MESSAGE;
    56     }
    57 
    58     return fsm_DeviceState_inject(session, event, partner, extra);
    59 }
    60 
    61 PEP_STATUS receive_DeviceState_msg(PEP_SESSION session, message *src, PEP_rating rating)
    62 {
    63     assert(session && src);
    64     if (!(session && src))
    65         return PEP_ILLEGAL_VALUE;
    66 
    67     assert(session->inject_sync_msg);
    68     if (!session->inject_sync_msg)
    69         return PEP_SYNC_NO_INJECT_CALLBACK;
    70 
    71     bool found = false;
    72     
    73     bloblist_t *last = NULL;
    74     for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
    75         if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp") == 0
    76                 && bl->size) {
    77             DeviceGroup_Protocol_t *msg = NULL;
    78             uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **)
    79                     &msg, bl->value, bl->size);
    80             if (msg) {
    81                 switch (msg->payload.present) {
    82                     // HandshakeRequest needs encryption
    83                     case DeviceGroup_Protocol__payload_PR_handshakeRequest:
    84                         if (rating < PEP_rating_reliable) {
    85                             ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    86                             goto skip;
    87                         }
    88                     // accepting GroupKeys needs trust
    89                     case DeviceGroup_Protocol__payload_PR_groupKeys:
    90                         if (rating < PEP_rating_trusted) {
    91                             ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    92                             goto skip;
    93                         }
    94                     default:
    95                         break;
    96                 }
    97 
    98                 found = true;
    99 
   100                 int32_t value = (int32_t) msg->header.sequence;
   101                 char *user_id = strndup((char *) msg->header.me.user_id->buf,
   102                         msg->header.me.user_id->size);
   103                 assert(user_id);
   104                 if (!user_id) {
   105                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   106                     return PEP_OUT_OF_MEMORY;
   107                 }
   108 
   109                 PEP_STATUS status = sequence_value(session, (char *) user_id,
   110                         &value);
   111 
   112                 if (status == PEP_STATUS_OK) {
   113                     status = session->inject_sync_msg(msg, session->sync_obj);
   114                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   115                     if (status != PEP_STATUS_OK)
   116                         return status;
   117                 }
   118             }
   119 
   120             bloblist_t *blob = bl;
   121             if (last)
   122                 last->next = bl->next;
   123             else
   124                 src->attachments = bl->next;
   125 
   126             blob->next = NULL;
   127             free_bloblist(blob);
   128         }
   129         else {
   130 skip:
   131             last = bl;
   132         }
   133     }
   134 
   135     if (found) {
   136         for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
   137                 spl = spl->next) {
   138             if (spl->value->key &&
   139                     strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
   140                 if (spl->value->value &&
   141                         strcasecmp(spl->value->value, "yes") == 0)
   142                     return PEP_MESSAGE_CONSUMED;
   143             }
   144         }
   145     }
   146 
   147     return PEP_STATUS_OK;
   148 }
   149 
   150 DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type)
   151 {
   152     DeviceGroup_Protocol_t *msg = (DeviceGroup_Protocol_t *)
   153             calloc(1, sizeof(DeviceGroup_Protocol_t));
   154     assert(msg);
   155     if (!msg)
   156         return NULL;
   157     msg->payload.present = type;
   158     return msg;
   159 }
   160 
   161 void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg)
   162 {
   163     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   164 }
   165 
   166 PEP_STATUS unicast_msg(
   167         PEP_SESSION session,
   168         const Identity partner,
   169         DeviceState_state state,
   170         DeviceGroup_Protocol_t *msg,
   171         bool encrypted
   172     )
   173 {
   174     PEP_STATUS status = PEP_STATUS_OK;
   175     char *payload = NULL;
   176     message *_message = NULL;
   177     pEp_identity *me = NULL;
   178     pEp_identity *_me = NULL;
   179 
   180     assert(session && partner && state && msg);
   181     if (!(session && partner && state && msg))
   182         return PEP_ILLEGAL_VALUE;
   183 
   184     assert(session->messageToSend);
   185     if (!session->messageToSend) {
   186         status = PEP_SEND_FUNCTION_NOT_REGISTERED;
   187         goto error;
   188     }
   189 
   190     msg->header.version.major = SYNC_VERSION_MAJOR;
   191     msg->header.version.minor = SYNC_VERSION_MINOR;
   192 
   193     status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
   194     if (status != PEP_STATUS_OK)
   195         goto error;
   196     
   197     int32_t seq = 0;
   198 
   199     status = sequence_value(session, sync_uuid, &seq);
   200     if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK)
   201         goto error;
   202 
   203     msg->header.sequence = (long) seq;
   204 
   205     _me = identity_dup(me);
   206     if (!_me)
   207         goto enomem;
   208 
   209     free(_me->user_id);
   210     _me->user_id = strndup(sync_uuid, 36);
   211     assert(_me->user_id);
   212     if (!_me->user_id)
   213         goto enomem;
   214 
   215     if (Identity_from_Struct(_me, &msg->header.me) == NULL)
   216         goto enomem;
   217 
   218     free_identity(_me);
   219     _me = NULL;
   220 
   221     msg->header.state = (long) state;
   222 
   223     bool devicegroup = storedGroupKeys(session);
   224     if (devicegroup)
   225         msg->header.devicegroup = 1;
   226     else
   227         msg->header.devicegroup = 0;
   228 
   229     if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) {
   230         status = PEP_CONTRAINTS_VIOLATED;
   231         goto error;
   232     }
   233 
   234     ssize_t size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol,
   235             NULL, msg, (void **) &payload);
   236     if (size == -1) {
   237         status = PEP_CANNOT_ENCODE;
   238         goto error;
   239     }
   240 
   241     status = prepare_message(me, partner, payload, size, &_message);
   242     if (status != PEP_STATUS_OK)
   243         goto error;
   244     payload = NULL;
   245     free_identity(me);
   246     me = NULL;
   247 
   248     if (encrypted) {
   249         if (msg->payload.present == DeviceGroup_Protocol__payload_PR_groupKeys) {
   250             PEP_rating rating = PEP_rating_undefined;
   251             status = outgoing_message_rating(session, _message, &rating);
   252             if (status != PEP_STATUS_OK)
   253                 goto error;
   254             if (rating < PEP_rating_trusted) {
   255                 status = PEP_SYNC_NO_TRUST;
   256                 goto error;
   257             }
   258             
   259             IdentityList_t *list = &msg->payload.choice.groupKeys.ownIdentities;
   260             for (int i=0; i<list->list.count; i++) {
   261                 Identity_t *ident = list->list.array[i];
   262                 bloblist_t *bl = bloblist_add(_message->attachments,
   263                         (char *) ident->fpr.buf, ident->fpr.size,
   264                         "application/pgp-keys", "");
   265                 if (!bl)
   266                     goto enomem;
   267                 if (!_message->attachments)
   268                     _message->attachments = bl;
   269             }
   270         }
   271 
   272         message *_encrypted = NULL;
   273         status = encrypt_message(session, _message, NULL, &_encrypted, PEP_enc_PEP, 0);
   274         if (status != PEP_STATUS_OK)
   275             goto error;
   276         free_message(_message);
   277         _message = _encrypted;
   278     }
   279 
   280     status = session->messageToSend(session->sync_obj, _message);
   281     return status;
   282 
   283 enomem:
   284     status = PEP_OUT_OF_MEMORY;
   285 error:
   286     free_identity(_me);
   287     free(payload);
   288     free_message(_message);
   289     free_identity(me);
   290     return status;
   291 }
   292 
   293 PEP_STATUS multicast_self_msg(
   294         PEP_SESSION session,
   295         DeviceState_state state,
   296         DeviceGroup_Protocol_t *msg,
   297         bool encrypted
   298     )
   299 {
   300     PEP_STATUS status = PEP_STATUS_OK;
   301 
   302     assert(session && state && msg);
   303     if (!(session && state && msg))
   304         return PEP_ILLEGAL_VALUE;
   305 
   306     identity_list *own_identities = NULL;
   307     status = own_identities_retrieve(session, &own_identities);
   308     if (status != PEP_STATUS_OK)
   309         return status;
   310 
   311     for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
   312         pEp_identity *me = _i->ident;
   313 
   314         // FIXME: no deep copy for multicast supported yet
   315         DeviceGroup_Protocol_t *_msg = malloc(sizeof(DeviceGroup_Protocol_t));
   316         assert(_msg);
   317         if (_msg == NULL)
   318             goto enomem;
   319         memcpy(_msg, msg, sizeof(DeviceGroup_Protocol_t));
   320         status = unicast_msg(session, me, state, _msg, encrypted);
   321         free_DeviceGroup_Protocol_msg(_msg);
   322     }
   323 
   324     free_identity_list(own_identities);
   325     return PEP_STATUS_OK;
   326 
   327 enomem:
   328     free_identity_list(own_identities);
   329     return PEP_OUT_OF_MEMORY;
   330 }
   331