src/sync_impl.c
author Edouard Tisserant <edouard@pep-project.org>
Wed, 01 Mar 2017 15:45:56 +0100
branchAllGroupDevicesShowHandshake
changeset 1607 f22aa0501060
parent 1606 c3f8396acee4
child 1608 16c78f261d78
permissions -rw-r--r--
KeySync: accept handshake requests addressed to group (partner-id = group's UUID)
vb@1513
     1
// This file is under GNU General Public License 3.0
vb@1513
     2
// see LICENSE.txt
vb@1513
     3
edouard@1261
     4
#include "platform.h"
edouard@1260
     5
edouard@1260
     6
// it seems pEp_internal.h needs to be the first pEp include due to the 
markus@1259
     7
// #define for the dllimport / dllexport DYNAMIC_API stuff.
markus@1259
     8
#include "pEp_internal.h"
markus@1259
     9
vb@1059
    10
#include "sync_impl.h"
vb@1059
    11
#include "keymanagement.h"
vb@1076
    12
#include "message_api.h"
vb@1059
    13
#include "map_asn1.h"
vb@1059
    14
#include "baseprotocol.h"
vb@1059
    15
vb@1077
    16
#define SYNC_VERSION_MAJOR 1
vb@1077
    17
#define SYNC_VERSION_MINOR 0
vb@1077
    18
edouard@1316
    19
#define SYNC_INHIBIT_TIME (60*10)
edouard@1316
    20
#define SYNC_MSG_EXPIRE_TIME (60 * 10)
edouard@1316
    21
edouard@1172
    22
struct _sync_msg_t {
edouard@1172
    23
    bool is_a_message;
edouard@1172
    24
    union {
edouard@1172
    25
        DeviceGroup_Protocol_t *message;
edouard@1172
    26
        struct {
edouard@1172
    27
            DeviceState_event event;
edouard@1172
    28
            Identity partner;
edouard@1172
    29
            void *extra;
edouard@1172
    30
        } event;
edouard@1172
    31
    } u;
edouard@1172
    32
};
edouard@1172
    33
edouard@1605
    34
static bool _is_own_uuid( PEP_SESSION session, UTF8String_t *uuid)
edouard@1605
    35
{
edouard@1605
    36
    return strncmp(session->sync_session->sync_uuid,
edouard@1606
    37
                   (const char*)uuid->buf, uuid->size) == 0;
edouard@1605
    38
}
edouard@1605
    39
edouard@1605
    40
static bool _is_own_group_uuid( PEP_SESSION session, UTF8String_t *uuid)
edouard@1605
    41
{
edouard@1605
    42
    PEP_STATUS status;
edouard@1605
    43
    char *devgrp = NULL;
edouard@1605
    44
edouard@1605
    45
    status = get_device_group(session, &devgrp);
edouard@1605
    46
edouard@1605
    47
    bool res = (status == PEP_STATUS_OK && devgrp && devgrp[0] &&
edouard@1605
    48
        strncmp(devgrp,(const char*)uuid->buf, uuid->size) == 0);
edouard@1605
    49
    free(devgrp);
edouard@1605
    50
    return res;
edouard@1605
    51
}
edouard@1605
    52
vb@1059
    53
PEP_STATUS receive_sync_msg(
vb@1059
    54
        PEP_SESSION session,
edouard@1445
    55
        sync_msg_t *sync_msg,
edouard@1445
    56
        time_t *timeout
vb@1059
    57
    )
vb@1059
    58
{
edouard@1172
    59
    PEP_STATUS status;
vb@1059
    60
    void *extra = NULL;
vb@1059
    61
    Identity partner = NULL;
vb@1059
    62
    DeviceState_event event = DeviceState_event_NONE;
edouard@1172
    63
    assert(session && sync_msg);
edouard@1172
    64
    if (!(session && sync_msg))
edouard@1172
    65
        return PEP_ILLEGAL_VALUE;
vb@1059
    66
edouard@1340
    67
    bool msgIsFromGroup = false;
edouard@1172
    68
    if(sync_msg->is_a_message){
edouard@1172
    69
        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
edouard@1172
    70
        assert(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING);
edouard@1172
    71
        if (!(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING)){
edouard@1172
    72
            status = PEP_OUT_OF_MEMORY;
edouard@1172
    73
            goto error;
edouard@1172
    74
        }
vb@1059
    75
edouard@1605
    76
        partner = Identity_to_Struct(&msg->header.me, NULL);
edouard@1605
    77
        if (!partner){
edouard@1605
    78
            status = PEP_OUT_OF_MEMORY;
edouard@1605
    79
            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1605
    80
            goto error;
edouard@1605
    81
        }
edouard@1605
    82
edouard@1340
    83
        msgIsFromGroup = msg->header.devicegroup;
edouard@1340
    84
edouard@1172
    85
        switch (msg->payload.present) {
edouard@1172
    86
            case DeviceGroup_Protocol__payload_PR_beacon:
edouard@1172
    87
                event = Beacon;
edouard@1172
    88
                break;
vb@1059
    89
edouard@1172
    90
            case DeviceGroup_Protocol__payload_PR_handshakeRequest:
edouard@1575
    91
                // re-check uuid in case sync_uuid changed while in the queue
edouard@1605
    92
edouard@1605
    93
// TODO check matching group-ID as well
edouard@1605
    94
edouard@1606
    95
                if (!_is_own_uuid(session, 
edouard@1606
    96
                        msg->payload.choice.handshakeRequest.partner_id)){
edouard@1575
    97
                    status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1575
    98
                    goto error;
edouard@1575
    99
                }
edouard@1586
   100
edouard@1586
   101
                if(msgIsFromGroup) {
edouard@1606
   102
                    if(_is_own_group_uuid(session, 
edouard@1606
   103
                           msg->payload.choice.handshakeRequest.group_id)) {
edouard@1586
   104
                        status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1586
   105
                        goto error;
edouard@1586
   106
                    }
edouard@1586
   107
                    // if it comes from another group, then this is groupmerge
edouard@1605
   108
                    
edouard@1605
   109
// TODO insert handshake request's group id into partner's id
edouard@1605
   110
edouard@1586
   111
                }
edouard@1586
   112
edouard@1316
   113
                event = HandshakeRequest;
edouard@1316
   114
                break;
edouard@1256
   115
edouard@1316
   116
            case DeviceGroup_Protocol__payload_PR_updateRequest:
edouard@1316
   117
                event = UpdateRequest;
edouard@1172
   118
                break;
vb@1059
   119
edouard@1172
   120
            case DeviceGroup_Protocol__payload_PR_groupKeys:
edouard@1586
   121
            {
edouard@1575
   122
                // re-check uuid in case sync_uuid changed while in the queue
edouard@1606
   123
                if (!_is_own_uuid(session, 
edouard@1606
   124
                        msg->payload.choice.groupKeys.partner_id)){
edouard@1575
   125
                    status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1575
   126
                    goto error;
edouard@1575
   127
                }
edouard@1586
   128
                group_keys_extra_t *group_keys_extra;
edouard@1586
   129
                group_keys_extra = malloc(sizeof(group_keys_extra_t));
edouard@1586
   130
                if(group_keys_extra == NULL){
edouard@1586
   131
                    status = PEP_OUT_OF_MEMORY;
edouard@1586
   132
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1586
   133
                    goto error;
edouard@1586
   134
                }
edouard@1586
   135
edouard@1586
   136
                char *group_id = strndup(
edouard@1586
   137
                        (char*)msg->payload.choice.groupKeys.group_id->buf,
edouard@1586
   138
                        msg->payload.choice.groupKeys.group_id->size);
edouard@1586
   139
edouard@1586
   140
                if (msg->payload.choice.groupKeys.group_id && !group_id){
edouard@1586
   141
                    status = PEP_OUT_OF_MEMORY;
edouard@1586
   142
                    free(group_keys_extra);
edouard@1586
   143
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1586
   144
                    goto error;
edouard@1586
   145
                }
edouard@1586
   146
                group_keys_extra->group_id = group_id;
edouard@1586
   147
edouard@1172
   148
                identity_list *group_keys = IdentityList_to_identity_list(
edouard@1587
   149
                        &msg->payload.choice.groupKeys.ownIdentities,
edouard@1281
   150
                        NULL);
edouard@1172
   151
                if (!group_keys) {
edouard@1172
   152
                    status = PEP_OUT_OF_MEMORY;
edouard@1586
   153
                    free(group_id);
edouard@1586
   154
                    free(group_keys_extra);
edouard@1586
   155
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1586
   156
                    goto error;
edouard@1586
   157
                }
edouard@1586
   158
                group_keys_extra->group_keys = group_keys;
edouard@1586
   159
edouard@1586
   160
                extra = (void *) group_keys_extra;
edouard@1587
   161
                event = GroupKeys;
edouard@1586
   162
edouard@1586
   163
                break;
edouard@1586
   164
            }
edouard@1586
   165
            case DeviceGroup_Protocol__payload_PR_groupUpdate:
edouard@1586
   166
            {
edouard@1586
   167
                identity_list *group_keys = IdentityList_to_identity_list(
edouard@1586
   168
                        &msg->payload.choice.groupUpdate.ownIdentities, NULL);
edouard@1586
   169
                if (!group_keys) {
edouard@1586
   170
                    status = PEP_OUT_OF_MEMORY;
edouard@1172
   171
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1172
   172
                    goto error;
edouard@1172
   173
                }
edouard@1172
   174
                extra = (void *) group_keys;
edouard@1586
   175
                event = GroupUpdate;
edouard@1172
   176
                break;
edouard@1316
   177
            }
edouard@1172
   178
edouard@1172
   179
            default:
edouard@1172
   180
                status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1172
   181
                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1172
   182
                goto error;
edouard@1172
   183
        }
edouard@1316
   184
edouard@1172
   185
    }
edouard@1172
   186
    else{
edouard@1172
   187
        partner = sync_msg->u.event.partner;
edouard@1172
   188
        extra = sync_msg->u.event.extra;
edouard@1172
   189
        event = sync_msg->u.event.event;
vb@1059
   190
    }
vb@1059
   191
edouard@1316
   192
    // Event inhibition, to limit mailbox and prevent cycles
edouard@1316
   193
    time_t *last = NULL;
edouard@1316
   194
    switch(event){
edouard@1316
   195
        case CannotDecrypt:
edouard@1316
   196
            last = &session->LastCannotDecrypt;
edouard@1316
   197
            break;
edouard@1316
   198
edouard@1316
   199
        case UpdateRequest:
edouard@1316
   200
            last = &session->LastUpdateRequest;
edouard@1316
   201
            break;
edouard@1316
   202
edouard@1316
   203
        default:
edouard@1316
   204
            break;
edouard@1316
   205
    }
edouard@1567
   206
edouard@1316
   207
    if(last != NULL){
edouard@1567
   208
        time_t now = time(NULL);
edouard@1316
   209
        if(*last != 0 && (*last + SYNC_INHIBIT_TIME) > now ){
edouard@1316
   210
            status = PEP_STATEMACHINE_INHIBITED_EVENT;
edouard@1316
   211
            goto error;
edouard@1316
   212
        }
edouard@1316
   213
        *last = now;
edouard@1316
   214
    }
edouard@1316
   215
edouard@1256
   216
    // partner identity must be explicitely added DB to later
edouard@1256
   217
    // be able to communicate securely with it.
edouard@1256
   218
    if(partner){
edouard@1260
   219
        // protect virtual user IDs 
edouard@1256
   220
        if((strncmp("TOFU_", partner->user_id, 6) == 0 &&
edouard@1256
   221
           strlen(partner->user_id) == strlen(partner->address) + 6 &&
edouard@1256
   222
           strcmp(partner->user_id + 6, partner->address)) ||
edouard@1260
   223
        // protect own ID 
edouard@1256
   224
           (strcmp(PEP_OWN_USERID, partner->user_id) == 0)){
edouard@1256
   225
            status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1256
   226
            goto error;
edouard@1256
   227
        }
edouard@1256
   228
edouard@1260
   229
        // partner IDs are UUIDs bound to session lifespan
edouard@1256
   230
        // and therefore partner identities are not supposed
edouard@1260
   231
        // to mutate over time, but just not be used anymore.
edouard@1260
   232
        // It should then be safe to accept given identity if not 
edouard@1256
   233
        // already pre-existing
edouard@1256
   234
        pEp_identity *stored_identity = NULL;
edouard@1256
   235
        status = get_identity(session,
edouard@1256
   236
                              partner->address,
edouard@1256
   237
                              partner->user_id,
edouard@1256
   238
                              &stored_identity);
edouard@1256
   239
edouard@1256
   240
        if (!stored_identity) {
edouard@1260
   241
            // make a safe copy of partner, with no flags or comm_type
edouard@1260
   242
            pEp_identity *tmpident = new_identity(partner->address,
edouard@1260
   243
                                                  partner->fpr,
edouard@1260
   244
                                                  partner->user_id,
edouard@1260
   245
                                                  partner->username);
edouard@1260
   246
            if (tmpident == NULL){
edouard@1260
   247
                status = PEP_OUT_OF_MEMORY;
edouard@1260
   248
                goto error;
edouard@1260
   249
            }
edouard@1260
   250
edouard@1260
   251
            // finaly add partner to DB
edouard@1260
   252
            status = set_identity(session, tmpident);
edouard@1340
   253
            assert(status == PEP_STATUS_OK);
edouard@1340
   254
            if(status == PEP_STATUS_OK && msgIsFromGroup)
edouard@1340
   255
                status = set_identity_flags(session, tmpident, PEP_idf_devicegroup);
edouard@1260
   256
            free_identity(tmpident);
edouard@1256
   257
            assert(status == PEP_STATUS_OK);
edouard@1256
   258
            if (status != PEP_STATUS_OK) {
edouard@1256
   259
                goto error;
edouard@1256
   260
            }
edouard@1256
   261
        }
edouard@1256
   262
        else if (status == PEP_STATUS_OK) {
edouard@1256
   263
            free_identity(stored_identity);
edouard@1256
   264
        } 
edouard@1256
   265
        else
edouard@1256
   266
            goto error;
edouard@1256
   267
    }
edouard@1256
   268
edouard@1445
   269
    status = fsm_DeviceState_inject(session, event, partner, extra, timeout);
edouard@1157
   270
edouard@1587
   271
error:
edouard@1587
   272
edouard@1157
   273
    free_identity(partner);
edouard@1157
   274
edouard@1587
   275
    switch(event){
edouard@1587
   276
        case GroupKeys:
edouard@1587
   277
        {
edouard@1597
   278
            free_group_keys_extra((group_keys_extra_t*)extra);
edouard@1587
   279
            break;
edouard@1587
   280
        }
edouard@1587
   281
        case GroupUpdate:
edouard@1587
   282
        {
edouard@1587
   283
            identity_list *group_keys = (identity_list*) extra;
edouard@1587
   284
            free_identity_list(group_keys);
edouard@1587
   285
            break;
edouard@1587
   286
        }
edouard@1587
   287
        default:
edouard@1587
   288
            assert(extra==NULL);
edouard@1587
   289
            break;
edouard@1587
   290
    }
edouard@1587
   291
edouard@1172
   292
    free(sync_msg);
edouard@1172
   293
edouard@1159
   294
    return status;
vb@1059
   295
}
vb@1059
   296
markus@1226
   297
// TODO: DYNAMIC_API was here, but broke the windows build. 
markus@1226
   298
// We need to check whether it belongs here or it's a bug.
markus@1226
   299
/* DYNAMIC_API */ void free_sync_msg(sync_msg_t *sync_msg)
Edouard@1203
   300
{
roker@1482
   301
    if (!sync_msg)
Edouard@1203
   302
        return;
Edouard@1203
   303
Edouard@1203
   304
    if(sync_msg->is_a_message){
Edouard@1203
   305
        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
Edouard@1203
   306
        assert(msg);
Edouard@1203
   307
        if (!(msg))
Edouard@1203
   308
            return;
Edouard@1203
   309
Edouard@1203
   310
        ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
Edouard@1203
   311
    }
Edouard@1203
   312
    else{
Edouard@1203
   313
        Identity partner = NULL;
Edouard@1203
   314
        partner = sync_msg->u.event.partner;
Edouard@1203
   315
        if(partner != NULL)
Edouard@1203
   316
            free_identity(partner);
Edouard@1203
   317
    }
Edouard@1203
   318
Edouard@1203
   319
    free(sync_msg);
Edouard@1203
   320
Edouard@1203
   321
    return;
Edouard@1203
   322
}
Edouard@1203
   323
edouard@1167
   324
// from sync.c
edouard@1167
   325
int call_inject_sync_msg(PEP_SESSION session, void *msg);
edouard@1167
   326
edouard@1172
   327
PEP_STATUS inject_DeviceState_event(
edouard@1172
   328
    PEP_SESSION session, 
edouard@1172
   329
    DeviceState_event event,
edouard@1172
   330
    Identity partner,
edouard@1172
   331
    void *extra)
edouard@1172
   332
{
edouard@1172
   333
    PEP_STATUS status;
edouard@1172
   334
edouard@1172
   335
    assert(session);
edouard@1172
   336
    if (!(session))
edouard@1172
   337
        return PEP_ILLEGAL_VALUE;
edouard@1172
   338
edouard@1172
   339
    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
edouard@1172
   340
    if(sync_msg == NULL)
edouard@1172
   341
        return PEP_OUT_OF_MEMORY;
edouard@1172
   342
edouard@1172
   343
    sync_msg->is_a_message = false;
edouard@1172
   344
    sync_msg->u.event.partner = partner;
edouard@1172
   345
    sync_msg->u.event.extra = extra;
edouard@1172
   346
    sync_msg->u.event.event = event;
edouard@1172
   347
edouard@1172
   348
    status = call_inject_sync_msg(session, sync_msg);
edouard@1172
   349
    if (status == PEP_SYNC_NO_INJECT_CALLBACK){
edouard@1172
   350
        free(sync_msg);
edouard@1172
   351
    }
edouard@1172
   352
edouard@1172
   353
    return status;
edouard@1172
   354
}
edouard@1172
   355
edouard@1165
   356
PEP_STATUS receive_DeviceState_msg(
edouard@1165
   357
    PEP_SESSION session, 
edouard@1165
   358
    message *src, 
edouard@1165
   359
    PEP_rating rating, 
edouard@1165
   360
    stringlist_t *keylist)
vb@1059
   361
{
vb@1059
   362
    assert(session && src);
vb@1059
   363
    if (!(session && src))
vb@1059
   364
        return PEP_ILLEGAL_VALUE;
vb@1059
   365
edouard@1339
   366
    bool consume = false;
edouard@1339
   367
    bool discard = false;
edouard@1248
   368
    bool force_keep_msg = false;
vb@1338
   369
vb@1059
   370
    for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
vb@1132
   371
        if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0
vb@1059
   372
                && bl->size) {
vb@1077
   373
            DeviceGroup_Protocol_t *msg = NULL;
vb@1091
   374
            uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **)
vb@1091
   375
                    &msg, bl->value, bl->size);
