src/key_reset.c
author Volker Birk <vb@pep-project.org>
Thu, 12 Dec 2019 06:31:35 +0100
branchsync
changeset 4265 441c82c3d526
parent 4264 d709b7af2f6c
child 4266 b7012c29e885
permissions -rw-r--r--
...
krista@2947
     1
// This file is under GNU General Public License 3.0
krista@2947
     2
// see LICENSE.txt
krista@2947
     3
krista@2947
     4
#include "pEp_internal.h"
krista@2947
     5
#include "dynamic_api.h"
krista@2947
     6
#include "message_api.h"
krista@3967
     7
#include "key_reset.h"
vb@4257
     8
#include "distribution_codec.h"
vb@4257
     9
#include "map_asn1.h"
vb@4257
    10
#include "../asn.1/Distribution.h"
krista@2947
    11
krista@2947
    12
#include <string.h>
krista@2947
    13
#include <stdlib.h>
krista@2947
    14
krista@2947
    15
PEP_STATUS has_key_reset_been_sent(
krista@2947
    16
        PEP_SESSION session, 
krista@2947
    17
        const char* user_id, 
krista@2947
    18
        const char* revoked_fpr,
krista@2947
    19
        bool* contacted)
krista@2947
    20
{
krista@2947
    21
    assert(session);
krista@2947
    22
    assert(contacted);
krista@2947
    23
    assert(user_id);
krista@2947
    24
    assert(revoked_fpr);
krista@2947
    25
    assert(!EMPTYSTR(user_id));
krista@2947
    26
krista@2947
    27
    if (!session || !contacted || EMPTYSTR(revoked_fpr) || EMPTYSTR(user_id))
krista@2947
    28
        return PEP_ILLEGAL_VALUE;
krista@2947
    29
    
krista@2947
    30
    *contacted = false;
krista@2947
    31
                    
krista@2947
    32
    char* alias_default = NULL;
krista@2947
    33
    
krista@2947
    34
    PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
krista@2947
    35
    
krista@2947
    36
    if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
krista@2947
    37
        free(alias_default);
krista@2947
    38
        alias_default = strdup(user_id);
krista@2947
    39
    }
krista@2947
    40
    
krista@2947
    41
    sqlite3_reset(session->was_id_for_revoke_contacted);
krista@2947
    42
    sqlite3_bind_text(session->was_id_for_revoke_contacted, 1, revoked_fpr, -1,
krista@2947
    43
            SQLITE_STATIC);
krista@2947
    44
    sqlite3_bind_text(session->was_id_for_revoke_contacted, 2, user_id, -1,
krista@2947
    45
            SQLITE_STATIC);        
krista@4142
    46
    int result = sqlite3_step(session->was_id_for_revoke_contacted);
krista@2947
    47
    switch (result) {
krista@2947
    48
        case SQLITE_ROW: {
krista@2947
    49
            *contacted = (sqlite3_column_int(session->was_id_for_revoke_contacted, 0) != 0);
krista@2947
    50
            break;
krista@2947
    51
        }
krista@2947
    52
        default:
krista@2947
    53
            sqlite3_reset(session->was_id_for_revoke_contacted);
krista@2947
    54
            free(alias_default);
krista@2947
    55
            return PEP_UNKNOWN_DB_ERROR;
krista@2947
    56
    }
krista@2947
    57
krista@2947
    58
    sqlite3_reset(session->was_id_for_revoke_contacted);
krista@2947
    59
    return PEP_STATUS_OK;
krista@2947
    60
}
krista@2947
    61
krista@2947
    62
//static const char *sql_set_revoke_contact_as_notified =
krista@2947
    63
//    "insert or replace into revocation_contact_list(fpr, contact_id) values (?1, ?2) ;";
krista@2947
    64
krista@2947
    65
PEP_STATUS set_reset_contact_notified(
krista@2947
    66
        PEP_SESSION session,
krista@2947
    67
        const char* revoke_fpr,
krista@2947
    68
        const char* contact_id
krista@2947
    69
    )
krista@2947
    70
{
krista@2947
    71
    PEP_STATUS status = PEP_STATUS_OK;
krista@2947
    72
    
krista@2947
    73
    assert(session && !EMPTYSTR(revoke_fpr) && !EMPTYSTR(contact_id));
krista@2947
    74
    
krista@2947
    75
    if (!session || EMPTYSTR(revoke_fpr) || EMPTYSTR(contact_id))
krista@2947
    76
        return PEP_ILLEGAL_VALUE;
krista@2947
    77
    
krista@2947
    78
    sqlite3_reset(session->set_revoke_contact_as_notified);
krista@2947
    79
    sqlite3_bind_text(session->set_revoke_contact_as_notified, 1, revoke_fpr, -1, 
krista@2947
    80
            SQLITE_STATIC);
krista@2947
    81
    sqlite3_bind_text(session->set_revoke_contact_as_notified, 2, contact_id, -1,
krista@2947
    82
            SQLITE_STATIC);
krista@2947
    83
krista@2947
    84
    int result;
krista@2947
    85
    
krista@4142
    86
    result = sqlite3_step(session->set_revoke_contact_as_notified);
krista@2947
    87
    switch (result) {
krista@2947
    88
        case SQLITE_DONE:
krista@2947
    89
            status = PEP_STATUS_OK;
krista@2947
    90
            break;
krista@2947
    91
            
krista@2947
    92
        default:
krista@2947
    93
            status = PEP_UNKNOWN_DB_ERROR;
krista@2947
    94
    }
krista@2947
    95
    
krista@2947
    96
    sqlite3_reset(session->set_revoke_contact_as_notified);
krista@2947
    97
    return status;    
krista@2947
    98
}
krista@2947
    99
krista@2947
   100
krista@2947
   101
