src/keymanagement.c
author Krista Grothoff <krista@pep-project.org>
Wed, 05 Oct 2016 14:56:54 +0200
branchENGINE-107
changeset 1243 f1ca06851a48
parent 1241 4e6ff02a9257
child 1253 6acef0303310
permissions -rw-r--r--
ENGINE-107: added ct and rating states for having no key
vb@130
     1
#include "platform.h"
vb@0
     2
vb@0
     3
#include <string.h>
vb@0
     4
#include <stdio.h>
vb@0
     5
#include <stdlib.h>
vb@0
     6
#include <assert.h>
Edouard@512
     7
#include <ctype.h>
vb@0
     8
vb@217
     9
#include "pEp_internal.h"
vb@0
    10
#include "keymanagement.h"
vb@0
    11
edouard@1195
    12
#include "sync_fsm.h"
edouard@1195
    13
Edouard@439
    14
#ifndef EMPTYSTR
roker@500
    15
#define EMPTYSTR(STR) ((STR) == NULL || (STR)[0] == '\0')
vb@8
    16
#endif
vb@8
    17
vb@214
    18
#define KEY_EXPIRE_DELTA (60 * 60 * 24 * 365)
vb@214
    19
Edouard@512
    20
// Space tolerant and case insensitive fingerprint string compare
Edouard@512
    21
static int _same_fpr(
Edouard@512
    22
        const char* fpra,
Edouard@512
    23
        size_t fpras,
Edouard@512
    24
        const char* fprb,
Edouard@512
    25
        size_t fprbs
Edouard@512
    26
    )
Edouard@512
    27
{
Edouard@512
    28
    size_t ai = 0;
Edouard@512
    29
    size_t bi = 0;
Edouard@512
    30
    
Edouard@544
    31
    do
Edouard@544
    32
    {
Edouard@544
    33
        if(fpra[ai] == 0 || fprb[bi] == 0)
Edouard@544
    34
        {
Edouard@512
    35
            return 0;
Edouard@544
    36
        }
Edouard@544
    37
        else if(fpra[ai] == ' ')
Edouard@544
    38
        {
Edouard@512
    39
            ai++;
Edouard@544
    40
        }
Edouard@544
    41
        else if(fprb[bi] == ' ')
Edouard@544
    42
        {
Edouard@512
    43
            bi++;
Edouard@544
    44
        }
Edouard@544
    45
        else if(toupper(fpra[ai]) == toupper(fprb[bi]))
Edouard@544
    46
        {
Edouard@512
    47
            ai++;
Edouard@512
    48
            bi++;
Edouard@512
    49
        }
Edouard@544
    50
        else
Edouard@544
    51
        {
Edouard@544
    52
            return 0;
Edouard@544
    53
        }
Edouard@544
    54
        
Edouard@544
    55
    }
Edouard@544
    56
    while(ai < fpras && bi < fprbs);
Edouard@512
    57
    
Edouard@512
    58
    return ai == fpras && bi == fprbs;
Edouard@512
    59
}
Edouard@512
    60
Edouard@774
    61
PEP_STATUS elect_pubkey(
Edouard@755
    62
        PEP_SESSION session, pEp_identity * identity
Edouard@755
    63
    )
Edouard@755
    64
{
Edouard@755
    65
    PEP_STATUS status;
Edouard@755
    66
    stringlist_t *keylist;
Edouard@755
    67
    char *_fpr = NULL;
Edouard@755
    68
    identity->comm_type = PEP_ct_unknown;
Edouard@755
    69
Edouard@755
    70
    status = find_keys(session, identity->address, &keylist);
Edouard@755
    71
    assert(status != PEP_OUT_OF_MEMORY);
Edouard@755
    72
    if (status == PEP_OUT_OF_MEMORY)
Edouard@755
    73
        return PEP_OUT_OF_MEMORY;
Edouard@755
    74
Edouard@755
    75
    stringlist_t *_keylist;
Edouard@755
    76
    for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
Edouard@755
    77
        PEP_comm_type _comm_type_key;
Edouard@755
    78
Edouard@755
    79
        status = get_key_rating(session, _keylist->value, &_comm_type_key);
Edouard@755
    80
        assert(status != PEP_OUT_OF_MEMORY);
Edouard@755
    81
        if (status == PEP_OUT_OF_MEMORY) {
Edouard@755
    82
            free_stringlist(keylist);
Edouard@755
    83
            return PEP_OUT_OF_MEMORY;
Edouard@755
    84
        }
Edouard@755
    85
Edouard@755
    86
        if (_comm_type_key != PEP_ct_compromized &&
Edouard@755
    87
            _comm_type_key != PEP_ct_unknown)
Edouard@755
    88
        {
Edouard@755
    89
            if (identity->comm_type == PEP_ct_unknown ||
Edouard@755
    90
                _comm_type_key > identity->comm_type)
Edouard@755
    91
            {
Edouard@755
    92
                identity->comm_type = _comm_type_key;
Edouard@755
    93
                _fpr = _keylist->value;
Edouard@755
    94
            }
Edouard@755
    95
        }
Edouard@755
    96
    }
Edouard@755
    97
Edouard@755
    98
    if (_fpr) {
Edouard@755
    99
        free(identity->fpr);
Edouard@755
   100
Edouard@755
   101
        identity->fpr = strdup(_fpr);
Edouard@755
   102
        if (identity->fpr == NULL) {
Edouard@755
   103
            free_stringlist(keylist);
Edouard@755
   104
            return PEP_OUT_OF_MEMORY;
Edouard@755
   105
        }
Edouard@755
   106
    }