edouard@1248
   376
vb@1059
   377
            if (msg) {
edouard@1257
   378
                PEP_STATUS status = PEP_STATUS_OK;
vb@1088
   379
vb@1091
   380
                char *user_id = strndup((char *) msg->header.me.user_id->buf,
vb@1091
   381
                        msg->header.me.user_id->size);
vb@1091
   382
                assert(user_id);
vb@1091
   383
                if (!user_id) {
vb@1091
   384
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
vb@1091
   385
                    return PEP_OUT_OF_MEMORY;
vb@1091
   386
                }
vb@1091
   387
edouard@1521
   388
                // detect and mitigate address spoofing
edouard@1521
   389
                Identity check_me = NULL;
edouard@1527
   390
                char* null_terminated_address = 
edouard@1521
   391
                    strndup((char *) msg->header.me.address->buf,
edouard@1521
   392
                            msg->header.me.address->size);
edouard@1521
   393
edouard@1527
   394
                if(null_terminated_address){
edouard@1527
   395
                    status = get_identity(session, 
edouard@1527
   396
                                          null_terminated_address, 
edouard@1527
   397
                                          PEP_OWN_USERID, 
edouard@1527
   398
                                          &check_me);
edouard@1527
   399
                    free(null_terminated_address);
edouard@1527
   400
                } 
edouard@1527
   401
                else
edouard@1527
   402
                    status = PEP_OUT_OF_MEMORY;
edouard@1521
   403
edouard@1521
   404
                if (status == PEP_OUT_OF_MEMORY)
edouard@1521
   405
                    goto free_all;
edouard@1521
   406
edouard@1521
   407
                free_identity(check_me);
edouard@1521
   408
edouard@1521
   409
                bool not_own_address = status != PEP_STATUS_OK;
edouard@1521
   410
                status = PEP_STATUS_OK;
edouard@1521
   411
edouard@1521
   412
                if (not_own_address || 
edouard@1521
   413
                    strncmp(src->from->address,
edouard@1521
   414
                            (char *) msg->header.me.address->buf,
edouard@1521
   415
                            msg->header.me.address->size) != 0 ||
edouard@1521
   416
                    strncmp(src->to->ident->address,
edouard@1521
   417
                            (char *) msg->header.me.address->buf,
edouard@1521
   418
                            msg->header.me.address->size) != 0) {
edouard@1521
   419
                    consume = true;
edouard@1521
   420
                    goto free_all;
edouard@1521
   421
                }
edouard@1521
   422
edouard@1521
   423
                // if encrypted, ensure that header.me.fpr match signer's fpr
edouard@1521
   424
                if (rating >= PEP_rating_reliable && (
edouard@1521
   425
                        !keylist ||
edouard@1521
   426
                        !_same_fpr((char *) msg->header.me.fpr.buf,
edouard@1521
   427
                                   msg->header.me.fpr.size,
edouard@1521
   428
                                   keylist->value,
edouard@1521
   429
                                   strlen(keylist->value)))) {
edouard@1521
   430
                    consume = true;
edouard@1521
   431
                    goto free_all;
edouard@1521
   432
                }
edouard@1521
   433
edouard@1248
   434
                // check message expiry 
edouard@1257
   435
                if(src->recv) {
edouard@1316
   436
                    time_t expiry = timegm(src->recv) + SYNC_MSG_EXPIRE_TIME;
edouard@1257
   437
                    time_t now = time(NULL);
edouard@1257
   438
                    if(expiry != 0 && now != 0 && expiry < now){
edouard@1339
   439
                        consume = true;
edouard@1257
   440
                        goto free_all;
edouard@1257
   441
                    }
edouard@1165
   442
                }
edouard@1165
   443
edouard@1248
   444
                int32_t value = (int32_t) msg->header.sequence;
edouard@1568
   445
                if (value < 1) {
edouard@1568
   446
                    status = PEP_SEQUENCE_VIOLATED;
edouard@1568
   447
                } else {
edouard@1568
   448
                    status = sequence_value(session, (char *) user_id,
edouard@1568
   449
                            &value);
edouard@1568
   450
                }
vb@1088
   451
vb@1088
   452
                if (status == PEP_STATUS_OK) {
edouard@1248
   453
                    switch (msg->payload.present) {
edouard@1248
   454
                        // HandshakeRequest needs encryption
edouard@1248
   455
                        case DeviceGroup_Protocol__payload_PR_handshakeRequest:
edouard@1607
   456
                        {
edouard@1607
   457
                            bool is_for_me = _is_own_uuid(session, 
edouard@1607
   458
                                msg->payload.choice.handshakeRequest.partner_id);
edouard@1607
   459
                            bool is_for_group = !is_for_me && _is_own_group_uuid(session, 
edouard@1607
   460
                                msg->payload.choice.handshakeRequest.partner_id);
edouard@1248
   461
                            if (rating < PEP_rating_reliable ||
edouard@1607
   462
                                !(is_for_me || is_for_group)){
edouard@1339
   463
                                discard = true;
edouard@1256
   464
                                goto free_all;
edouard@1248
   465
                            }
edouard@1607
   466
                            if(is_for_group){ 
edouard@1607
   467
                                // if handshake request is for group then dont consume
edouard@1607
   468
                                force_keep_msg = true;
edouard@1607
   469
                            }
edouard@1248
   470
                            break;
edouard@1607
   471
                        }
edouard@1297
   472
                        // accepting GroupKeys needs encryption and trust of peer device
edouard@1248
   473
                        case DeviceGroup_Protocol__payload_PR_groupKeys:
edouard@1297
   474
                        {
edouard@1248
   475
                            if (!keylist || rating < PEP_rating_reliable ||
edouard@1297
   476
                                // message is only consumed by instance it is addressed to
edouard@1606
   477
                                !_is_own_uuid(session, 
edouard@1606
   478
                                    msg->payload.choice.groupKeys.partner_id)){
edouard@1339
   479
                                discard = true;
edouard@1256
   480
                                goto free_all;
edouard@1248
   481
                            }
edouard@1248
   482
edouard@1523
   483
                            // check trust of identity using user_id given in msg.header.me
edouard@1297
   484
                            // to exacly match identity of device, the one trusted in
edouard@1297
   485
                            // case of accepted handshake
edouard@1297
   486
                            pEp_identity *_from = new_identity(NULL, 
edouard@1248
   487
                                                               keylist->value,
edouard@1248
   488
                                                               user_id,
edouard@1297
   489
                                                               NULL);
edouard@1248
   490
                            if (_from == NULL){
edouard@1248
   491
                                status = PEP_OUT_OF_MEMORY;
edouard@1256
   492
                                goto free_all;
edouard@1248
   493
                            }
edouard@1297
   494
                            status = get_trust(session, _from);
edouard@1368
   495
                            if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) {
edouard@1368
   496
                                status = PEP_STATUS_OK;
edouard@1297
   497
                                free_identity(_from);
edouard@1339
   498
                                discard = true;
edouard@1256
   499
                                goto free_all;
edouard@1248
   500
                            }
edouard@1297
   501
                            free_identity(_from);
edouard@1248
   502
                            break;
edouard@1297
   503
                        }
edouard@1297
   504
                        case DeviceGroup_Protocol__payload_PR_groupUpdate:
edouard@1316
   505
                        case DeviceGroup_Protocol__payload_PR_updateRequest:
edouard@1316
   506
                        {
edouard@1297
   507
                            // inject message but don't consume it, so 
edouard@1297
   508
                            // that other group members can also be updated
edouard@1297
   509
                            force_keep_msg = true;
edouard@1297
   510
                            
edouard@1297
   511
                            if (!keylist || rating < PEP_rating_reliable){
edouard@1339
   512
                                discard = true;
edouard@1297
   513
                                goto free_all;
edouard@1297
   514
                            }
edouard@1297
   515
                            // GroupUpdate and UpdateRequests come from group.
edouard@1297
   516
                            // check trust relation in between signer key and 
edouard@1297
   517
                            // own id to be sure.
edouard@1297
   518
                            pEp_identity *_from = new_identity(NULL, 
edouard@1297
   519
                                                               keylist->value,
edouard@1297
   520
                                                               PEP_OWN_USERID,
edouard@1297
   521
                                                               NULL);
edouard@1297
   522
                            if (_from == NULL){
edouard@1297
   523
                                status = PEP_OUT_OF_MEMORY;
edouard@1297
   524
                                goto free_all;
edouard@1297
   525
                            }
edouard@1297
   526
                            status = get_trust(session, _from);
edouard@1368
   527
                            if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_pEp) {
edouard@1368
   528
                                status = PEP_STATUS_OK;
edouard@1297
   529
                                free_identity(_from);
edouard@1339
   530
                                discard = true;
edouard@1297
   531
                                goto free_all;
edouard@1297
   532
                            }
edouard@1297
   533
                            free_identity(_from);
edouard@1297
   534
                        }
edouard@1248
   535
                        default:
edouard@1248
   536
                            break;
edouard@1248
   537
                    }
