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