PEP_STATUS receive_key_reset(PEP_SESSION session,
krista@2947
   102
                             message* reset_msg) {
krista@2947
   103
krista@2947
   104
    if (!session || !reset_msg)
krista@2947
   105
        return PEP_ILLEGAL_VALUE;
krista@2947
   106
krista@2947
   107
    pEp_identity* sender_id = reset_msg->from;
krista@2947
   108
                
krista@2947
   109
    if (!sender_id)
krista@2947
   110
        return PEP_MALFORMED_KEY_RESET_MSG;
krista@2947
   111
        
krista@2947
   112
    PEP_STATUS status = update_identity(session, sender_id);
krista@2947
   113
    if (!sender_id->user_id)
krista@2947
   114
        return PEP_UNKNOWN_ERROR;
krista@2947
   115
        
krista@2947
   116
    if (is_me(session, sender_id))
krista@2947
   117
        return PEP_ILLEGAL_VALUE;    
krista@2947
   118
        
krista@2947
   119
    if (!reset_msg->longmsg || strncmp(reset_msg->longmsg, "OLD: ", 5) != 0) 
krista@2947
   120
        return PEP_MALFORMED_KEY_RESET_MSG;
krista@2947
   121
krista@2947
   122
    status = PEP_STATUS_OK;
krista@2947
   123
    char* old_fpr = NULL;
krista@2947
   124
    char* new_fpr = NULL;
krista@2947
   125
    
krista@2947
   126
    stringlist_t* keylist = NULL;
krista@2947
   127
    pEp_identity* temp_ident = identity_dup(sender_id);
krista@2947
   128
    if (!temp_ident) {
krista@2947
   129
        status = PEP_OUT_OF_MEMORY;
krista@2956
   130
        goto pEp_free;
krista@2947
   131
    }        
krista@2947
   132
            
krista@2947
   133
    char* rest = NULL;
krista@2947
   134
    char* p = strtok_r(reset_msg->longmsg, "\r\n", &rest);
krista@2947
   135
    if (!EMPTYSTR(p + 5))
krista@2947
   136
        old_fpr = strdup(p + 5);
krista@2947
   137
    else {
krista@2947
   138
        status = PEP_MALFORMED_KEY_RESET_MSG;
krista@2956
   139
        goto pEp_free;
krista@2947
   140
    }
krista@2947
   141
    
krista@2947
   142
    bool own_key = false;
krista@2947
   143
    status = is_own_key(session, old_fpr, &own_key);
krista@2947
   144
    
krista@2947
   145
    if (own_key) {
krista@2947
   146
        // Nope, no one can make us our own default. If we want to do that,
krista@2947
   147
        // that's keysync, NOT key reset.
krista@2947
   148
        status = PEP_ILLEGAL_VALUE;
krista@2956
   149
        goto pEp_free;
krista@2947
   150
    }
krista@2947
   151
            
krista@2947
   152
    p = strtok_r(NULL, "\r\n", &rest); 
krista@2947
   153
    if (strncmp(p, "NEW: ", 5) != 0  || EMPTYSTR(p + 5)) {
krista@2947
   154
        status = PEP_MALFORMED_KEY_RESET_MSG;
krista@2956
   155
        goto pEp_free;
krista@2947
   156
    }
krista@2947
   157
krista@2947
   158
    new_fpr = strdup(p + 5);
krista@2947
   159
        
krista@2947
   160
    // Reset the original key
krista@4245
   161
    status = key_reset(session, old_fpr, temp_ident, NULL, NULL);
krista@2947
   162
    if (status != PEP_STATUS_OK)
krista@2956
   163
        goto pEp_free;
krista@2947
   164
        
krista@2947
   165
    status = find_keys(session, new_fpr, &keylist);
krista@2947
   166
    if (status != PEP_STATUS_OK)
krista@2956
   167
        goto pEp_free;
krista@2947
   168
        
krista@2947
   169
    if (!keylist) {
krista@2947
   170
        status = PEP_KEY_NOT_FOUND;
krista@2956
   171
        goto pEp_free;
krista@2947
   172
    }
krista@2947
   173
krista@2947
   174
    // alright, we've checked as best we can. Let's set that baby.
krista@2947
   175
    sender_id->fpr = new_fpr;
krista@2947
   176
    
krista@2947
   177
    // This only sets as the default, does NOT TRUST IN ANY WAY
krista@2947
   178
    sender_id->comm_type = sender_id->comm_type & (~PEP_ct_confirmed);
krista@2947
   179
    status = set_identity(session, sender_id);
krista@2947
   180
    
krista@2947
   181
    sender_id->fpr = NULL; // ownership for free
krista@2956
   182
pEp_free:    
krista@2947
   183
    free_stringlist(keylist);    
krista@2947
   184
    free(old_fpr);
krista@2947
   185
    free(new_fpr);
krista@2947
   186
    free_identity(temp_ident);
krista@2947
   187
    return status;
krista@2947
   188
}
krista@2947
   189
krista@2947
   190