edouard@1248
   538
edouard@1248
   539
edouard@1339
   540
                    consume = true;
edouard@1172
   541
                    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
edouard@1172
   542
                    if(sync_msg == NULL){
edouard@1248
   543
                        status = PEP_OUT_OF_MEMORY;
edouard@1256
   544
                        goto free_all;
edouard@1172
   545
                    }
edouard@1172
   546
                    sync_msg->is_a_message = true;
edouard@1172
   547
                    sync_msg->u.message = msg;
edouard@1172
   548
                    status = call_inject_sync_msg(session, sync_msg);
edouard@1165
   549
                    if (status != PEP_STATUS_OK){
edouard@1172
   550
                        if (status == PEP_SYNC_NO_INJECT_CALLBACK){
edouard@1172
   551
                            free(sync_msg);
edouard@1172
   552
                        }
edouard@1256
   553
                        goto free_all;
edouard@1165
   554
                    }
edouard@1339
   555
                    // don't free message now that it is in the queue
edouard@1256
   556
                    goto free_userid;
edouard@1165
   557
                }
edouard@1165
   558
                else if (status == PEP_OWN_SEQUENCE) {
edouard@1248
   559
                    status = PEP_STATUS_OK;
edouard@1339
   560
                    discard = true;
edouard@1256
   561
                    goto free_all;
vb@1088
   562
                }