Edouard@755
   107
    free_stringlist(keylist);
Edouard@755
   108
    return PEP_STATUS_OK;
Edouard@755
   109
}
Edouard@755
   110
vb@0
   111
DYNAMIC_API PEP_STATUS update_identity(
vb@0
   112
        PEP_SESSION session, pEp_identity * identity
vb@0
   113
    )
vb@0
   114
{
vb@0
   115
    pEp_identity *stored_identity;
krista@1224
   116
    pEp_identity* temp_id = NULL;
vb@0
   117
    PEP_STATUS status;
vb@0
   118
vb@0
   119
    assert(session);
vb@0
   120
    assert(identity);
Edouard@439
   121
    assert(!EMPTYSTR(identity->address));
vb@0
   122
Edouard@439
   123
    if (!(session && identity && !EMPTYSTR(identity->address)))
vb@191
   124
        return PEP_ILLEGAL_VALUE;
vb@191
   125
vb@1078
   126
    if (identity->me || (identity->user_id && strcmp(identity->user_id, PEP_OWN_USERID) == 0)) {
vb@1078
   127
        identity->me = true;
vb@1078
   128
        return myself(session, identity);
vb@1078
   129
    }
vb@1078
   130
Edouard@559
   131
    int _no_user_id = EMPTYSTR(identity->user_id);
edouard@1164
   132
    int _did_elect_new_key = 0;
Edouard@559
   133
Edouard@559
   134
    if (_no_user_id)
Edouard@559
   135
    {
vb@1015
   136
        status = get_identity(session, identity->address, PEP_OWN_USERID,
vb@1015
   137
                &stored_identity);
vb@1015
   138
        if (status == PEP_STATUS_OK) {
vb@1015
   139
            free_identity(stored_identity);
vb@1015
   140
            return myself(session, identity);
vb@1015
   141
        }
vb@1015
   142
Edouard@559
   143
        free(identity->user_id);
Edouard@559
   144
vb@591
   145
        identity->user_id = calloc(1, strlen(identity->address) + 6);
Edouard@562
   146
        if (!identity->user_id)
Edouard@559
   147
        {
Edouard@562
   148
            return PEP_OUT_OF_MEMORY;
Edouard@559
   149
        }
vb@983
   150
        snprintf(identity->user_id, strlen(identity->address) + 6,
Edouard@562
   151
                 "TOFU_%s", identity->address);
Edouard@559
   152
    }
vb@934
   153
 
Edouard@559
   154
    status = get_identity(session,
Edouard@559
   155
                          identity->address,
Edouard@559
   156
                          identity->user_id,
Edouard@559
   157
                          &stored_identity);
Edouard@559
   158
    
vb@0
   159
    assert(status != PEP_OUT_OF_MEMORY);
vb@0
   160
    if (status == PEP_OUT_OF_MEMORY)
Edouard@829
   161
        goto exit_free;
vb@0
   162
krista@1188
   163
    /* We elect a pubkey first in case there's no acceptable stored fpr */
krista@1224
   164
    temp_id = identity_dup(identity);
krista@1220
   165
    
krista@1220
   166
    status = elect_pubkey(session, temp_id);
krista@1185
   167
    if (status != PEP_STATUS_OK)
krista@1185
   168
        goto exit_free;
krista@1188
   169
        
vb@14
   170
    if (stored_identity) {
vb@14
   171
        PEP_comm_type _comm_type_key;
krista@1188
   172
        
krista@1188
   173
        bool dont_use_fpr = true;
krista@1220
   174
krista@1220
   175
        /* if we have a stored_identity fpr */
krista@1220
   176
        if (!EMPTYSTR(stored_identity->fpr)) {
krista@1220
   177
            status = blacklist_is_listed(session, stored_identity->fpr, &dont_use_fpr);
krista@1220
   178
            if (status != PEP_STATUS_OK)
krista@1220
   179
                dont_use_fpr = true; 
krista@1220
   180
        }
krista@1188
   181
            
krista@1220
   182
krista@1220
   183
        if (!dont_use_fpr) {
krista@1220
   184
            free(temp_id->fpr);
krista@1220
   185
            temp_id->fpr = strdup(stored_identity->fpr);
krista@1220
   186
            assert(temp_id->fpr);
krista@1220
   187
            if (temp_id->fpr == NULL) {
krista@1220
   188
                status = PEP_OUT_OF_MEMORY;
krista@1188
   189
                goto exit_free;
krista@1220
   190
            }
krista@1220
   191
        }
krista@1220
   192
        else if (!EMPTYSTR(temp_id->fpr)) {
krista@1220
   193
            status = blacklist_is_listed(session, temp_id->fpr, &dont_use_fpr);
krista@1188
   194
            if (dont_use_fpr) {
krista@1220
   195
                free(temp_id->fpr);
krista@1220
   196
                temp_id->fpr = strdup("");
krista@1188
   197
            }
krista@1188
   198
            else {
krista@1188
   199
                _did_elect_new_key = 1;
krista@1188
   200
            }
krista@1188
   201
        }
krista@1188
   202
        else {
krista@1220
   203
            if (temp_id->fpr == NULL)
krista@1220
   204
                temp_id->fpr = strdup("");
krista@1188
   205
        }
krista@1188
   206
        
krista@1220
   207
        /* ok, from here on out, use temp_id */
krista@1220
   208
        
krista@1220
   209
        
krista@1220
   210
        /* At this point, we either have a non-blacklisted fpr we can work */
krista@1220
   211
        /* with, or we've got nada.                                        */        
krista@1220
   212
        if (!EMPTYSTR(temp_id->fpr)) {
krista@1220
   213
            status = get_key_rating(session, temp_id->fpr, &_comm_type_key);
krista@1188
   214
            assert(status != PEP_OUT_OF_MEMORY);
krista@1188
   215
            if (status == PEP_OUT_OF_MEMORY)
krista@1188
   216
                goto exit_free;
krista@1220
   217
            status = get_trust(session, temp_id);
krista@1188
   218
            if (status == PEP_OUT_OF_MEMORY)
krista@1188
   219
                goto exit_free;
krista@1188
   220
            if (_comm_type_key < PEP_ct_unconfirmed_encryption) {
krista@1220
   221
                temp_id->comm_type = _comm_type_key;
krista@1188
   222
            } else{
krista@1220
   223
                temp_id->comm_type = stored_identity->comm_type;
krista@1220
   224
                if (temp_id->comm_type == PEP_ct_unknown) {
krista@1220
   225
                    temp_id->comm_type = _comm_type_key;
krista@1188
   226
                }
krista@1188
   227
            }
krista@1188
   228
        }
krista@1243
   229
        else {
krista@1243
   230
            /* Set comm_type accordingly */
krista@1243
   231
            temp_id->comm_type = PEP_ct_key_not_found;
krista@1243
   232
        }
krista@1243
   233
        
krista@1220
   234
        if (EMPTYSTR(temp_id->username)) {
krista@1220
   235
            free(temp_id->username);
krista@1220
   236
            temp_id->username = strdup(stored_identity->username);
krista@1220
   237
            assert(temp_id->username);
krista@1220
   238
            if (temp_id->username == NULL){
Edouard@829
   239
                status = PEP_OUT_OF_MEMORY;
Edouard@829
   240
                goto exit_free;
Edouard@829
   241
            }
vb@22
   242
        }
vb@22
   243
krista@1220
   244
        if (temp_id->lang[0] == 0) {
krista@1220
   245
            temp_id->lang[0] = stored_identity->lang[0];
krista@1220
   246
            temp_id->lang[1] = stored_identity->lang[1];
krista@1220
   247
            temp_id->lang[2] = 0;
vb@21
   248
        }
vb@932
   249
krista@1220
   250
        temp_id->flags = stored_identity->flags;
vb@21
   251
    }
vb@21
   252
    else /* stored_identity == NULL */ {
krista@1220
   253
        temp_id->flags = 0;
vb@934
   254
krista@1188
   255
        /* Work with the elected key from above */
krista@1220
   256
        if (!EMPTYSTR(temp_id->fpr)) {
krista@1196
   257
            
krista@1196
   258
            bool dont_use_fpr = true;
krista@1220
   259
            status = blacklist_is_listed(session, temp_id->fpr, &dont_use_fpr);
krista@1196
   260
            if (status != PEP_STATUS_OK)
krista@1196
   261
                dont_use_fpr = true; 
krista@1196
   262
krista@1196
   263
            if (!dont_use_fpr) {
krista@1196
   264
                PEP_comm_type _comm_type_key;
vb@21
   265
krista@1220
   266
                status = get_key_rating(session, temp_id->fpr, &_comm_type_key);
krista@1196
   267
                assert(status != PEP_OUT_OF_MEMORY);
krista@1196
   268
                if (status == PEP_OUT_OF_MEMORY)
krista@1196
   269
                    goto exit_free;
vb@21
   270
krista@1220
   271
                temp_id->comm_type = _comm_type_key;
krista@1196
   272
            }
krista@1196
   273
            else {
krista@1220
   274
                free(temp_id->fpr);
krista@1220
   275
                temp_id->fpr = strdup("");
krista@1196
   276
            }
vb@21
   277
        }
vb@21
   278
    }
vb@21
   279
krista@1220
   280
    if (temp_id->fpr == NULL)
krista@1220
   281
        temp_id->fpr = strdup("");
krista@1193
   282
    
krista@1193
   283
    
vb@21
   284
    status = PEP_STATUS_OK;
vb@21
   285
krista@1220
   286
    if (temp_id->comm_type != PEP_ct_unknown && !EMPTYSTR(temp_id->user_id)) {
krista@1220
   287
        assert(!EMPTYSTR(temp_id->username)); // this should not happen
vb@22
   288
krista@1220
   289
        if (EMPTYSTR(temp_id->username)) { // mitigate
krista@1220
   290
            free(temp_id->username);
krista@1220
   291
            temp_id->username = strdup("anonymous");
krista@1220
   292
            assert(temp_id->username);
krista@1220
   293
            if (temp_id->username == NULL){
Edouard@829
   294
                status = PEP_OUT_OF_MEMORY;
Edouard@829
   295
                goto exit_free;
Edouard@829
   296
            }
vb@0
   297
        }
vb@8
   298
Edouard@755
   299
        // Identity doesn't get stored if call was just about checking existing
Edouard@755
   300
        // user by address (i.e. no user id given but already stored)
krista@1223
   301
        if (!(_no_user_id && stored_identity) || _did_elect_new_key)
Edouard@559
   302
        {
krista@1220
   303
            status = set_identity(session, temp_id);
Edouard@559
   304
            assert(status == PEP_STATUS_OK);
Edouard@559
   305
            if (status != PEP_STATUS_OK) {
Edouard@829
   306
                goto exit_free;
Edouard@559
   307
            }
Edouard@499
   308
        }
vb@8
   309
    }
vb@8
   310
krista@1220
   311
    if (temp_id->comm_type != PEP_ct_compromized &&
krista@1220
   312
            temp_id->comm_type < PEP_ct_strong_but_unconfirmed)
vb@297
   313
        if (session->examine_identity)
krista@1220
   314
            session->examine_identity(temp_id, session->examine_management);
krista@1220
   315
    
krista@1220
   316
    /* ok, we got to the end. So we can assign the output identity */
krista@1220
   317
    free(identity->address);
krista@1220
   318
    identity->address = strdup(temp_id->address);
krista@1220
   319
    free(identity->fpr);
krista@1220
   320
    identity->fpr = strdup(temp_id->fpr);
krista@1220
   321
    free(identity->user_id);
krista@1220
   322
    identity->user_id = strdup(temp_id->user_id);
krista@1220
   323
    free(identity->username);
krista@1220
   324
    identity->username = strdup(temp_id->username);
krista@1220
   325
    identity->comm_type = temp_id->comm_type;
krista@1220
   326
    identity->lang[0] = temp_id->lang[0];
krista@1220
   327
    identity->lang[1] = temp_id->lang[1];
krista@1220
   328
    identity->lang[2] = 0;
krista@1220
   329
    identity->me = temp_id->me;
krista@1220
   330
    identity->flags = temp_id->flags;
vb@297
   331
Edouard@829
   332
exit_free :
Edouard@829
   333
    
Edouard@829
   334
    if (stored_identity){
Edouard@829
   335
        free_identity(stored_identity);
Edouard@829
   336
    }
Edouard@829
   337
krista@1220
   338
    if (temp_id)
krista@1220
   339
        free_identity(temp_id);
krista@1220
   340
    
vb@8
   341
    return status;
vb@0
   342
}
vb@0
   343
