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