edouard@1248
   563
edouard@1256
   564
            free_all:
edouard@1248
   565
                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1256
   566
            free_userid:
edouard@1248
   567
                free(user_id);
edouard@1248
   568
edouard@1248
   569
                if (status != PEP_STATUS_OK)
edouard@1248
   570
                    return status;
vb@1059
   571
            }
vb@1059
   572
        }
vb@1059
   573
    }
vb@1059
   574
edouard@1248
   575
    if (force_keep_msg) {
edouard@1369
   576
        return PEP_MESSAGE_IGNORE;
edouard@1248
   577
    }
edouard@1248
   578
edouard@1339
   579
    if (consume && !session->keep_sync_msg) {
vb@1059
   580
        for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
vb@1059
   581
                spl = spl->next) {
vb@1059
   582
            if (spl->value->key &&
vb@1059
   583
                    strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
vb@1059
   584
                if (spl->value->value &&
vb@1059
   585
                        strcasecmp(spl->value->value, "yes") == 0)
edouard@1369
   586
                    return PEP_MESSAGE_CONSUME;
vb@1059
   587
            }
vb@1059
   588
        }
edouard@1369
   589
        return PEP_MESSAGE_IGNORE;
vb@1059
   590
    }
vb@1059
   591
edouard@1339
   592
    if(discard)
