src/sync_impl.c
author Edouard Tisserant <edouard@pep-project.org>
Mon, 03 Oct 2016 19:08:15 +0200
branchkeysync
changeset 1236 991afc1aa2a1
parent 1216 76e7a6748913
child 1242 e7b0ff022963
permissions -rw-r--r--
sync : attach_sync_session
     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 struct _sync_msg_t {
    13     bool is_a_message;
    14     union {
    15         DeviceGroup_Protocol_t *message;
    16         struct {
    17             DeviceState_event event;
    18             Identity partner;
    19             void *extra;
    20         } event;
    21     } u;
    22 };
    23 
    24 PEP_STATUS receive_sync_msg(
    25         PEP_SESSION session,
    26         sync_msg_t *sync_msg
    27     )
    28 {
    29     PEP_STATUS status;
    30     void *extra = NULL;
    31     Identity partner = NULL;
    32     DeviceState_event event = DeviceState_event_NONE;
    33     assert(session && sync_msg);
    34     if (!(session && sync_msg))
    35         return PEP_ILLEGAL_VALUE;
    36 
    37     if(sync_msg->is_a_message){
    38         DeviceGroup_Protocol_t *msg = sync_msg->u.message;
    39         assert(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING);
    40         if (!(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING)){
    41             status = PEP_OUT_OF_MEMORY;
    42             goto error;
    43         }
    44 
    45         switch (msg->payload.present) {
    46             case DeviceGroup_Protocol__payload_PR_beacon:
    47                 partner = Identity_to_Struct(&msg->header.me, NULL);
    48                 if (!partner){
    49                     status = PEP_OUT_OF_MEMORY;
    50                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    51                     goto error;
    52                 }
    53                 event = Beacon;
    54                 break;
    55 
    56             case DeviceGroup_Protocol__payload_PR_handshakeRequest:
    57                 partner = Identity_to_Struct(&msg->header.me, NULL);
    58                 if (!partner){
    59                     status = PEP_OUT_OF_MEMORY;
    60                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    61                     goto error;
    62                 }
    63                 event = HandshakeRequest;
    64                 break;
    65 
    66             case DeviceGroup_Protocol__payload_PR_groupKeys:
    67                 partner = Identity_to_Struct(&msg->header.me, NULL);
    68                 if (!partner){
    69                     status = PEP_OUT_OF_MEMORY;
    70                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    71                     goto error;
    72                 }
    73                 identity_list *group_keys = IdentityList_to_identity_list(
    74                         &msg->payload.choice.groupKeys.ownIdentities, NULL);
    75                 if (!group_keys) {
    76                     free_identity(partner);
    77                     status = PEP_OUT_OF_MEMORY;
    78                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    79                     goto error;
    80                 }
    81                 extra = (void *) group_keys;
    82                 event = GroupKeys;
    83                 break;
    84 
    85             default:
    86                 status = PEP_SYNC_ILLEGAL_MESSAGE;
    87                 ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
    88                 goto error;
    89         }
    90     }
    91     else{
    92         partner = sync_msg->u.event.partner;
    93         extra = sync_msg->u.event.extra;
    94         event = sync_msg->u.event.event;
    95     }
    96 
    97     status = fsm_DeviceState_inject(session, event, partner, extra);
    98 
    99     free_identity(partner);
   100 
   101 error:
   102     free(sync_msg);
   103 
   104     return status;
   105 }
   106 
   107 DYNAMIC_API void free_sync_msg(sync_msg_t *sync_msg)
   108 {
   109     assert(sync_msg);
   110     if (!(sync_msg))
   111         return;
   112 
   113     if(sync_msg->is_a_message){
   114         DeviceGroup_Protocol_t *msg = sync_msg->u.message;
   115         assert(msg);
   116         if (!(msg))
   117             return;
   118 
   119         ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   120     }
   121     else{
   122         Identity partner = NULL;
   123         partner = sync_msg->u.event.partner;
   124         if(partner != NULL)
   125             free_identity(partner);
   126     }
   127 
   128     free(sync_msg);
   129 
   130     return;
   131 }
   132 
   133 // from sync.c
   134 int call_inject_sync_msg(PEP_SESSION session, void *msg);
   135 
   136 PEP_STATUS inject_DeviceState_event(
   137     PEP_SESSION session, 
   138     DeviceState_event event,
   139     Identity partner,
   140     void *extra)
   141 {
   142     PEP_STATUS status;
   143 
   144     assert(session);
   145     if (!(session))
   146         return PEP_ILLEGAL_VALUE;
   147 
   148     sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
   149     if(sync_msg == NULL)
   150         return PEP_OUT_OF_MEMORY;
   151 
   152     sync_msg->is_a_message = false;
   153     sync_msg->u.event.partner = partner;
   154     sync_msg->u.event.extra = extra;
   155     sync_msg->u.event.event = event;
   156 
   157     status = call_inject_sync_msg(session, sync_msg);
   158     if (status == PEP_SYNC_NO_INJECT_CALLBACK){
   159         free(sync_msg);
   160     }
   161 
   162     return status;
   163 }
   164 
   165 PEP_STATUS receive_DeviceState_msg(
   166     PEP_SESSION session, 
   167     message *src, 
   168     PEP_rating rating, 
   169     stringlist_t *keylist)
   170 {
   171     assert(session && src);
   172     if (!(session && src))
   173         return PEP_ILLEGAL_VALUE;
   174 
   175     bool found = false;
   176     
   177     bloblist_t *last = NULL;
   178     for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
   179         if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0
   180                 && bl->size) {
   181             DeviceGroup_Protocol_t *msg = NULL;
   182             uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **)
   183                     &msg, bl->value, bl->size);
   184             if (msg) {
   185 
   186                 int32_t value = (int32_t) msg->header.sequence;
   187                 char *user_id = strndup((char *) msg->header.me.user_id->buf,
   188                         msg->header.me.user_id->size);
   189                 assert(user_id);
   190                 if (!user_id) {
   191                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   192                     return PEP_OUT_OF_MEMORY;
   193                 }
   194 
   195                 switch (msg->payload.present) {
   196                     // HandshakeRequest needs encryption
   197                     case DeviceGroup_Protocol__payload_PR_handshakeRequest:
   198                         if (rating < PEP_rating_reliable ||
   199                             strncmp(session->sync_uuid,
   200                                     (const char *)msg->payload.choice.handshakeRequest.partner.user_id->buf,
   201                                     msg->payload.choice.handshakeRequest.partner.user_id->size) != 0){
   202                             ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   203                             free(user_id);
   204                             return PEP_MESSAGE_DISCARDED;
   205                         }
   206                         break;
   207                     // accepting GroupKeys needs encryption and trust
   208                     case DeviceGroup_Protocol__payload_PR_groupKeys:
   209                         if (!keylist || rating < PEP_rating_reliable ||
   210                             strncmp(session->sync_uuid,
   211                                     (const char *)msg->payload.choice.groupKeys.partner.user_id->buf,
   212                                     msg->payload.choice.groupKeys.partner.user_id->size) != 0){
   213                             ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   214                             free(user_id);
   215                             return PEP_MESSAGE_DISCARDED;
   216                         }
   217 
   218                         // check trust of identity with the right user_id
   219                         pEp_identity *_from = new_identity(src->from->address, 
   220                                                            keylist->value,
   221                                                            user_id,
   222                                                            src->from->username);
   223                         if (_from == NULL){
   224                             free(user_id);
   225                             ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   226                             return PEP_OUT_OF_MEMORY;
   227                         }
   228                         PEP_rating this_user_id_rating = PEP_rating_undefined;
   229                         identity_rating(session, _from, &this_user_id_rating);
   230                         free_identity(_from);
   231 
   232                         if (this_user_id_rating < PEP_rating_trusted ) {
   233                             ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   234                             free(user_id);
   235                             return PEP_MESSAGE_DISCARDED;
   236                         }
   237                         break;
   238                     default:
   239                         break;
   240                 }
   241 
   242 
   243                 PEP_STATUS status = sequence_value(session, (char *) user_id,
   244                         &value);
   245 
   246                 if (status == PEP_STATUS_OK) {
   247                     found = true;
   248                     sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
   249                     if(sync_msg == NULL){
   250                         ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   251                         return PEP_OUT_OF_MEMORY;
   252                     }
   253                     sync_msg->is_a_message = true;
   254                     sync_msg->u.message = msg;
   255                     status = call_inject_sync_msg(session, sync_msg);
   256                     if (status != PEP_STATUS_OK){
   257                         ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   258                         if (status == PEP_SYNC_NO_INJECT_CALLBACK){
   259                             free(sync_msg);
   260                         }
   261                         return status;
   262                     }
   263                 }
   264                 else if (status == PEP_OWN_SEQUENCE) {
   265                     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   266                     return PEP_MESSAGE_DISCARDED;
   267                 }
   268             }
   269 
   270             if (!session->keep_sync_msg) {
   271                 bloblist_t *blob = bl;
   272                 if (last)
   273                     last->next = bl->next;
   274                 else
   275                     src->attachments = bl->next;
   276 
   277                 blob->next = NULL;
   278                 free_bloblist(blob);
   279             }
   280             else {
   281                 last = bl;
   282             }
   283         }
   284         else {
   285             last = bl;
   286         }
   287     }
   288 
   289     if (found && !session->keep_sync_msg) {
   290         for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
   291                 spl = spl->next) {
   292             if (spl->value->key &&
   293                     strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
   294                 if (spl->value->value &&
   295                         strcasecmp(spl->value->value, "yes") == 0)
   296                     return PEP_MESSAGE_CONSUMED;
   297             }
   298         }
   299     }
   300 
   301     return PEP_STATUS_OK;
   302 }
   303 
   304 DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type)
   305 {
   306     DeviceGroup_Protocol_t *msg = (DeviceGroup_Protocol_t *)
   307             calloc(1, sizeof(DeviceGroup_Protocol_t));
   308     assert(msg);
   309     if (!msg)
   310         return NULL;
   311     msg->payload.present = type;
   312     return msg;
   313 }
   314 
   315 void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg)
   316 {
   317     ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   318 }
   319 
   320 PEP_STATUS unicast_msg(
   321         PEP_SESSION session,
   322         const Identity partner,
   323         DeviceState_state state,
   324         DeviceGroup_Protocol_t *msg,
   325         bool encrypted
   326     )
   327 {
   328     PEP_STATUS status = PEP_STATUS_OK;
   329     char *payload = NULL;
   330     message *_message = NULL;
   331     pEp_identity *me = NULL;
   332     pEp_identity *_me = NULL;
   333 
   334     assert(session && partner && state && msg);
   335     if (!(session && partner && state && msg))
   336         return PEP_ILLEGAL_VALUE;
   337 
   338     assert(session->messageToSend);
   339     if (!session->messageToSend) {
   340         status = PEP_SEND_FUNCTION_NOT_REGISTERED;
   341         goto error;
   342     }
   343 
   344     msg->header.version.major = SYNC_VERSION_MAJOR;
   345     msg->header.version.minor = SYNC_VERSION_MINOR;
   346 
   347     status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
   348     if (status != PEP_STATUS_OK)
   349         goto error;
   350     
   351     int32_t seq = 0;
   352 
   353     status = sequence_value(session, session->sync_uuid, &seq);
   354     if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK)
   355         goto error;
   356 
   357     msg->header.sequence = (long) seq;
   358 
   359     _me = identity_dup(me);
   360     if (!_me)
   361         goto enomem;
   362 
   363     free(_me->user_id);
   364     _me->user_id = strndup(session->sync_uuid, 36);
   365     assert(_me->user_id);
   366     if (!_me->user_id)
   367         goto enomem;
   368 
   369     if (Identity_from_Struct(_me, &msg->header.me) == NULL)
   370         goto enomem;
   371 
   372     free_identity(_me);
   373     _me = NULL;
   374 
   375     msg->header.state = (long) state;
   376 
   377     bool devicegroup = storedGroupKeys(session);
   378     if (devicegroup)
   379         msg->header.devicegroup = 1;
   380     else
   381         msg->header.devicegroup = 0;
   382 
   383     if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) {
   384         status = PEP_CONTRAINTS_VIOLATED;
   385         goto error;
   386     }
   387 
   388     ssize_t size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol,
   389             NULL, msg, (void **) &payload);
   390     if (size == -1) {
   391         status = PEP_CANNOT_ENCODE;
   392         goto error;
   393     }
   394 
   395     status = prepare_message(me, partner, payload, size, &_message);
   396     if (status != PEP_STATUS_OK)
   397         goto error;
   398     payload = NULL;
   399     free_identity(me);
   400     me = NULL;
   401 
   402     if (encrypted) {
   403         if (msg->payload.present == DeviceGroup_Protocol__payload_PR_groupKeys) {
   404             PEP_rating rating = PEP_rating_undefined;
   405             status = outgoing_message_rating(session, _message, &rating);
   406             if (status != PEP_STATUS_OK)
   407                 goto error;
   408             if (rating < PEP_rating_trusted) {
   409                 status = PEP_SYNC_NO_TRUST;
   410                 goto error;
   411             }
   412             
   413             IdentityList_t *list = &msg->payload.choice.groupKeys.ownIdentities;
   414             for (int i=0; i<list->list.count; i++) {
   415                 Identity_t *ident = list->list.array[i];
   416                 char *fpr = strndup((const char *)ident->fpr.buf, ident->fpr.size);
   417                 assert(fpr);
   418                 if (!fpr)
   419                     goto enomem;
   420                 static char filename[MAX_LINELENGTH];
   421                 int result = snprintf(filename, MAX_LINELENGTH, "%s-sec.asc", fpr);
   422                 if (result < 0)
   423                     goto enomem;
   424                 char *key = NULL;
   425                 size_t size = 0;
   426                 status = export_secrect_key(session, fpr, &key, &size);
   427                 free(fpr);
   428                 if (status != PEP_STATUS_OK)
   429                     goto error;
   430                 bloblist_t *bl = bloblist_add(_message->attachments,
   431                         (char *) key, size, "application/pgp-keys", filename);
   432                 if (!bl)
   433                     goto enomem;
   434                 if (!_message->attachments)
   435                     _message->attachments = bl;
   436             }
   437         }
   438 
   439         message *_encrypted = NULL;
   440         status = encrypt_message(session, _message, NULL, &_encrypted, PEP_enc_PEP, 0);
   441         if (status != PEP_STATUS_OK)
   442             goto error;
   443         free_message(_message);
   444         _message = _encrypted;
   445     }
   446     else {
   447         attach_own_key(session, _message);
   448     }
   449 
   450     status = session->messageToSend(session->sync_obj, _message);
   451     return status;
   452 
   453 enomem:
   454     status = PEP_OUT_OF_MEMORY;
   455 error:
   456     free_identity(_me);
   457     free(payload);
   458     free_message(_message);
   459     free_identity(me);
   460     return status;
   461 }
   462 
   463 PEP_STATUS multicast_self_msg(
   464         PEP_SESSION session,
   465         DeviceState_state state,
   466         DeviceGroup_Protocol_t *msg,
   467         bool encrypted
   468     )
   469 {
   470     PEP_STATUS status = PEP_STATUS_OK;
   471 
   472     assert(session && state && msg);
   473     if (!(session && state && msg))
   474         return PEP_ILLEGAL_VALUE;
   475 
   476     identity_list *own_identities = NULL;
   477     status = own_identities_retrieve(session, &own_identities);
   478     if (status != PEP_STATUS_OK)
   479         return status;
   480 
   481     // FIXME: exclude previously rejected identities
   482     for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
   483         pEp_identity *me = _i->ident;
   484 
   485         // FIXME: no deep copy for multicast supported yet
   486         DeviceGroup_Protocol_t *_msg = malloc(sizeof(DeviceGroup_Protocol_t));
   487         assert(_msg);
   488         if (_msg == NULL)
   489             goto enomem;
   490         memcpy(_msg, msg, sizeof(DeviceGroup_Protocol_t));
   491         status = unicast_msg(session, me, state, _msg, encrypted);
   492         free_DeviceGroup_Protocol_msg(_msg);
   493     }
   494 
   495     free_identity_list(own_identities);
   496     return PEP_STATUS_OK;
   497 
   498 enomem:
   499     free_identity_list(own_identities);
   500     return PEP_OUT_OF_MEMORY;
   501 }
   502