Edouard@774
   344
PEP_STATUS elect_ownkey(
krista@1194
   345
        PEP_SESSION session, pEp_identity * identity
Edouard@774
   346
    )
Edouard@774
   347
{
Edouard@774
   348
    PEP_STATUS status;
Edouard@774
   349
    stringlist_t *keylist = NULL;
Edouard@774
   350
Edouard@774
   351
    free(identity->fpr);
Edouard@774
   352
    identity->fpr = NULL;
Edouard@774
   353
Edouard@774
   354
    status = find_keys(session, identity->address, &keylist);
Edouard@774
   355
    assert(status != PEP_OUT_OF_MEMORY);
Edouard@774
   356
    if (status == PEP_OUT_OF_MEMORY)
Edouard@774
   357
        return PEP_OUT_OF_MEMORY;
Edouard@774
   358
    
Edouard@774
   359
    if (keylist != NULL && keylist->value != NULL)
Edouard@774
   360
    {
Edouard@774
   361
        char *_fpr = NULL;
Edouard@774
   362
        identity->comm_type = PEP_ct_unknown;
Edouard@774
   363
Edouard@774
   364
        stringlist_t *_keylist;
Edouard@774
   365
        for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
Edouard@774
   366
            bool is_own = false;
Edouard@774
   367
            
Edouard@774
   368
            if (session->use_only_own_private_keys)
Edouard@774
   369
            {
Edouard@774
   370
                status = own_key_is_listed(session, _keylist->value, &is_own);
Edouard@774
   371
                assert(status == PEP_STATUS_OK);
Edouard@774
   372
                if (status != PEP_STATUS_OK) {
Edouard@774
   373
                    free_stringlist(keylist);
Edouard@774
   374
                    return status;
Edouard@774
   375
                }
Edouard@774
   376
            }
Edouard@774
   377
Edouard@774
   378
            // TODO : also accept synchronized device group keys ?
Edouard@774
   379
            
Edouard@774
   380
            if (!session->use_only_own_private_keys || is_own)
Edouard@774
   381
            {
Edouard@774
   382
                PEP_comm_type _comm_type_key;
Edouard@774
   383
                
Edouard@774
   384
                status = get_key_rating(session, _keylist->value, &_comm_type_key);
Edouard@774
   385
                assert(status != PEP_OUT_OF_MEMORY);
Edouard@774
   386
                if (status == PEP_OUT_OF_MEMORY) {
Edouard@774
   387
                    free_stringlist(keylist);
Edouard@774
   388
                    return PEP_OUT_OF_MEMORY;
Edouard@774
   389
                }
Edouard@774
   390
                
Edouard@774
   391
                if (_comm_type_key != PEP_ct_compromized &&
Edouard@774
   392
                    _comm_type_key != PEP_ct_unknown)
Edouard@774
   393
                {
Edouard@774
   394
                    if (identity->comm_type == PEP_ct_unknown ||
Edouard@774
   395
                        _comm_type_key > identity->comm_type)
Edouard@774
   396
                    {
Edouard@774
   397
                        identity->comm_type = _comm_type_key;
Edouard@774
   398
                        _fpr = _keylist->value;
Edouard@774
   399
                    }
Edouard@774
   400
                }
Edouard@774
   401
            }
Edouard@774
   402
        }
Edouard@774
   403
        
Edouard@774
   404
        if (_fpr)
Edouard@774
   405
        {
Edouard@774
   406
            identity->fpr = strdup(_fpr);
Edouard@774
   407
            assert(identity->fpr);
Edouard@774
   408
            if (identity->fpr == NULL)
Edouard@774
   409
            {
Edouard@774
   410
                free_stringlist(keylist);
Edouard@774
   411
                return PEP_OUT_OF_MEMORY;
Edouard@774
   412
            }
Edouard@774
   413
        }
Edouard@774
   414
        free_stringlist(keylist);
Edouard@774
   415
    }