edouard@1369
   593
        return PEP_MESSAGE_IGNORE;
edouard@1248
   594
vb@1338
   595
    if (!session->keep_sync_msg) {
vb@1338
   596
        bloblist_t *last = NULL;
vb@1338
   597
        for (bloblist_t *bl = src->attachments; bl && bl->value; ) {
vb@1338
   598
            if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0) {
vb@1338
   599
                bloblist_t *b = bl;
vb@1338
   600
                bl = bl->next;
vb@1338
   601
                if (!last)
vb@1338
   602
                    src->attachments = bl;
vb@1338
   603
                else
vb@1338
   604
                    last->next = bl;
vb@1338
   605
                free(b->mime_type);
vb@1338
   606
                free(b->filename);
vb@1338
   607
                free(b->value);
vb@1338
   608
                free(b);
vb@1338
   609
            }
vb@1338
   610
            else {
vb@1338
   611
                last = bl;
vb@1338
   612
                bl = bl->next;
vb@1338
   613
            }
vb@1338
   614
        }
vb@1338
   615
    }
vb@1338
   616
vb@1059
   617
    return PEP_STATUS_OK;
vb@1059
   618
}
vb@1059
   619
vb@1059
   620
DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type)
vb@1059
   621
{
vb@1059
   622
    DeviceGroup_Protocol_t *msg = (DeviceGroup_Protocol_t *)
vb@1073
   623
            calloc(1, sizeof(DeviceGroup_Protocol_t));
vb@1059
   624
    assert(msg);
vb@1059
   625
    if (!msg)
vb@1059
   626
        return NULL;
vb@1059
   627
    msg->payload.present = type;
vb@1059
   628
    return msg;
vb@1059
   629
}
vb@1059
   630