PEP_STATUS create_standalone_key_reset_message(PEP_SESSION session,
krista@2947
   191
                                               message** dst, 
krista@2947
   192
                                               pEp_identity* recip,
krista@2947
   193
                                               const char* old_fpr,
krista@2947
   194
                                               const char* new_fpr) {
krista@2947
   195
                                                   
krista@2947
   196
    if (!dst || !recip->user_id || !recip->address)
krista@2947
   197
        return PEP_ILLEGAL_VALUE;
krista@2947
   198
krista@2947
   199
    if (!old_fpr || !new_fpr)
krista@2947
   200
        return PEP_ILLEGAL_VALUE;
krista@2947
   201
        
krista@2947
   202
    *dst = NULL;
krista@2947
   203
    // Get own identity user has corresponded with
krista@2947
   204
    pEp_identity* own_identity = NULL;
krista@2947
   205
    
krista@2947
   206
    PEP_STATUS status = get_own_ident_for_contact_id(session,
krista@2947
   207
                                                     recip,
krista@2947
   208
                                                     &own_identity);                                                       
krista@2947
   209
    if (status != PEP_STATUS_OK)
krista@2947
   210
        return status;
krista@2947
   211
        
krista@2947
   212
    message* reset_message = new_message(PEP_dir_outgoing);
krista@2947
   213
    reset_message->from = own_identity;
krista@2947
   214
    reset_message->to = new_identity_list(identity_dup(recip)); // ?
krista@2947
   215
    
krista@2947
   216
    const char* oldtag = "OLD: ";
krista@2947
   217
    const char* newtag = "\nNEW: ";
krista@2947
   218
    const size_t taglens = 11;
krista@2947
   219
    size_t full_len = taglens + strlen(old_fpr) + strlen(new_fpr) + 2; // \n and \0
krista@2947
   220
    char* longmsg = calloc(full_len, 1);
krista@2947
   221
    strlcpy(longmsg, oldtag, full_len);
krista@2947
   222
    strlcat(longmsg, old_fpr, full_len);
krista@2947
   223
    strlcat(longmsg, newtag, full_len);
krista@2947
   224
    strlcat(longmsg, new_fpr, full_len);
krista@2947
   225
    strlcat(longmsg, "\n", full_len);
krista@2947
   226
    reset_message->longmsg = longmsg; 
krista@2947
   227
    reset_message->shortmsg = strdup("Key reset");    
krista@2947
   228
    
krista@2947
   229
    message* output_msg = NULL;
krista@2947
   230
    
krista@2947
   231
    status = encrypt_message(session, reset_message, NULL,
krista@2947
   232
                             &output_msg, PEP_enc_PGP_MIME,
krista@2947
   233
                             PEP_encrypt_flag_key_reset_only);
krista@2947
   234
krista@2947
   235
    if (status == PEP_STATUS_OK)
krista@2947
   236
        *dst = output_msg;
krista@2947
   237
        
krista@2947
   238
    free_message(reset_message);
krista@2947
   239
    return status;
krista@2947
   240
}
krista@2947
   241
krista@2947
   242
PEP_STATUS send_key_reset_to_recents(PEP_SESSION session,
krista@2947
   243
                                     const char* old_fpr, 
krista@2947
   244
                                     const char* new_fpr) {
krista@2947
   245
    assert(old_fpr);
krista@2947
   246
    assert(new_fpr);
krista@2947
   247
    assert(session);
krista@2956
   248
    assert(session->messageToSend);
krista@2947
   249
    
krista@2947
   250
    if (!session || !old_fpr || !new_fpr)
krista@2947
   251
        return PEP_ILLEGAL_VALUE;
krista@2947
   252
krista@2956
   253
    messageToSend_t send_cb = session->messageToSend;
krista@2947
   254
    if (!send_cb)
krista@2947
   255
        return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
krista@2947
   256
        
krista@2947
   257
    identity_list* recent_contacts = NULL;
krista@2947
   258
    message* reset_msg = NULL;
krista@2947
   259
krista@2947
   260
    PEP_STATUS status = get_last_contacted(session, &recent_contacts);
krista@2947
   261
    
krista@2947
   262
    if (status != PEP_STATUS_OK)
krista@2956
   263
        goto pEp_free;
krista@2947
   264
                    
krista@2947
   265
    identity_list* curr_id_ptr = recent_contacts;
krista@2947
   266
krista@2947
   267
    for (curr_id_ptr = recent_contacts; curr_id_ptr; curr_id_ptr = curr_id_ptr->next) {
krista@2947
   268
        pEp_identity* curr_id = curr_id_ptr->ident;
krista@2947
   269
        
krista@2947
   270
        if (!curr_id)
krista@2947
   271
            break;
krista@2947
   272
    
krista@2947
   273
        const char* user_id = curr_id->user_id;
krista@2947
   274
        
krista@2947
   275
        // Should be impossible, but?
krista@2947
   276
        if (!user_id)
krista@2947
   277
            continue;
krista@2947
   278
        
krista@2947
   279
        // Check if it's us - if so, pointless...
krista@2947
   280
        if (is_me(session, curr_id))
krista@2947
   281
            continue;
krista@2947
   282
            
krista@2947
   283
        // Check if they've already been told - this shouldn't be the case, but...
krista@2947
   284
        bool contacted = false;
krista@2947
   285
        status = has_key_reset_been_sent(session, user_id, old_fpr, &contacted);
krista@2947
   286
        if (status != PEP_STATUS_OK)
krista@2956
   287
            goto pEp_free;
krista@2947
   288
    
krista@2947
   289
        if (contacted)
krista@2947
   290
            continue;
krista@2947
   291
            
krista@2947
   292
        // if not, make em a message    
krista@2947
   293
        reset_msg = NULL;
krista@2947
   294
        
krista@2947
   295
        status = create_standalone_key_reset_message(session,
krista@2947
   296
                                                     &reset_msg,
krista@2947
   297
                                                     curr_id,
krista@2947
   298
                                                     old_fpr,
krista@2947
   299
                                                     new_fpr);
krista@2947
   300
krista@2947
   301
        if (status == PEP_CANNOT_FIND_IDENTITY) { // this is ok, just means we never mailed them 
krista@2947
   302
            status = PEP_STATUS_OK;
krista@2947
   303
            continue; 
krista@2947
   304
        }
krista@2947
   305
            
krista@2947
   306
        if (status != PEP_STATUS_OK) {
krista@2947
   307
            free(reset_msg);
krista@2956
   308
            goto pEp_free;
krista@2947
   309
        }
krista@2947
   310
        
krista@2947
   311
        // insert into queue
krista@2956
   312
        status = send_cb(reset_msg);
krista@2947
   313
krista@2947
   314
        if (status != PEP_STATUS_OK) {
krista@2947
   315
            free(reset_msg);
krista@2956
   316
            goto pEp_free;            
krista@2947
   317
        }
krista@2947
   318
            
krista@2947
   319
        // Put into notified DB
krista@2947
   320
        status = set_reset_contact_notified(session, old_fpr, user_id);
krista@2947
   321
        if (status != PEP_STATUS_OK)
krista@2956
   322
            goto pEp_free;            
krista@2947
   323
    }
krista@2947
   324
    
krista@2956
   325
pEp_free:
krista@2947
   326
    free_identity_list(recent_contacts);
krista@2947
   327
    return status;
krista@2947
   328
}
krista@2947
   329