Edouard@774
   416
    return PEP_STATUS_OK;
Edouard@774
   417
}
Edouard@774
   418
vb@0
   419
DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
vb@0
   420
{
Edouard@560
   421
    pEp_identity *stored_identity;
vb@0
   422
    PEP_STATUS status;
vb@0
   423
vb@0
   424
    assert(session);
vb@0
   425
    assert(identity);
vb@1044
   426
    assert(!EMPTYSTR(identity->address));
vb@1043
   427
Edouard@658
   428
    assert(EMPTYSTR(identity->user_id) ||
Edouard@658
   429
           strcmp(identity->user_id, PEP_OWN_USERID) == 0);
vb@0
   430
vb@1044
   431
    if (!(session && identity && !EMPTYSTR(identity->address) &&
vb@1043
   432
            (EMPTYSTR(identity->user_id) ||
vb@1043
   433
            strcmp(identity->user_id, PEP_OWN_USERID) == 0)))
vb@191
   434
        return PEP_ILLEGAL_VALUE;
vb@191
   435
vb@0
   436
    identity->comm_type = PEP_ct_pEp;
vb@0
   437
    identity->me = true;
Edouard@658
   438
    
vb@1043
   439
    if (EMPTYSTR(identity->user_id))
Edouard@658
   440
    {
Edouard@658
   441
        free(identity->user_id);
Edouard@658
   442
        identity->user_id = strdup(PEP_OWN_USERID);
Edouard@658
   443
        assert(identity->user_id);
Edouard@658
   444
        if (identity->user_id == NULL)
Edouard@658
   445
            return PEP_OUT_OF_MEMORY;
Edouard@658
   446
    }
vb@0
   447
vb@215
   448
    DEBUG_LOG("myself", "debug", identity->address);
vb@1044
   449
 
Edouard@560
   450
    status = get_identity(session,
Edouard@560
   451
                          identity->address,
Edouard@560
   452
                          identity->user_id,
Edouard@560
   453
                          &stored_identity);
Edouard@560
   454
    
vb@0
   455
    assert(status != PEP_OUT_OF_MEMORY);
vb@0
   456
    if (status == PEP_OUT_OF_MEMORY)
vb@0
   457
        return PEP_OUT_OF_MEMORY;
Edouard@560
   458
    
Edouard@560
   459
    if (stored_identity)
Edouard@560
   460
    {
Edouard@560
   461
        if (EMPTYSTR(identity->fpr)) {
vb@591
   462
            identity->fpr = strdup(stored_identity->fpr);
Edouard@560
   463
            assert(identity->fpr);
Edouard@560
   464
            if (identity->fpr == NULL)
Edouard@560
   465
            {
Edouard@560
   466
                return PEP_OUT_OF_MEMORY;
Edouard@560
   467
            }
Edouard@560
   468
        }
vb@932
   469
vb@932
   470
        identity->flags = stored_identity->flags;
Edouard@588
   471
    }
Edouard@588
   472
    else if (!EMPTYSTR(identity->fpr))
Edouard@588
   473
    {
Edouard@588
   474
        // App must have a good reason to give fpr, such as explicit
Edouard@588
   475
        // import of private key, or similar.
Edouard@588
   476
Edouard@658
   477
        // Take given fpr as-is.
vb@934
   478
vb@934
   479
        identity->flags = 0;
Edouard@560
   480
    }
Edouard@560
   481
    else
Edouard@560
   482
    {
Edouard@774
   483
        status = elect_ownkey(session, identity);
Edouard@774
   484
        assert(status == PEP_STATUS_OK);
Edouard@774
   485
        if (status != PEP_STATUS_OK) {
Edouard@774
   486
            return status;
Edouard@560
   487
        }
vb@934
   488
vb@934
   489
        identity->flags = 0;
Edouard@560
   490
    }
Edouard@695
   491
Edouard@695
   492
    bool revoked = false;
Edouard@695
   493
    char *r_fpr = NULL;
Edouard@695
   494
    if (!EMPTYSTR(identity->fpr))
Edouard@695
   495
    {
Edouard@695
   496
        status = key_revoked(session, identity->fpr, &revoked);
Edouard@775
   497
Edouard@775
   498
        // Forces re-election if key is missing and own-key-only not forced
Edouard@775
   499
        if (!session->use_only_own_private_keys && status == PEP_KEY_NOT_FOUND) 
Edouard@775
   500
        {
Edouard@775
   501
            status = elect_ownkey(session, identity);
Edouard@775
   502
            assert(status == PEP_STATUS_OK);
Edouard@775
   503
            if (status != PEP_STATUS_OK) {
Edouard@775
   504
                return status;
Edouard@775
   505
            }
Edouard@775
   506
        } 
Edouard@775
   507
        else if (status != PEP_STATUS_OK) 
Edouard@775
   508
        {
Edouard@695
   509
            return status;
Edouard@695
   510
        }
Edouard@695
   511
    }
edouard@1140
   512
   
edouard@1140
   513
    bool new_key_generated = false;
edouard@1140
   514
Edouard@695
   515
    if (EMPTYSTR(identity->fpr) || revoked)
Edouard@695
   516
    {        
Edouard@695
   517
        if(revoked)
Edouard@695
   518
        {
Edouard@697
   519
            r_fpr = identity->fpr;
Edouard@697
   520
            identity->fpr = NULL;
Edouard@695
   521
        }
Edouard@560
   522
        
vb@215
   523
        DEBUG_LOG("generating key pair", "debug", identity->address);
vb@0
   524
        status = generate_keypair(session, identity);
vb@0
   525
        assert(status != PEP_OUT_OF_MEMORY);
vb@0
   526
        if (status != PEP_STATUS_OK) {
vb@0
   527
            char buf[11];
vb@0
   528
            snprintf(buf, 11, "%d", status);
vb@215
   529
            DEBUG_LOG("generating key pair failed", "debug", buf);
Edouard@695
   530
            if(revoked && r_fpr)
Edouard@695
   531
                free(r_fpr);
vb@0
   532
            return status;
vb@0
   533
        }
edouard@1140
   534
edouard@1140
   535
        new_key_generated = true;
Edouard@560
   536
        
Edouard@695
   537
        if(revoked)
Edouard@695
   538
        {
Edouard@695
   539
            status = set_revoked(session, r_fpr,
Edouard@695
   540
                                 identity->fpr, time(NULL));
Edouard@695
   541
            free(r_fpr);
Edouard@695
   542
            if (status != PEP_STATUS_OK) {
Edouard@695
   543
                return status;
Edouard@695
   544
            }
Edouard@371
   545
        }
vb@0
   546
    }
Edouard@560
   547
    else
Edouard@560
   548
    {
vb@214
   549
        bool expired;
Edouard@701
   550
        status = key_expired(session, identity->fpr, 
Edouard@701
   551
                             time(NULL) + (7*24*3600), // In a week
Edouard@701
   552
                             &expired);
Edouard@701
   553
vb@214
   554
        assert(status == PEP_STATUS_OK);
Edouard@499
   555
        if (status != PEP_STATUS_OK) {
Edouard@588
   556
            return status;
Edouard@499
   557
        }
vb@214
   558
vb@214
   559
        if (status == PEP_STATUS_OK && expired) {
vb@214
   560
            timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
Edouard@560
   561
            renew_key(session, identity->fpr, ts);
vb@214
   562
            free_timestamp(ts);
vb@214
   563
        }
vb@214
   564
    }
vb@0
   565
vb@0
   566
    status = set_identity(session, identity);
vb@0
   567
    assert(status == PEP_STATUS_OK);
Edouard@499
   568
    if (status != PEP_STATUS_OK) {
Edouard@588
   569
        return status;
Edouard@499
   570
    }
vb@0
   571
edouard@1145
   572
    if(new_key_generated)
edouard@1145
   573
    {
edouard@1145
   574
        // if a state machine for keysync is in place, inject notify
edouard@1195
   575
        status = inject_DeviceState_event(session, KeyGen, NULL, NULL);
edouard@1145
   576
        if (status != PEP_STATUS_OK)
edouard@1145
   577
            return status;
edouard@1145
   578
    }
edouard@1140
   579
vb@0
   580
    return PEP_STATUS_OK;
Edouard@499
   581
vb@0
   582
}
vb@0
   583
