src/message_api.c
author vb
Sat, 07 Mar 2015 20:29:13 +0100
changeset 89 aef5a4bc78f3
parent 85 6fd10806c186
child 90 42b5eb9d5af2
permissions -rw-r--r--
...
vb@37
     1
#include "message_api.h"
vb@37
     2
#include "keymanagement.h"
vb@62
     3
#include "mime.h"
vb@37
     4
vb@85
     5
#ifndef WIN32 // POSIX
vb@85
     6
#define _POSIX_C_SOURCE 200809L
vb@85
     7
#include <strings.h>
vb@85
     8
#else
vb@85
     9
#include "platform_windows.h"
vb@85
    10
#endif
vb@85
    11
vb@37
    12
#include <assert.h>
vb@37
    13
#include <string.h>
vb@39
    14
#include <stdlib.h>
vb@39
    15
vb@76
    16
#define NOT_IMPLEMENTED assert(0); return PEP_UNKNOWN_ERROR;
vb@37
    17
vb@83
    18
static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
vb@62
    19
{
vb@62
    20
    char * ptext;
vb@81
    21
vb@83
    22
    assert(shortmsg);
vb@83
    23
    assert(strcmp(shortmsg, "pEp") != 0);
vb@62
    24
vb@83
    25
    if (longmsg == NULL)
vb@63
    26
        longmsg = "";
vb@63
    27
vb@83
    28
    ptext = calloc(1, strlen(shortmsg) + strlen(longmsg) + 12);
vb@62
    29
    if (ptext == NULL)
vb@62
    30
        return NULL;
vb@62
    31
vb@85
    32
    strcpy(ptext, "Subject: ");
vb@83
    33
    strcat(ptext, shortmsg);
vb@62
    34
    strcat(ptext, "\n\n");
vb@63
    35
    strcat(ptext, longmsg);
vb@62
    36
vb@62
    37
    return ptext;
vb@62
    38
}
vb@44
    39
vb@82
    40
static int seperate_short_and_long(const char *src, char **shortmsg, char **longmsg)
vb@82
    41
{
vb@82
    42
    char *_shortmsg = NULL;
vb@82
    43
    char *_longmsg = NULL;
vb@82
    44
vb@82
    45
    assert(src);
vb@82
    46
    assert(shortmsg);
vb@82
    47
    assert(longmsg);
vb@82
    48
vb@82
    49
    *shortmsg = NULL;
vb@82
    50
    *longmsg = NULL;
vb@82
    51
vb@85
    52
    if (strncasecmp(src, "subject: ", 9) == 0) {
vb@82
    53
        char *line_end = strchr(src, '\n');
vb@82
    54
        
vb@82
    55
        if (line_end == NULL) {
vb@82
    56
            _shortmsg = strdup(src + 9);
vb@82
    57
            if (_shortmsg == NULL)
vb@82
    58
                goto enomem;
vb@82
    59
            // _longmsg = NULL;
vb@82
    60
        }
vb@82
    61
        else {
vb@82
    62
            size_t n = line_end - src;
vb@82
    63
            if (*(line_end - 1) == '\r')
vb@82
    64
                _shortmsg = strndup(src + 9, n - 1);
vb@82
    65
            else
vb@82
    66
                _shortmsg = strndup(src + 9, n);
vb@82
    67
            if (_shortmsg == NULL)
vb@82
    68
                goto enomem;
vb@82
    69
            _longmsg = strdup(src + n);
vb@82
    70
            if (_longmsg == NULL)
vb@82
    71
                goto enomem;
vb@82
    72
        }
vb@82
    73
    }
vb@82
    74
    else {
vb@82
    75
        _shortmsg = strdup("pEp");
vb@82
    76
        if (_shortmsg == NULL)
vb@82
    77
            goto enomem;
vb@82
    78
        _longmsg = strdup(src);
vb@82
    79
        if (_longmsg == NULL)
vb@82
    80
            goto enomem;
vb@82
    81
    }
vb@82
    82
    
vb@82
    83
    *shortmsg = _shortmsg;
vb@82
    84
    *longmsg = _longmsg;
vb@82
    85
vb@82
    86
    return 0;
vb@82
    87
vb@82
    88
enomem:
vb@82
    89
    free(_shortmsg);
vb@82
    90
    free(_longmsg);
vb@82
    91
vb@82
    92
    return -1;
vb@82
    93
}
vb@82
    94
vb@81
    95