krista@3495
   330
DYNAMIC_API PEP_STATUS key_reset_identity(
krista@3495
   331
        PEP_SESSION session,
krista@3503
   332
        pEp_identity* ident,
krista@3503
   333
        const char* fpr        
krista@3495
   334
    )
krista@3495
   335
{
krista@3503
   336
    if (!session || !ident || (ident && (EMPTYSTR(ident->user_id) || EMPTYSTR(ident->address))))
krista@3495
   337
        return PEP_ILLEGAL_VALUE;
krista@3495
   338
    
krista@4245
   339
    return key_reset(session, fpr, ident, NULL, NULL);    
krista@3495
   340
}
krista@3495
   341
krista@3495
   342
DYNAMIC_API PEP_STATUS key_reset_user(
krista@3495
   343
        PEP_SESSION session,
krista@3503
   344
        const char* user_id,
krista@3503
   345
        const char* fpr        
krista@3495
   346
    )
krista@3495
   347
{
krista@3503
   348
    if (!session || EMPTYSTR(user_id))
krista@3495
   349
        return PEP_ILLEGAL_VALUE;
krista@3495
   350
krista@3503
   351
    pEp_identity* input_ident = new_identity(NULL, NULL, user_id, NULL);
krista@3503
   352
    if (!input_ident)
krista@3503
   353
        return PEP_OUT_OF_MEMORY;
krista@3503
   354
        
krista@3503
   355
    if (is_me(session, input_ident) && EMPTYSTR(fpr))
krista@3503
   356
        return PEP_ILLEGAL_VALUE;
krista@3495
   357
        
krista@4245
   358
    PEP_STATUS status = key_reset(session, fpr, input_ident, NULL, NULL);
krista@3503
   359
    free_identity(input_ident);
krista@3503
   360
    return status;
krista@3503
   361
}
krista@3495
   362
krista@3503
   363
DYNAMIC_API PEP_STATUS key_reset_all_own_keys(PEP_SESSION session) {
krista@4245
   364
    return key_reset(session, NULL, NULL, NULL, NULL);
krista@3495
   365
}
krista@3495
   366
krista@3495
   367
// Notes to integrate into header:
krista@3495
   368
// IF there is an ident, it must have a user_id.
krista@3495
   369
PEP_STATUS key_reset(
krista@2947
   370
        PEP_SESSION session,
krista@2947
   371
        const char* key_id,
krista@4245
   372
        pEp_identity* ident,
krista@4245
   373
        identity_list** own_identities,
krista@4245
   374
        stringlist_t** own_revoked_fprs
krista@2947
   375
    )
krista@2947
   376
{
krista@3495
   377
    if (!session || (ident && EMPTYSTR(ident->user_id)))
krista@2947
   378
        return PEP_ILLEGAL_VALUE;
krista@2947
   379
        
krista@2947
   380
    PEP_STATUS status = PEP_STATUS_OK;
krista@2947
   381
        
krista@2947
   382
    char* fpr_copy = NULL;
krista@2947
   383
    char* own_id = NULL;
krista@3495
   384
    char* user_id = NULL;
krista@2947
   385
    char* new_key = NULL;
krista@3495
   386
    pEp_identity* tmp_ident = NULL;
krista@2947
   387
    identity_list* key_idents = NULL;
krista@2947
   388
    stringlist_t* keys = NULL;
krista@2947
   389
    
krista@2947
   390
    if (!EMPTYSTR(key_id)) {
krista@2947
   391
        fpr_copy = strdup(key_id);
krista@2947
   392
        if (!fpr_copy)
krista@2947
   393
            return PEP_OUT_OF_MEMORY;
krista@2947
   394
    }
krista@3495
   395
krista@3495
   396
    // This is true when we don't have a user_id and address and the fpr isn't specified
krista@3495
   397
    bool reset_all_for_user = !fpr_copy && (!ident || EMPTYSTR(ident->address));
krista@3495
   398
krista@3495
   399
    // FIXME: does this need to be done everywhere?> I think not.
krista@3495
   400
    if (ident) {
krista@3495
   401
        user_id = strdup(ident->user_id);
krista@3495
   402
        if (!user_id) {
krista@3495
   403
            status = PEP_OUT_OF_MEMORY;
krista@2956
   404
            goto pEp_free;
krista@3495
   405
        }
krista@3495
   406
    }
krista@3495
   407
    else {
krista@3495
   408
        status = get_default_own_userid(session, &user_id);
krista@3495
   409
        if (status != PEP_STATUS_OK || !user_id)
krista@3495
   410
            goto pEp_free;                    
krista@3495
   411
    }
krista@3495
   412
    
krista@3495
   413
    // FIXME: Make sure this can't result in a double-free in recursive calls
krista@3495
   414
    tmp_ident = (ident ? identity_dup(ident) : new_identity(NULL, NULL, user_id, NULL));
krista@3495
   415
    
krista@3495
   416
    if (reset_all_for_user) {
krista@3495
   417
        status = get_all_keys_for_user(session, user_id, &keys);
krista@3495
   418
        // TODO: free
krista@3495
   419
        if (status == PEP_STATUS_OK) {
krista@3495
   420
            stringlist_t* curr_key;
krista@2947
   421
            
krista@3495
   422
            for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
krista@3495
   423
                // FIXME: Is the ident really necessary?
krista@4245
   424
                status = key_reset(session, curr_key->value, tmp_ident, own_identities, own_revoked_fprs);
krista@2947
   425
                if (status != PEP_STATUS_OK)
krista@3495
   426
                    break;
krista@2947
   427
            }
krista@2947
   428
        }
krista@3495
   429
        goto pEp_free;
krista@3495
   430
    }                   