vb@296
   584
DYNAMIC_API PEP_STATUS register_examine_function(
vb@292
   585
        PEP_SESSION session, 
vb@292
   586
        examine_identity_t examine_identity,
vb@292
   587
        void *management
vb@292
   588
    )
vb@292
   589
{
vb@292
   590
    assert(session);
vb@292
   591
    if (!session)
vb@292
   592
        return PEP_ILLEGAL_VALUE;
vb@292
   593
vb@292
   594
    session->examine_management = management;
vb@292
   595
    session->examine_identity = examine_identity;
vb@292
   596
vb@292
   597
    return PEP_STATUS_OK;
vb@292
   598
}
vb@292
   599
vb@0
   600
DYNAMIC_API PEP_STATUS do_keymanagement(
vb@0
   601
        retrieve_next_identity_t retrieve_next_identity,
vb@0
   602
        void *management
vb@0
   603
    )
vb@0
   604
{
vb@0
   605
    PEP_SESSION session;
vb@0
   606
    pEp_identity *identity;
Edouard@499
   607
    PEP_STATUS status;
vb@0
   608
vb@24
   609
    assert(retrieve_next_identity);
vb@24
   610
    assert(management);
vb@24
   611
Edouard@499
   612
    if (!retrieve_next_identity || !management)
Edouard@499
   613
        return PEP_ILLEGAL_VALUE;
Edouard@499
   614
Edouard@499
   615
    status = init(&session);
Edouard@499
   616
    assert(status == PEP_STATUS_OK);
Edouard@499
   617
    if (status != PEP_STATUS_OK)
Edouard@499
   618
        return status;
Edouard@499
   619
vb@0
   620
    log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
vb@0
   621
Edouard@499
   622
    while ((identity = retrieve_next_identity(management))) 
Edouard@499
   623
    {
vb@0
   624
        assert(identity->address);
Edouard@499
   625
        if(identity->address)
Edouard@499
   626
        {
Edouard@499
   627
            DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
Edouard@499
   628
Edouard@499
   629
            if (identity->me) {
Edouard@499
   630
                status = myself(session, identity);
Edouard@499
   631
            } else {
Edouard@499
   632
                status = recv_key(session, identity->address);
Edouard@499
   633
            }
Edouard@499
   634
vb@0
   635
            assert(status != PEP_OUT_OF_MEMORY);
Edouard@499
   636
            if(status == PEP_OUT_OF_MEMORY)
Edouard@499
   637
                return PEP_OUT_OF_MEMORY;
vb@0
   638
        }
vb@0
   639
        free_identity(identity);
vb@0
   640
    }
vb@0
   641
vb@0
   642
    log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
vb@0
   643
vb@0
   644
    release(session);
vb@0
   645
    return PEP_STATUS_OK;
vb@0
   646
}
vb@0
   647