static message * clone_to_empty_message(const message * src)
vb@80
    96
{
vb@80
    97
    pEp_identity *from = NULL;
vb@80
    98
    identity_list *to = NULL;
vb@81
    99
vb@80
   100
    message * msg = NULL;
vb@80
   101
vb@81
   102
    assert(src);
vb@81
   103
    assert(src->from);
vb@81
   104
    assert(src->to);
vb@81
   105
vb@80
   106
    from = identity_dup(src->from);
vb@80
   107
    if (from == NULL)
vb@80
   108
        goto enomem;
vb@80
   109
vb@80
   110
    from->me = true;
vb@80
   111
vb@80
   112
    to = identity_list_dup(src->to);
vb@80
   113
    if (to == NULL)
vb@80
   114
        goto enomem;
vb@80
   115
vb@80
   116
    msg = new_message(src->dir, from, to, NULL);
vb@80
   117
    if (msg == NULL)
vb@80
   118
        goto enomem;
vb@80
   119
vb@82
   120
    msg->dir = src->dir;
vb@82
   121
vb@81
   122
    if (src->cc) {
vb@81
   123
        msg->cc = identity_list_dup(src->cc);
vb@81
   124
        if (msg->cc == NULL)
vb@81
   125
            goto enomem;
vb@81
   126
    }
vb@81
   127
vb@81
   128
    if (src->bcc) {
vb@81
   129
        msg->bcc = identity_list_dup(src->bcc);
vb@81
   130
        if (msg->bcc == NULL)
vb@81
   131
            goto enomem;
vb@81
   132
    }
vb@81
   133
vb@81
   134
    if (src->reply_to) {
vb@81
   135
        msg->reply_to = identity_dup(src->reply_to);
vb@81
   136
        if (msg->reply_to == NULL)
vb@81
   137
            goto enomem;
vb@81
   138
    }
vb@81
   139
vb@81
   140
    msg->sent = src->sent;
vb@81
   141
    msg->recv = src->recv;
vb@81
   142
vb@80
   143
    return msg;
vb@80
   144
vb@80
   145
enomem:
vb@81
   146
    if (msg) {
vb@81
   147
        free_message(msg);
vb@81
   148
    }
vb@81
   149
    else {
vb@81
   150
        free_identity(from);
vb@81
   151
        free_identity_list(to);
vb@81
   152
    }
vb@81
   153
vb@80
   154
    return NULL;
vb@80
   155
}
vb@80
   156
vb@48
   157
DYNAMIC_API PEP_STATUS encrypt_message(
vb@37
   158
        PEP_SESSION session,
vb@37
   159
        const message *src,
vb@37
   160
        stringlist_t * extra,
vb@38
   161
        message **dst,
vb@81
   162
        PEP_enc_format enc_format
vb@37
   163
    )