vb@1059
   631
void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg)
vb@1059
   632
{
vb@1059
   633
    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
vb@1059
   634
}
vb@1059
   635
Edouard@1495
   636
Edouard@1495
   637
#ifndef NDEBUG
Edouard@1495
   638
static int _append(const void *buffer, size_t size, void *appkey)
edouard@1494
   639
{
edouard@1494
   640
    char **dest_ptr = (char **)appkey;
edouard@1494
   641
    size_t osize = strlen(*dest_ptr);
edouard@1494
   642
    size_t nsize = size + osize;
edouard@1494
   643
    *dest_ptr = realloc(*dest_ptr, nsize + 1);
edouard@1494
   644
    if(*dest_ptr == NULL) return -1;
edouard@1494
   645
    memcpy(*dest_ptr + osize, buffer, size);
edouard@1494
   646
    (*dest_ptr)[nsize] = '\0';
edouard@1494
   647
    return 0;
edouard@1494
   648
}
Edouard@1495
   649
#endif
edouard@1494
   650
vb@1059
   651
PEP_STATUS unicast_msg(
vb@1059
   652
        PEP_SESSION session,
vb@1091
   653
        const Identity partner,
vb@1059
   654
        DeviceState_state state,
vb@1097
   655
        DeviceGroup_Protocol_t *msg,
vb@1097
   656
        bool encrypted
vb@1059
   657
    )