krista@1213
   648
DYNAMIC_API PEP_STATUS key_mistrusted(
vb@357
   649
        PEP_SESSION session,
vb@357
   650
        pEp_identity *ident
vb@357
   651
    )
vb@215
   652
{
vb@218
   653
    PEP_STATUS status = PEP_STATUS_OK;
vb@218
   654
vb@215
   655
    assert(session);
vb@357
   656
    assert(ident);
Edouard@439
   657
    assert(!EMPTYSTR(ident->fpr));
vb@215
   658
vb@357
   659
    if (!(session && ident && ident->fpr))
vb@215
   660
        return PEP_ILLEGAL_VALUE;
vb@215
   661
vb@357
   662
    if (ident->me)
Edouard@697
   663
    {
vb@357
   664
        revoke_key(session, ident->fpr, NULL);
Edouard@697
   665
        myself(session, ident);
Edouard@697
   666
    }
Edouard@697
   667
    else
Edouard@697
   668
    {
Edouard@697
   669
        status = mark_as_compromized(session, ident->fpr);
Edouard@697
   670
    }
vb@218
   671
vb@218
   672
    return status;
vb@215
   673
}
vb@215
   674
Edouard@410
   675
DYNAMIC_API PEP_STATUS key_reset_trust(
Edouard@410
   676
        PEP_SESSION session,
Edouard@410
   677
        pEp_identity *ident
Edouard@410
   678
    )