vb@37
   164
{
vb@37
   165
    PEP_STATUS status = PEP_STATUS_OK;
vb@63
   166
    message * msg = NULL;
vb@63
   167
    stringlist_t * keys = NULL;
vb@37
   168
vb@37
   169
    assert(session);
vb@37
   170
    assert(src);
vb@37
   171
    assert(dst);
vb@81
   172
    assert(enc_format >= PEP_enc_pieces);
vb@81
   173
vb@37
   174
    *dst = NULL;
vb@67
   175
vb@81
   176
    if (src->enc_format >= PEP_enc_pieces) {
vb@81
   177
        if (src->enc_format == enc_format) {
vb@81
   178
            msg = message_dup(src);
vb@81
   179
            if (msg == NULL)
vb@81
   180
                goto enomem;
vb@81
   181
            *dst = msg;
vb@81
   182
            return PEP_STATUS_OK;
vb@81
   183
        }
vb@81
   184
        else {
vb@81
   185
            // TODO: we don't re-encrypt yet
vb@81
   186
            NOT_IMPLEMENTED
vb@81
   187
        }
vb@67
   188
    }
vb@37
   189
vb@81
   190
    msg = clone_to_empty_message(src);
vb@80
   191
    if (msg == NULL)
vb@63
   192
        goto enomem;
vb@40
   193
vb@48
   194
    msg->enc_format = PEP_enc_pieces;
vb@37
   195
vb@80
   196
    status = myself(session, src->from);
vb@63
   197
    if (status != PEP_STATUS_OK)
vb@63
   198
        goto pep_error;
vb@37
   199
vb@80
   200
    keys = new_stringlist(src->from->fpr);
vb@63
   201
    if (keys == NULL)
vb@63
   202
        goto enomem;
vb@37
   203
vb@39
   204
    stringlist_t *_k = keys;
vb@39
   205
vb@39
   206
    if (extra) {
vb@39
   207
        _k = stringlist_append(_k, extra);
vb@63
   208
        if (_k == NULL)
vb@63
   209
            goto enomem;
vb@37
   210
    }
vb@39
   211
vb@39
   212
    bool dest_keys_found = false;
vb@37
   213
    identity_list * _il;
vb@80
   214
    for (_il = msg->to; _il && _il->ident; _il = _il->next) {
vb@63
   215
        PEP_STATUS status = update_identity(session, _il->ident);
vb@63
   216
        if (status != PEP_STATUS_OK)
vb@63
   217
            goto pep_error;
vb@63
   218
vb@37
   219
        if (_il->ident->fpr) {
vb@39
   220
            dest_keys_found = true;
vb@39
   221
            _k = stringlist_add(_k, _il->ident->fpr);
vb@63
   222
            if (_k == NULL)
vb@63
   223
                goto enomem;
vb@37
   224
        }
vb@37
   225
        else
vb@37
   226
            status = PEP_KEY_NOT_FOUND;
vb@37
   227
    }
vb@37
   228
vb@39
   229
    if (dest_keys_found) {
vb@38
   230
        char *ptext;
vb@37
   231
        char *ctext = NULL;
vb@37
   232
        size_t csize = 0;
vb@37
   233
vb@81
   234
        switch (enc_format) {
vb@44
   235
        case PEP_enc_MIME_multipart: {
vb@62
   236
            bool free_ptext = false;
vb@64
   237
vb@48
   238
            msg->enc_format = PEP_enc_MIME_multipart;
vb@37
   239
vb@63
   240
            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@83
   241
                ptext = combine_short_and_long(src->shortmsg, src->longmsg);
vb@63
   242
                if (ptext == NULL)
vb@63
   243
                    goto enomem;
vb@62
   244
                free_ptext = true;
vb@62
   245
            }
vb@62
   246
            else if (src->longmsg) {
vb@62
   247
                ptext = src->longmsg;
vb@62
   248
            }
vb@62
   249
vb@81
   250
            if (src->enc_format == PEP_enc_none) {
vb@89
   251
                message *_src = (message *) malloc(sizeof(message));
vb@89
   252
                assert(_src);
vb@89
   253
                if (_src == NULL)
vb@89
   254
                    goto enomem;
vb@89
   255
                memcpy(_src, src, sizeof(message));
vb@89
   256
                _src->shortmsg = "pEp";
vb@89
   257
                _src->longmsg = ptext;
vb@89
   258
                status = mime_encode_message(src, &ptext);
vb@67
   259
                assert(status == PEP_STATUS_OK);
vb@67
   260
                if (free_ptext)
vb@89
   261
                    free(_src->longmsg);
vb@89
   262
                free(_src);
vb@67
   263
                assert(ptext);
vb@67
   264
                if (ptext == NULL)
vb@67
   265
                    goto pep_error;
vb@67
   266
                free_ptext = true;
vb@67
   267
            }
vb@81
   268
            else if (src->enc_format == PEP_enc_none_MIME) {
vb@67
   269
                assert(src->longmsg);
vb@67
   270
                if (src->longmsg == NULL) {
vb@67
   271
                    status = PEP_ILLEGAL_VALUE;
vb@67
   272
                    goto pep_error;
vb@67
   273
                }
vb@67
   274
                ptext = src->longmsg;
vb@67
   275
            }
vb@67
   276
vb@67
   277
            status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@67
   278
                    &ctext, &csize);
vb@62
   279
            if (free_ptext)
vb@62
   280
                free(ptext);
vb@62
   281
            if (ctext) {
vb@62
   282
                msg->longmsg = strdup(ctext);
vb@64
   283
                if (msg->longmsg == NULL)
vb@63
   284
                    goto enomem;
vb@63
   285
            }
vb@63
   286
            else {
vb@63
   287
                goto pep_error;
vb@62
   288
            }
vb@62
   289
        }
vb@63
   290
        break;
vb@62
   291
vb@62
   292
        case PEP_enc_pieces:
vb@64
   293
            msg->enc_format = PEP_enc_pieces;
vb@64
   294
vb@67
   295
            // TODO: decoding MIME
vb@81
   296
            if (src->enc_format == PEP_enc_none_MIME) {
vb@67
   297
                NOT_IMPLEMENTED
vb@67
   298
            }
vb@67
   299
vb@63
   300
            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@83
   301
                ptext = combine_short_and_long(src->shortmsg, src->longmsg);
vb@63
   302
                if (ptext == NULL)
vb@63
   303
                    goto enomem;
vb@63
   304
vb@39
   305
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   306
                        &ctext, &csize);