krista@3495
   431
    else {
krista@3495
   432
        // tmp_ident => tmp_ident->user_id (was checked)
krista@3495
   433
        //
krista@3495
   434
        // !(EMPTYSTR(fpr) && (!tmp_ident || EMPTYSTR(tmp_ident->address)))
krista@3495
   435
        // => fpr || (tmp_ident && tmp_ident->address)
krista@3495
   436
        //
krista@3495
   437
        // so: We have an fpr or we have an ident with user_id and address
krista@3495
   438
        //     or both
krista@3495
   439
        if (!fpr_copy) {
krista@3495
   440
            // We are guaranteed to have an ident w/ id + addr here.
krista@3495
   441
            // Get the default key.
krista@3495
   442
            pEp_identity* stored_ident = NULL;
krista@3495
   443
            status = get_identity(session, tmp_ident->address, 
krista@3495
   444
                                  tmp_ident->user_id, &stored_ident);
krista@3495
   445
krista@3495
   446
            // FIXME FIXME FIXME
krista@3495
   447
            if (status == PEP_STATUS_OK) {
krista@3495
   448
                // transfer ownership
krista@3495
   449
                fpr_copy = stored_ident->fpr;
krista@3495
   450
                stored_ident->fpr = NULL;
krista@3495
   451
                free_identity(stored_ident);                
krista@3495
   452
            }
krista@3174
   453
            
krista@3495
   454
            if (!fpr_copy || status == PEP_CANNOT_FIND_IDENTITY) {
krista@3495
   455
                // There's no identity default. Try resetting user default
krista@3495
   456
                status = get_user_default_key(session, tmp_ident->user_id, &fpr_copy);
krista@3495
   457
            }            
krista@4117
   458
                        
krista@3495
   459
            if (!fpr_copy || status != PEP_STATUS_OK) // No default to free. We're done here.
krista@3495
   460
                goto pEp_free;            
krista@3495
   461
        }
krista@3495
   462
        
krista@3495
   463
        // Ok - now we have at least an ident with user_id and an fpr.
krista@3495
   464
        // Now it matters if we're talking about ourselves or a partner.
krista@3495
   465
        bool is_own_private = false;
krista@3495
   466
        if (is_me(session, tmp_ident)) {
krista@3495
   467
            bool own_key = false;            
krista@3495
   468
            status = is_own_key(session, fpr_copy, &own_key);
krista@3495
   469
krista@3495
   470
            if (status != PEP_STATUS_OK)
krista@3495
   471
                goto pEp_free;
krista@3495
   472
            if (!own_key) {
krista@3495
   473
                status = PEP_ILLEGAL_VALUE;
krista@3495
   474
                goto pEp_free;
krista@3495
   475
            }
krista@3495
   476
krista@3495
   477
            status = contains_priv_key(session, fpr_copy, &is_own_private);
krista@3507
   478
            if (status != PEP_STATUS_OK && status != PEP_KEY_NOT_FOUND)
krista@3495
   479
                goto pEp_free;
krista@3495
   480
        }
krista@3495
   481
        
krista@3495
   482
        // Up to this point, we haven't cared about whether or not we 
krista@3495
   483
        // had a full identity. Now we have to deal with that in the 
krista@3495
   484
        // case of own identities with private keys.
krista@3495
   485
        
krista@3495
   486
        if (is_own_private) {
krista@3495
   487
            
krista@3495
   488
            // If there's no address, we want to reset this key for every identity 
krista@3495
   489
            // it's a part of. Since this means generating new keys, we have to 
krista@3495
   490
            // grab all the identities associated with it.
krista@3495
   491
            if (EMPTYSTR(tmp_ident->address)) {
krista@3495
   492
                status = get_identities_by_main_key_id(session, fpr_copy, &key_idents);
krista@3495
   493
                
krista@3495
   494
                if (status != PEP_CANNOT_FIND_IDENTITY) {
krista@3495
   495
                    if (status == PEP_STATUS_OK) {
krista@3495
   496
                        // now have ident list, or should
krista@3495
   497
                        identity_list* curr_ident;
krista@3495
   498
                        
krista@3495
   499
                        for (curr_ident = key_idents; curr_ident && curr_ident->ident; 
krista@3495
   500
                                                        curr_ident = curr_ident->next) {
krista@3495
   501
                            
krista@3495
   502
                            pEp_identity* this_identity = curr_ident->ident;
krista@3495
   503
                            // Do the full reset on this identity        
krista@4245
   504
                            status = key_reset(session, fpr_copy, this_identity, own_identities, own_revoked_fprs);
krista@3495
   505
                            
krista@3495
   506
                            // Ident list gets freed below, do not free here!
krista@3495
   507
krista@3495
   508
                            if (status != PEP_STATUS_OK)
krista@3495
   509
                                break;
krista@3495
   510
                            
krista@3495
   511
                        }
krista@2947
   512
                    }
krista@3495
   513
                    // Ok, we've either now reset for each own identity with this key, or 
krista@3495
   514
                    // we got an error and want to bail anyway.
krista@3495
   515
                    goto pEp_free;
krista@3495
   516
                }    
krista@2947
   517
            }
krista@3495
   518
            
krista@4245
   519
            // Base case for is_own_private starts here
krista@4245
   520
            
krista@2947
   521
            status = revoke_key(session, fpr_copy, NULL);
krista@2947
   522
            
krista@3495
   523
            // If we have a full identity, we have some cleanup and generation tasks here
krista@3495
   524
            if (!EMPTYSTR(tmp_ident->address)) {
krista@3495
   525
                // generate new key
krista@3495
   526
                if (status == PEP_STATUS_OK) {
krista@3495
   527
                    tmp_ident->fpr = NULL;
krista@3989
   528
                    status = myself(session, tmp_ident);
krista@3988
   529
                }
krista@3989
   530
                if (status == PEP_STATUS_OK && tmp_ident->fpr && strcmp(fpr_copy, tmp_ident->fpr) != 0) {
krista@3988
   531
                    new_key = strdup(tmp_ident->fpr);
krista@3989
   532
//                    status = set_own_key(session, tmp_ident, new_key);
krista@3495
   533
                }
krista@4245
   534
krista@4245
   535
                if (own_revoked_fprs) {
krista@4245
   536
                    // We can dedup this later
krista@4245
   537
                    if (!(*own_revoked_fprs))
krista@4245
   538
                        *own_revoked_fprs = new_stringlist(NULL);
krista@4245
   539
                    
krista@4245
   540
                    char* revkey = strdup(fpr_copy);
krista@4245
   541
                    if (!revkey) {
krista@4245
   542
                        status = PEP_OUT_OF_MEMORY;
krista@4245
   543
                        goto pEp_free;
krista@4245
   544
                    }
krista@4245
   545
                    stringlist_add(*own_revoked_fprs, revkey);                
krista@4245
   546
                }
krista@4245
   547
                
krista@3495
   548
                // mistrust fpr from trust
krista@3495
   549
                tmp_ident->fpr = fpr_copy;
krista@4245
   550
                                                
krista@3495
   551
                tmp_ident->comm_type = PEP_ct_mistrusted;
krista@3495
   552
                status = set_trust(session, tmp_ident);
krista@3495
   553
                tmp_ident->fpr = NULL;
krista@3495
   554
                
krista@3495
   555
                // Done with old use of ident.
krista@3495
   556
                if (status == PEP_STATUS_OK) {
krista@3495
   557
                    // Update fpr for outgoing
krista@3495
   558
                    status = myself(session, tmp_ident);
krista@3495
   559
                }
krista@4245
   560
                
krista@4246
   561
                if (status == PEP_STATUS_OK && own_identities) {
krista@4245
   562
                    if (!(*own_identities))
krista@4245
   563
                        *own_identities = new_identity_list(NULL);
krista@4245
   564
                    
krista@4245
   565
                    pEp_identity* new_ident = identity_dup(tmp_ident);
krista@4245
   566
                    if (!new_ident) {
krista@4245
   567
                        status = PEP_OUT_OF_MEMORY;
krista@4245
   568
                        goto pEp_free;
krista@4245
   569
                    }
krista@4245
   570
                    identity_list_add(*own_identities, new_ident);            
krista@4245
   571
                }    
krista@3495
   572
            }    
krista@2947
   573
            
krista@2947
   574
            if (status == PEP_STATUS_OK)
krista@2947
   575
                // cascade that mistrust for anyone using this key
krista@2947
   576
                status = mark_as_compromised(session, fpr_copy);
krista@3495
   577
                
krista@2947
   578
            if (status == PEP_STATUS_OK)
krista@2947
   579
                status = remove_fpr_as_default(session, fpr_copy);
krista@2947
   580
            if (status == PEP_STATUS_OK)
krista@2947
   581
                status = add_mistrusted_key(session, fpr_copy);
krista@3495
   582
krista@3495
   583
            // If there's a new key, do the DB linkage with the revoked one, and 
krista@3495
   584
            // send the key reset mail opportunistically to recently contacted
krista@3495
   585
            // partners
krista@3495
   586
            if (new_key) {
krista@3495
   587
                // add to revocation list 
krista@3495
   588
                if (status == PEP_STATUS_OK) 
krista@3495
   589
                    status = set_revoked(session, fpr_copy, new_key, time(NULL));            
krista@3495
   590
                // for all active communication partners:
krista@3495
   591
                //      active_send revocation
krista@3495
   592
                if (status == PEP_STATUS_OK)
krista@3495
   593
                    status = send_key_reset_to_recents(session, fpr_copy, new_key);        
krista@3495
   594
            }        
krista@3495
   595
        } // end is_own_private
krista@3495
   596
        else {
krista@4120
   597
            // if it's mistrusted, make it not be so.
krista@4120
   598
            bool mistrusted_key = false;
krista@4120
   599
            is_mistrusted_key(session, fpr_copy, &mistrusted_key);
krista@4120
   600
krista@4120
   601
            if (mistrusted_key)
krista@4120
   602
                delete_mistrusted_key(session, fpr_copy);
krista@4120
   603
            
krista@4121
   604
            if (tmp_ident->user_id)
krista@4121
   605
                status = clear_trust_info(session, tmp_ident->user_id, fpr_copy);
krista@4121
   606
krista@3495
   607
            // This is a public key (or a private key that isn't ours, which means
krista@3495
   608
            // we want it gone anyway)
krista@3495
   609
            //
krista@3495
   610
            // Delete this key from the keyring.
krista@4245
   611
            // FIXME: when key election disappears, so should this!
krista@3495
   612
            status = delete_keypair(session, fpr_copy);
krista@2947
   613
        }
krista@3495
   614
krista@3495
   615
        // REGARDLESS OF WHO OWNS THE KEY, WE NOW NEED TO REMOVE IT AS A DEFAULT.
krista@3495
   616
        PEP_STATUS cached_status = status;
krista@3495
   617
        // remove fpr from all identities
krista@3495
   618
        // remove fpr from all users
krista@3495
   619
        status = remove_fpr_as_default(session, fpr_copy);
krista@3495
   620
        // delete key from DB - this does NOT touch the keyring!
krista@3495
   621
        // Note: for own priv keys, we cannot do this. But we'll never encrypt to/from it.
krista@3495
   622
        if (status == PEP_STATUS_OK && !is_own_private) {
krista@3495
   623
            status = remove_key(session, fpr_copy);
krista@2947
   624
        }
krista@3495
   625
        if (status == PEP_STATUS_OK)
krista@3495
   626
            status = cached_status;
krista@3495
   627
    }           