Edouard@410
   679
{
Edouard@410
   680
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@410
   681
Edouard@410
   682
    assert(session);
Edouard@410
   683
    assert(ident);
vb@420
   684
    assert(!ident->me);
Edouard@439
   685
    assert(!EMPTYSTR(ident->fpr));
Edouard@439
   686
    assert(!EMPTYSTR(ident->address));
Edouard@439
   687
    assert(!EMPTYSTR(ident->user_id));
Edouard@410
   688
vb@420
   689
    if (!(session && ident && !ident->me && ident->fpr && ident->address &&
vb@420
   690
            ident->user_id))
Edouard@410
   691
        return PEP_ILLEGAL_VALUE;
Edouard@410
   692
vb@420
   693
    status = update_identity(session, ident);
vb@420
   694
    if (status != PEP_STATUS_OK)
vb@420
   695
        return status;
Edouard@410
   696
Edouard@442
   697
    if (ident->comm_type == PEP_ct_mistrusted)
vb@421
   698
        ident->comm_type = PEP_ct_unknown;
vb@421
   699
    else
vb@421
   700
        ident->comm_type &= ~PEP_ct_confirmed;
vb@421
   701
vb@420
   702
    status = set_identity(session, ident);
vb@421
   703
    if (status != PEP_STATUS_OK)
vb@421
   704
        return status;
vb@421
   705
vb@422
   706
    if (ident->comm_type == PEP_ct_unknown)
vb@422
   707
        status = update_identity(session, ident);
Edouard@410
   708
    return status;
Edouard@410
   709
}
Edouard@410
   710
vb@354
   711
DYNAMIC_API PEP_STATUS trust_personal_key(
vb@354
   712
        PEP_SESSION session,
vb@354
   713
        pEp_identity *ident
vb@354
   714
    )
vb@354
   715
{
vb@354
   716
    PEP_STATUS status = PEP_STATUS_OK;
vb@354
   717
vb@354
   718
    assert(session);
vb@354
   719
    assert(ident);
Edouard@439
   720
    assert(!EMPTYSTR(ident->address));
Edouard@439
   721
    assert(!EMPTYSTR(ident->user_id));
Edouard@439
   722
    assert(!EMPTYSTR(ident->fpr));
vb@354
   723
    assert(!ident->me);
vb@354
   724
Edouard@439
   725
    if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
Edouard@439
   726
            EMPTYSTR(ident->fpr) || ident->me)
vb@354
   727
        return PEP_ILLEGAL_VALUE;
vb@354
   728
vb@354
   729
    status = update_identity(session, ident);
vb@354
   730
    if (status != PEP_STATUS_OK)
vb@354
   731
        return status;
vb@354
   732
vb@356
   733
    if (ident->comm_type > PEP_ct_strong_but_unconfirmed) {
vb@356
   734
        ident->comm_type |= PEP_ct_confirmed;
Edouard@488
   735
        status = set_identity(session, ident);
vb@356
   736
    }
vb@356
   737
    else {
vb@356
   738
        // MISSING: S/MIME has to be handled depending on trusted CAs
vb@370
   739
        status = PEP_CANNOT_SET_TRUST;
vb@356
   740
    }
vb@354
   741
vb@354
   742
    return status;
vb@354
   743
}
vb@354
   744
Edouard@584
   745
DYNAMIC_API PEP_STATUS own_key_is_listed(
vb@955
   746
        PEP_SESSION session,
vb@955
   747
        const char *fpr,
vb@955
   748
        bool *listed
vb@955
   749
    )
Edouard@584
   750
{
Edouard@584
   751
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@584
   752
    int count;
Edouard@584
   753
    
Edouard@584
   754
    assert(session && fpr && fpr[0] && listed);
Edouard@584
   755
    
Edouard@584
   756
    if (!(session && fpr && fpr[0] && listed))
Edouard@584
   757
        return PEP_ILLEGAL_VALUE;
Edouard@584
   758
    
Edouard@584
   759
    *listed = false;
Edouard@584
   760
    
Edouard@584
   761
    sqlite3_reset(session->own_key_is_listed);
Edouard@584
   762
    sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1, SQLITE_STATIC);