vb@1059
   658
{
vb@1059
   659
    PEP_STATUS status = PEP_STATUS_OK;
vb@1059
   660
    char *payload = NULL;
vb@1059
   661
    message *_message = NULL;
vb@1059
   662
    pEp_identity *me = NULL;
vb@1088
   663
    pEp_identity *_me = NULL;
vb@1059
   664
vb@1059
   665
    assert(session && partner && state && msg);
vb@1059
   666
    if (!(session && partner && state && msg))
vb@1059
   667
        return PEP_ILLEGAL_VALUE;
vb@1059
   668
vb@1059
   669
    assert(session->messageToSend);
vb@1059
   670
    if (!session->messageToSend) {
vb@1059
   671
        status = PEP_SEND_FUNCTION_NOT_REGISTERED;
vb@1059
   672
        goto error;
vb@1059
   673
    }
vb@1059
   674
vb@1077
   675
    msg->header.version.major = SYNC_VERSION_MAJOR;
vb@1077
   676
    msg->header.version.minor = SYNC_VERSION_MINOR;
vb@1077
   677
vb@1071
   678
    status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
vb@1059
   679
    if (status != PEP_STATUS_OK)
vb@1059
   680
        goto error;
vb@1088
   681
    
vb@1088
   682
    int32_t seq = 0;
vb@1088
   683
edouard@1603
   684
    status = sequence_value(session, session->sync_session->sync_uuid, &seq);
vb@1088
   685
    if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK)
vb@1088
   686
        goto error;
vb@1088
   687
vb@1088
   688
    msg->header.sequence = (long) seq;
vb@1088
   689
vb@1088
   690
    _me = identity_dup(me);
vb@1088
   691
    if (!_me)
vb@1059
   692
        goto enomem;
vb@1059
   693
vb@1088
   694
    free(_me->user_id);
edouard@1603
   695
    _me->user_id = strndup(session->sync_session->sync_uuid, 36);
vb@1088
   696
    assert(_me->user_id);
vb@1088
   697
    if (!_me->user_id)
vb@1088
   698
        goto enomem;
vb@1088
   699
vb@1088
   700
    if (Identity_from_Struct(_me, &msg->header.me) == NULL)
vb@1088
   701
        goto enomem;
vb@1088
   702
vb@1088
   703
    free_identity(_me);
vb@1088
   704
    _me = NULL;
vb@1088
   705
vb@1077
   706
    msg->header.state = (long) state;
vb@1077
   707
edouard@1574
   708
    bool devicegroup = deviceGrouped(session);
vb@1077
   709
    if (devicegroup)
vb@1077
   710
        msg->header.devicegroup = 1;
vb@1077
   711
    else
vb@1077
   712
        msg->header.devicegroup = 0;
vb@1077
   713
vb@1059
   714
    if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) {
vb@1059
   715
        status = PEP_CONTRAINTS_VIOLATED;
vb@1059
   716
        goto error;
vb@1059
   717
    }
vb@1059
   718
vb@1059
   719
    ssize_t size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol,
vb@1059
   720
            NULL, msg, (void **) &payload);
vb@1059
   721
    if (size == -1) {
vb@1059
   722
        status = PEP_CANNOT_ENCODE;
vb@1059
   723
        goto error;
vb@1059
   724
    }
vb@1059
   725
vb@1059
   726
    status = prepare_message(me, partner, payload, size, &_message);
vb@1059
   727
    if (status != PEP_STATUS_OK)
vb@1059
   728
        goto error;
vb@1059
   729
    payload = NULL;
vb@1059
   730
    free_identity(me);
vb@1059
   731
    me = NULL;
vb@1059
   732
edouard@1494
   733
#ifndef NDEBUG
edouard@1494
   734
    asn_enc_rval_t er;
edouard@1494
   735
    er = xer_encode(&asn_DEF_DeviceGroup_Protocol, msg, 
edouard@1494
   736
                    XER_F_BASIC, _append, &_message->longmsg);
edouard@1494
   737
    if(er.encoded == -1)
edouard@1494
   738
        goto error;
edouard@1494
   739
#endif
edouard@1494
   740
vb@1097
   741
    if (encrypted) {
edouard@1386
   742
        if (msg->payload.present == DeviceGroup_Protocol__payload_PR_groupKeys || 
edouard@1386
   743
            msg->payload.present == DeviceGroup_Protocol__payload_PR_groupUpdate) {
vb@1101
   744
            PEP_rating rating = PEP_rating_undefined;
vb@1101
   745
            status = outgoing_message_rating(session, _message, &rating);
vb@1101
   746
            if (status != PEP_STATUS_OK)
vb@1101
   747
                goto error;
vb@1101
   748
            if (rating < PEP_rating_trusted) {
vb@1101
   749
                status = PEP_SYNC_NO_TRUST;
vb@1101
   750
                goto error;
vb@1101
   751
            }
edouard@1386
   752
            
edouard@1364
   753
            stringlist_t *keylist = NULL;
edouard@1412
   754
            status = _own_keys_retrieve(session, &keylist, PEP_idf_not_for_sync);
edouard@1364
   755
            if (status != PEP_STATUS_OK)
edouard@1364
   756
                goto error;
edouard@1281
   757
edouard@1364
   758
            for (stringlist_t *_keylist=keylist; _keylist!=NULL; _keylist=_keylist->next) {
edouard@1364
   759
                char *fpr = _keylist->value;
vb@1133
   760
                static char filename[MAX_LINELENGTH];
vb@1133
   761
                int result = snprintf(filename, MAX_LINELENGTH, "%s-sec.asc", fpr);
vb@1133
   762
                if (result < 0)
vb@1133
   763
                    goto enomem;
vb@1133
   764
                char *key = NULL;
vb@1133
   765
                size_t size = 0;
vb@1133
   766
                status = export_secrect_key(session, fpr, &key, &size);
vb@1133
   767
                if (status != PEP_STATUS_OK)
vb@1133
   768
                    goto error;
vb@1104
   769
                bloblist_t *bl = bloblist_add(_message->attachments,
vb@1133
   770
                        (char *) key, size, "application/pgp-keys", filename);
vb@1104
   771
                if (!bl)
vb@1104
   772
                    goto enomem;
vb@1104
   773
                if (!_message->attachments)
vb@1104
   774
                    _message->attachments = bl;
vb@1104
   775
            }
vb@1101
   776
        }
vb@1101
   777
vb@1097
   778
        message *_encrypted = NULL;
vb@1097
   779
        status = encrypt_message(session, _message, NULL, &_encrypted, PEP_enc_PEP, 0);
vb@1097
   780
        if (status != PEP_STATUS_OK)
vb@1097
   781
            goto error;
vb@1097
   782
        free_message(_message);
vb@1097
   783
        _message = _encrypted;
vb@1097
   784
    }