vb@40
   307
                free(ptext);
vb@38
   308
                if (ctext) {
vb@40
   309
                    msg->longmsg = strdup(ctext);
vb@64
   310
                    if (msg->longmsg == NULL)
vb@63
   311
                        goto enomem;
vb@38
   312
                }
vb@38
   313
                else {
vb@63
   314
                    goto pep_error;
vb@38
   315
                }
vb@38
   316
            }
vb@38
   317
            else if (src->longmsg) {
vb@38
   318
                ptext = src->longmsg;
vb@39
   319
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   320
                        &ctext, &csize);
vb@38
   321
                if (ctext) {
vb@40
   322
                    msg->longmsg = strdup(ctext);
vb@64
   323
                    if (msg->longmsg == NULL)
vb@63
   324
                        goto enomem;
vb@38
   325
                }
vb@38
   326
                else {
vb@63
   327
                    goto pep_error;
vb@38
   328
                }
vb@38
   329
            }
vb@63
   330
vb@63
   331
            if (msg->longmsg_formatted) {
vb@38
   332
                ptext = src->longmsg_formatted;
vb@39
   333
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   334
                        &ctext, &csize);
vb@38
   335
                if (ctext) {
vb@40
   336
                    msg->longmsg_formatted = strdup(ctext);
vb@63
   337
                    if (msg->longmsg_formatted == NULL)
vb@63
   338
                        goto enomem;
vb@63
   339
                }
vb@63
   340
                else {
vb@63
   341
                    goto pep_error;
vb@63
   342
                }
vb@63
   343
            }
vb@63
   344
vb@63
   345
            if (src->attachments) {
vb@63
   346
                bloblist_t *_s;
vb@63
   347
                bloblist_t *_d = new_bloblist(NULL, 0, NULL, NULL);
vb@63
   348
                if (_d == NULL)
vb@63
   349
                    goto enomem;
vb@63
   350
vb@63
   351
                msg->attachments = _d;
vb@63
   352
                for (_s = src->attachments; _s && _s->data; _s = _s->next) {
vb@63
   353
                    int psize = _s->size;
vb@63
   354
                    ptext = _s->data;
vb@63
   355
                    status = encrypt_and_sign(session, keys, ptext, psize,
vb@63
   356
                            &ctext, &csize);
vb@63
   357
                    if (ctext) {
vb@63
   358
                        char * _c = strdup(ctext);
vb@63
   359
                        if (_c == NULL)
vb@63
   360
                            goto enomem;
vb@63
   361
vb@63
   362
                        _d = bloblist_add(_d, _c, csize, _s->mime_type,
vb@63
   363
                                _s->file_name);
vb@63
   364
                        if (_d == NULL)
vb@63
   365
                            goto enomem;
vb@63
   366
                    }
vb@63
   367
                    else {
vb@63
   368
                        goto pep_error;
vb@40
   369
                    }
vb@38
   370
                }
vb@38
   371
            }
vb@38
   372
            break;
vb@38
   373
vb@81
   374
        case PEP_enc_PEP:
vb@81
   375
            // TODO: implement
vb@81
   376
            NOT_IMPLEMENTED
vb@81
   377
vb@38
   378
        default:
vb@38
   379
            assert(0);
vb@63
   380
            status = PEP_ILLEGAL_VALUE;
vb@63
   381
            goto pep_error;
vb@37
   382
        }
vb@37
   383
    }
vb@37
   384
vb@37
   385
    free_stringlist(keys);
vb@63
   386
vb@64
   387
    if (msg->shortmsg == NULL)
vb@64
   388
        msg->shortmsg = strdup("pEp");
vb@64
   389
vb@63
   390
    *dst = msg;
vb@63
   391
    return PEP_STATUS_OK;
vb@63
   392
vb@63
   393
enomem:
vb@63
   394
    status = PEP_OUT_OF_MEMORY;
vb@63
   395
vb@63
   396
pep_error:
vb@63
   397
    free_stringlist(keys);
vb@63
   398
    free_message(msg);
vb@63
   399
vb@37
   400
    return status;
vb@37
   401
}
vb@37
   402