krista@3495
   628
        
krista@2956
   629
pEp_free:
krista@3495
   630
    if (!ident)
krista@3495
   631
        free_identity(tmp_ident);
krista@2947
   632
    free(fpr_copy);
krista@2947
   633
    free(own_id);
krista@2947
   634
    free_identity_list(key_idents);
krista@2947
   635
    free_stringlist(keys);
krista@2947
   636
    free(new_key);    
krista@2947
   637
    return status;
krista@2947
   638
}
krista@4245
   639
krista@4245
   640
static stringlist_t* collect_key_material(PEP_SESSION session, stringlist_t* fprs) {
krista@4245
   641
    stringlist_t* keydata = NULL;    
krista@4245
   642
    stringlist_t* curr_fpr = fprs;    
krista@4245
   643
    while (curr_fpr) {
krista@4245
   644
        if (curr_fpr->value) {
krista@4245
   645
            char* key_material = NULL;
krista@4245
   646
            size_t datasize = 0;
krista@4245
   647
            PEP_STATUS status = export_key(session, curr_fpr->value, &key_material, &datasize);
krista@4245
   648
            if (status) {
krista@4245
   649
                free_stringlist(keydata);
krista@4245
   650
                return NULL;
krista@4245
   651
            }
krista@4245
   652
            if (datasize > 0 && key_material) {
krista@4245
   653
                if (!(keydata))
krista@4245
   654
                    keydata = new_stringlist(NULL);
krista@4245
   655
                    
krista@4245
   656
                stringlist_add(keydata, key_material);
krista@4245
   657
            }
krista@4245
   658
        }
krista@4245
   659
        curr_fpr = curr_fpr->next;        
krista@4245
   660
    }   
krista@4245
   661
    return keydata; 
krista@4245
   662
}
krista@4245
   663