vb@1131
   785
    else {
vb@1131
   786
        attach_own_key(session, _message);
vb@1131
   787
    }
vb@1059
   788
vb@1097
   789
    status = session->messageToSend(session->sync_obj, _message);
vb@1059
   790
    return status;
vb@1059
   791
vb@1059
   792
enomem:
vb@1059
   793
    status = PEP_OUT_OF_MEMORY;
vb@1059
   794
error:
vb@1088
   795
    free_identity(_me);
vb@1059
   796
    free(payload);
vb@1059
   797
    free_message(_message);
vb@1059
   798
    free_identity(me);
vb@1059
   799
    return status;
vb@1059
   800
}
vb@1059
   801
vb@1059
   802
PEP_STATUS multicast_self_msg(
vb@1059
   803
        PEP_SESSION session,
vb@1059
   804
        DeviceState_state state,
vb@1097
   805
        DeviceGroup_Protocol_t *msg,
vb@1097
   806
        bool encrypted
vb@1059
   807
    )
vb@1059
   808
{
vb@1059
   809
    PEP_STATUS status = PEP_STATUS_OK;
vb@1059
   810
vb@1059
   811
    assert(session && state && msg);
vb@1059
   812
    if (!(session && state && msg))
vb@1059
   813
        return PEP_ILLEGAL_VALUE;
vb@1059
   814
vb@1059
   815
    identity_list *own_identities = NULL;
edouard@1412
   816
    status = _own_identities_retrieve(session, &own_identities, PEP_idf_not_for_sync);
vb@1059
   817
    if (status != PEP_STATUS_OK)
vb@1059
   818
        return status;
vb@1059
   819
vb@1059
   820
    for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
vb@1091
   821
        pEp_identity *me = _i->ident;
vb@1059
   822
vb@1065
   823
        // FIXME: no deep copy for multicast supported yet
edouard@1281
   824
        // DeviceGroup_Protocol_t *_msg = malloc(sizeof(DeviceGroup_Protocol_t));
edouard@1281
   825
        // assert(_msg);
edouard@1281
   826
        // if (_msg == NULL){
edouard@1281
   827
        //     status = PEP_OUT_OF_MEMORY;
edouard@1281
   828
        //     goto error;
edouard@1281
   829
        // }
edouard@1281
   830
        // memcpy(_msg, msg, sizeof(DeviceGroup_Protocol_t));
edouard@1281
   831
        status = unicast_msg(session, me, state, msg, encrypted);
edouard@1281
   832
        //status = unicast_msg(session, me, state, _msg, encrypted);
edouard@1281
   833
        //free_DeviceGroup_Protocol_msg(_msg);
vb@1059
   834
    }
vb@1059
   835
vb@1059
   836
    free_identity_list(own_identities);
vb@1059
   837
    return PEP_STATUS_OK;
vb@1065
   838
edouard@1281
   839
// error:
edouard@1281
   840
//     free_identity_list(own_identities);
edouard@1281
   841
//     return status;
vb@1059
   842
}
vb@1059
   843
edouard@1597
   844
void free_group_keys_extra(group_keys_extra_t* group_keys_extra)
edouard@1597
   845
{
edouard@1597
   846
    identity_list *group_keys = group_keys_extra->group_keys;
edouard@1597
   847
    char *group_id = group_keys_extra->group_id;
edouard@1597
   848
    free_identity_list(group_keys);
edouard@1597
   849
    free(group_id);
edouard@1597
   850
    free(group_keys_extra);
edouard@1597
   851
}
edouard@1597
   852
edouard@1597
   853
group_keys_extra_t* group_keys_extra_dup(group_keys_extra_t* groupkeys)
edouard@1597
   854
{
edouard@1597
   855
    group_keys_extra_t *group_keys_extra;
edouard@1597
   856
    group_keys_extra = malloc(sizeof(group_keys_extra_t));
edouard@1597
   857
    if(group_keys_extra == NULL){
edouard@1597
   858
        return NULL;
edouard@1597
   859
    }
edouard@1597
   860
edouard@1597
   861
    char *group_id = strdup(group_keys_extra->group_id);
edouard@1597
   862
edouard@1597
   863
    if (group_keys_extra->group_id && !group_id){
edouard@1597
   864
        free(group_keys_extra);
edouard@1597
   865
        return NULL;
edouard@1597
   866
    }
edouard@1597
   867
    group_keys_extra->group_id = group_id;
edouard@1597
   868
edouard@1597
   869
    identity_list *group_keys = identity_list_dup(group_keys_extra->group_keys);;
edouard@1597
   870
    if (!group_keys) {
edouard@1597
   871
        free(group_id);
edouard@1597
   872
        free(group_keys_extra);
edouard@1597
   873
        return NULL;
edouard@1597
   874
    }
edouard@1597
   875
    group_keys_extra->group_keys = group_keys;
edouard@1597
   876
edouard@1597
   877
    return group_keys_extra;
edouard@1597
   878
}
edouard@1597
   879