vb@48
   403
DYNAMIC_API PEP_STATUS decrypt_message(
vb@37
   404
        PEP_SESSION session,
vb@37
   405
        const message *src,
vb@81
   406
        message **dst,
vb@81
   407
        PEP_enc_format enc_format
vb@37
   408
    )
vb@37
   409
{
vb@37
   410
    PEP_STATUS status = PEP_STATUS_OK;
vb@73
   411
    message *msg = NULL;
vb@37
   412
vb@74
   413
    assert(session);
vb@74
   414
    assert(src);
vb@81
   415
    assert(src->dir == PEP_dir_incoming);
vb@74
   416
    assert(dst);
vb@81
   417
    assert(enc_format < PEP_enc_pieces);
vb@73
   418
vb@74
   419
    *dst = NULL;
vb@81
   420
 
vb@81
   421
    if (src->enc_format < PEP_enc_pieces) {
vb@81
   422
        if (enc_format == src->enc_format) {
vb@81
   423
            msg = message_dup(src);
vb@81
   424
            if (msg == NULL)
vb@81
   425
                goto enomem;
vb@81
   426
            *dst = msg;
vb@81
   427
            return PEP_STATUS_OK;
vb@81
   428
        }
vb@81
   429
        else {
vb@81
   430
            // TODO: we don't re-encode yet
vb@81
   431
            NOT_IMPLEMENTED
vb@81
   432
        }
vb@81
   433
    }
vb@81
   434
vb@81
   435
    msg = clone_to_empty_message(src);
vb@81
   436
    if (msg == NULL)
vb@81
   437
        goto enomem;
vb@81
   438
vb@81
   439
    switch (enc_format) {
vb@81
   440
        case PEP_enc_none:
vb@85
   441
            // TODO: implement
vb@85
   442
            NOT_IMPLEMENTED
vb@81
   443
vb@81
   444
        case PEP_enc_none_MIME:
vb@82
   445
            if (src->enc_format == PEP_enc_PEP) {
vb@82
   446
                // TODO: implement
vb@82
   447
                NOT_IMPLEMENTED
vb@82
   448
            }
vb@82
   449
vb@82
   450
            char *ctext = src->longmsg;
vb@82
   451
            size_t csize = strlen(src->longmsg);
vb@82
   452
            char *ptext;
vb@82
   453
            size_t psize;
vb@82
   454
            stringlist_t *keylist;
vb@82
   455
vb@82
   456
            status = decrypt_and_verify(session, ctext, csize, &ptext, &psize,
vb@82
   457
                    &keylist);
vb@82
   458
            if (ptext == NULL)
vb@82
   459
                goto pep_error;
vb@82
   460
vb@82
   461
            if (src->enc_format == PEP_enc_MIME_multipart) {
vb@82
   462
                if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
vb@82
   463
                {
vb@82
   464
                    char * shortmsg;
vb@82
   465
                    char * longmsg;
vb@82
   466
vb@82
   467
                    int r = seperate_short_and_long(ptext, &shortmsg,
vb@82
   468
                            &longmsg);
vb@82
   469
                    free(ptext);
vb@82
   470
                    if (r == -1)
vb@82
   471
                        goto enomem;
vb@82
   472
vb@82
   473
                    msg->shortmsg = shortmsg;
vb@82
   474
                    msg->longmsg = longmsg;
vb@82
   475
                }
vb@82
   476
                else {
vb@82
   477
                    msg->shortmsg = strdup(src->shortmsg);
vb@82
   478
                    if (msg->shortmsg == NULL)
vb@82
   479
                        goto enomem;
vb@82
   480
                    msg->longmsg = ptext;
vb@82
   481
                }
vb@82
   482
            }
vb@82
   483
            else {
vb@82
   484
                
vb@82
   485
            }
vb@81
   486
            break;
vb@81
   487
vb@81
   488
        default:
vb@81
   489
            assert(0);
vb@81
   490
            status = PEP_ILLEGAL_VALUE;
vb@81
   491
            goto pep_error;
vb@81
   492
    }
vb@74
   493
vb@74
   494
    *dst = msg;
vb@74
   495
    return PEP_STATUS_OK;
vb@73
   496
vb@73
   497
enomem:
vb@73
   498
    status = PEP_OUT_OF_MEMORY;
vb@73
   499
vb@73
   500
pep_error:
vb@73
   501
    free_message(msg);
vb@39
   502
vb@37
   503
    return status;
vb@37
   504
}
vb@37
   505