Edouard@584
   763
    
Edouard@584
   764
    int result;
Edouard@584
   765
    
Edouard@584
   766
    result = sqlite3_step(session->own_key_is_listed);
Edouard@584
   767
    switch (result) {
Edouard@584
   768
        case SQLITE_ROW:
Edouard@584
   769
            count = sqlite3_column_int(session->own_key_is_listed, 0);
Edouard@584
   770
            *listed = count > 0;
Edouard@584
   771
            status = PEP_STATUS_OK;
Edouard@584
   772
            break;
Edouard@584
   773
            
Edouard@584
   774
        default:
Edouard@584
   775
            status = PEP_UNKNOWN_ERROR;
Edouard@584
   776
    }
Edouard@584
   777
    
Edouard@584
   778
    sqlite3_reset(session->own_key_is_listed);
Edouard@584
   779
    return status;
Edouard@584
   780
}
Edouard@584
   781
vb@955
   782
DYNAMIC_API PEP_STATUS own_identities_retrieve(
vb@955
   783
        PEP_SESSION session,
vb@955
   784
        identity_list **own_identities
vb@955
   785
      )
Edouard@584
   786
{
Edouard@584
   787
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@584
   788
    
vb@955
   789
    assert(session && own_identities);
vb@955
   790
    if (!(session && own_identities))
Edouard@584
   791
        return PEP_ILLEGAL_VALUE;
Edouard@584
   792
    
vb@955
   793
    *own_identities = NULL;
vb@955
   794
    identity_list *_own_identities = new_identity_list(NULL);
vb@955
   795
    if (_own_identities == NULL)
Edouard@584
   796
        goto enomem;
Edouard@584
   797
    
vb@955
   798
    sqlite3_reset(session->own_identities_retrieve);
Edouard@584
   799
    
Edouard@584
   800
    int result;
vb@955
   801
    // address, fpr, username, user_id, comm_type, lang, flags
vb@955
   802
    const char *address = NULL;
Edouard@584
   803
    const char *fpr = NULL;
vb@955
   804
    const char *username = NULL;
vb@955
   805
    const char *user_id = NULL;
vb@955
   806
    PEP_comm_type comm_type = PEP_ct_unknown;
vb@955
   807
    const char *lang = NULL;
vb@955
   808
    unsigned int flags = 0;
Edouard@584
   809
    
vb@955
   810
    identity_list *_bl = _own_identities;
Edouard@584
   811
    do {
vb@955
   812
        result = sqlite3_step(session->own_identities_retrieve);
Edouard@584
   813
        switch (result) {
Edouard@584
   814
            case SQLITE_ROW:
vb@955
   815
                address = (const char *)
vb@955
   816
                    sqlite3_column_text(session->own_identities_retrieve, 0);
vb@955
   817
                fpr = (const char *)
vb@955
   818
                    sqlite3_column_text(session->own_identities_retrieve, 1);
vb@1071
   819
                user_id = PEP_OWN_USERID;
vb@1071
   820
                username = (const char *)
vb@955
   821
                    sqlite3_column_text(session->own_identities_retrieve, 2);
vb@1071
   822
                comm_type = PEP_ct_pEp;
vb@1071
   823
                lang = (const char *)
vb@955
   824
                    sqlite3_column_text(session->own_identities_retrieve, 3);
vb@1071
   825
                flags = (unsigned int)
vb@955
   826
                    sqlite3_column_int(session->own_key_is_listed, 4);
vb@955
   827
vb@1078
   828
                pEp_identity *ident = new_identity(address, fpr, user_id, username);
vb@1079
   829
                if (!ident)
Edouard@584
   830
                    goto enomem;
vb@955
   831
                ident->comm_type = comm_type;
vb@955
   832
                if (lang && lang[0]) {
vb@955
   833
                    ident->lang[0] = lang[0];
vb@955
   834
                    ident->lang[1] = lang[1];
vb@1078
   835
                    ident->lang[2] = 0;
vb@955
   836
                }
vb@1068
   837
                ident->me = true;
vb@955
   838
                ident->flags = flags;
vb@955
   839
vb@955
   840
                _bl = identity_list_add(_bl, ident);
vb@1080
   841
                if (_bl == NULL) {
vb@1080
   842
                    free_identity(ident);
Edouard@584
   843
                    goto enomem;
vb@1080
   844
                }
Edouard@584
   845
                
Edouard@584
   846
                break;
Edouard@584
   847
                
Edouard@584
   848
            case SQLITE_DONE:
Edouard@584
   849
                break;
Edouard@584
   850
                
Edouard@584
   851
            default:
Edouard@584
   852
                status = PEP_UNKNOWN_ERROR;
Edouard@584
   853
                result = SQLITE_DONE;
Edouard@584
   854
        }
Edouard@584
   855
    } while (result != SQLITE_DONE);
Edouard@584
   856
    
vb@955
   857
    sqlite3_reset(session->own_identities_retrieve);
Edouard@584
   858
    if (status == PEP_STATUS_OK)
vb@955
   859
        *own_identities = _own_identities;
Edouard@584
   860
    else
vb@955
   861
        free_identity_list(_own_identities);
Edouard@584
   862
    
Edouard@584
   863
    goto the_end;
Edouard@584
   864
    
Edouard@584
   865
enomem:
vb@955
   866
    free_identity_list(_own_identities);
Edouard@584
   867
    status = PEP_OUT_OF_MEMORY;
Edouard@584
   868
    
Edouard@584
   869
the_end:
Edouard@584
   870
    return status;
Edouard@584
   871
}
vb@955
   872