krista@4245
   664
PEP_STATUS key_reset_own_and_deliver_revocations(PEP_SESSION session, 
krista@4245
   665
                                                 identity_list** own_identities, 
krista@4245
   666
                                                 stringlist_t** revocations, 
krista@4245
   667
                                                 stringlist_t** keys) {
krista@4245
   668
krista@4245
   669
    if (!(session && own_identities && revocations && keys))
krista@4245
   670
        return PEP_ILLEGAL_VALUE;
krista@4245
   671
        
krista@4245
   672
    stringlist_t* revoked_fprs = NULL;
krista@4245
   673
    identity_list* affected_idents = NULL;
krista@4245
   674
        
krista@4245
   675
    PEP_STATUS status = key_reset(session, NULL, NULL, &affected_idents, &revoked_fprs);                                                 
krista@4245
   676
krista@4245
   677
    // FIXME: free things
krista@4245
   678
    if (status != PEP_STATUS_OK)
krista@4245
   679
        return status;
krista@4245
   680
    
krista@4245
   681
    dedup_stringlist(revoked_fprs);
krista@4245
   682
krista@4245
   683
    *revocations = collect_key_material(session, revoked_fprs);
krista@4245
   684
    stringlist_t* keydata = NULL;
krista@4245
   685
    
krista@4245
   686
    if (affected_idents) {
krista@4245
   687
        keydata = new_stringlist(NULL);
krista@4245
   688
        identity_list* curr_ident = affected_idents;
krista@4245
   689
        while (curr_ident) {
krista@4245
   690
            if (curr_ident->ident && curr_ident->ident->fpr) {
krista@4245
   691
                char* key_material = NULL;
krista@4245
   692
                size_t datasize = 0;
krista@4245
   693
                status = export_key(session, curr_ident->ident->fpr, &key_material, &datasize);
krista@4245
   694
                if (status) {
krista@4245
   695
                    free_stringlist(keydata);
krista@4245
   696
                    return status;
krista@4245
   697
                }
krista@4245
   698
                if (datasize > 0 && key_material)
krista@4245
   699
                    stringlist_add(keydata, key_material);
krista@4245
   700
            }
krista@4246
   701
            curr_ident = curr_ident->next;
krista@4245
   702
        }
krista@4245
   703
    }
krista@4245
   704
    
krista@4245
   705
    *own_identities = affected_idents;
krista@4245
   706
    *keys = keydata;
krista@4245
   707
    
krista@4245
   708
    free(revoked_fprs);
krista@4245
   709
    return PEP_STATUS_OK;
krista@4245
   710
}
vb@4256
   711
vb@4261
   712
PEP_STATUS key_reset_commands_to_PER(const keyreset_command_list *command_list, char **cmds, size_t *size)
vb@4256
   713
{
vb@4257
   714
    PEP_STATUS status = PEP_STATUS_OK;
vb@4257
   715
vb@4257
   716
    assert(command_list && cmds);
vb@4257
   717
    if (!(command_list && cmds))
vb@4257
   718
        return PEP_ILLEGAL_VALUE;
vb@4257
   719
vb@4261
   720
    *cmds = NULL;
vb@4261
   721
    *size = 0;
vb@4261
   722
vb@4261
   723
    Distribution_t *dist = (Distribution_t *) calloc(1, sizeof(Distribution_t));
vb@4261
   724
    assert(dist);
vb@4261
   725
    if (!dist)
vb@4261
   726
        goto enomem;
vb@4261
   727
vb@4261
   728
    dist->present = Distribution_PR_keyreset;
vb@4261
   729
    dist->choice.keyreset.present = KeyReset_PR_commands;
vb@4261
   730
vb@4261
   731
    // convert to ASN.1 struct
vb@4261
   732
vb@4257
   733
    for (const keyreset_command_list *cl = command_list; cl && cl->command; cl = cl->next) {
vb@4260
   734
        Command_t *c = (Command_t *) calloc(1, sizeof(Command_t));
vb@4257
   735
        assert(c);
vb@4257
   736
        if (!c)
vb@4257
   737
            goto enomem;
vb@4257
   738
vb@4257
   739
        if (!Identity_from_Struct(cl->command->ident, &c->ident)) {
vb@4257
   740
            free(c);
vb@4257
   741
            goto enomem;
vb@4257
   742
        }
vb@4257
   743
vb@4257
   744
        if (OCTET_STRING_fromString(&c->newkey, cl->command->new_key)) {
vb@4261
   745
            ASN_STRUCT_FREE(asn_DEF_Command, c);
vb@4261
   746
            goto enomem;
vb@4261
   747
        }
vb@4261
   748
vb@4261
   749
        if (ASN_SEQUENCE_ADD(&dist->choice.keyreset.choice.commands.commandlist, c)) {
vb@4261
   750
            ASN_STRUCT_FREE(asn_DEF_Command, c);
vb@4257
   751
            goto enomem;
vb@4257
   752
        }
vb@4257
   753
    }
vb@4257
   754
vb@4261
   755
    // encode
vb@4261
   756
vb@4261
   757
    char *_cmds;
vb@4261
   758
    size_t _size;
vb@4261
   759
    status = encode_Distribution_message(dist, &_cmds, &_size);
vb@4261
   760
    if (status)
vb@4261
   761
        goto the_end;
vb@4261
   762
vb@4261
   763
    *cmds = _cmds;
vb@4261
   764
    *size = _size;
vb@4261
   765
    goto the_end;
vb@4261
   766
vb@4257
   767
enomem:
vb@4257
   768
    status = PEP_OUT_OF_MEMORY;
vb@4257
   769
vb@4257
   770
the_end:
vb@4261
   771
    ASN_STRUCT_FREE(asn_DEF_Distribution, dist);
vb@4257
   772
    return status;
vb@4257
   773
}
vb@4257
   774
vb@4261
   775
PEP_STATUS PER_to_key_reset_commands(const char *cmds, size_t size, keyreset_command_list **command_list)
vb@4257
   776
{
vb@4257
   777
    assert(command_list && cmds);
vb@4257
   778
    if (!(command_list && cmds))
vb@4256
   779
        return PEP_ILLEGAL_VALUE;
vb@4256
   780
vb@4262
   781
    *command_list = NULL;
vb@4262
   782
    keyreset_command_list *result = NULL;
vb@4262
   783
vb@4262
   784
    Distribution_t *dist = NULL;
vb@4262
   785
    PEP_STATUS status = decode_Distribution_message(cmds, size, &dist);
vb@4262
   786
    if (status)
vb@4262
   787
        goto the_end;
vb@4262
   788
vb@4265
   789
    assert(dist && dist->present == Distribution_PR_keyreset
vb@4265
   790
            && dist->choice.keyreset.present == KeyReset_PR_commands);
vb@4265
   791
vb@4262
   792
    if (!(dist && dist->present == Distribution_PR_keyreset
vb@4262
   793
            && dist->choice.keyreset.present == KeyReset_PR_commands)) {
vb@4265
   794
        status = PEP_ILLEGAL_VALUE;
vb@4262
   795
        goto the_end;
vb@4262
   796
    }
vb@4262
   797
vb@4262
   798
    result = new_keyreset_command_list(NULL);
vb@4262
   799
    if (!result)
vb@4262
   800
        goto enomem;
vb@4262
   801
vb@4262
   802
    struct Commands__commandlist *cl = &dist->choice.keyreset.choice.commands.commandlist;
vb@4262
   803
    keyreset_command_list *_result = result;
vb@4262
   804
    for (int i=0; i<cl->list.count; i++) {
vb@4262
   805
        pEp_identity *ident = Identity_to_Struct(&cl->list.array[i]->ident, NULL);
vb@4262
   806
        if (!ident)
vb@4262
   807
            goto enomem;
vb@4262
   808
vb@4262
   809
        const char *new_key = (const char *) cl->list.array[i]->newkey.buf;
vb@4262
   810
        keyreset_command *command = new_keyreset_command(ident, new_key);
vb@4262
   811
        if (!command) {
vb@4262
   812
            free_identity(ident);
vb@4262
   813
            goto enomem;
vb@4262
   814
        }
vb@4262
   815
vb@4262
   816
        _result = keyreset_command_list_add(_result, command);
vb@4262
   817
        free_identity(ident);
vb@4262
   818
        if (!_result)
vb@4262
   819
            goto enomem;
vb@4262
   820
    }
vb@4262
   821
vb@4263
   822
    *command_list = result;
vb@4262
   823
    goto the_end;
vb@4262
   824
vb@4262
   825
enomem:
vb@4262
   826
    status = PEP_OUT_OF_MEMORY;
vb@4264
   827
    free_keyreset_command_list(result);
vb@4262
   828
vb@4262
   829
the_end:
vb@4262
   830
    ASN_STRUCT_FREE(asn_DEF_Distribution, dist);
vb@4262
   831
    return status;
vb@4256
   832
}
vb@4256
   833