src/key_reset.c
author Krista 'DarthMama' Bennett <krista@pep.foundation>
Mon, 20 Jan 2020 11:57:38 +0100
branchsync
changeset 4356 abf2aaa18e05
parent 4353 3c59288158d7
child 4361 f13151f0b577
permissions -rw-r--r--
reset status
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"
krista@4312
    10
#include "keymanagement.h"
krista@4312
    11
#include "baseprotocol.h"
vb@4257
    12
#include "../asn.1/Distribution.h"
krista@4312
    13
#include "Sync_impl.h" // this seems... bad
krista@2947
    14
krista@2947
    15
#include <string.h>
krista@2947
    16
#include <stdlib.h>
krista@2947
    17
vb@4275
    18
// FIXME: these should be taken from sync/Distribution.fsm
vb@4275
    19
vb@4275
    20
#define KEY_RESET_MAJOR_VERSION 1L
vb@4275
    21
#define KEY_RESET_MINOR_VERSION 0L
vb@4275
    22
krista@4327
    23
static PEP_STATUS _generate_reset_structs(PEP_SESSION session,
krista@4327
    24
                                          const pEp_identity* reset_ident,
krista@4327
    25
                                          const char* old_fpr,
krista@4327
    26
                                          const char* new_fpr,
krista@4327
    27
                                          bloblist_t** key_attachments,
krista@4327
    28
                                          keyreset_command_list** command_list,
krista@4327
    29
                                          bool include_secret) {
krista@4327
    30
krista@4327
    31
    if (!session || !reset_ident || EMPTYSTR(old_fpr) || EMPTYSTR(new_fpr) ||
krista@4327
    32
        !key_attachments || !command_list)
krista@4327
    33
        return PEP_ILLEGAL_VALUE;
krista@4327
    34
    
krista@4327
    35
    // Ok, generate payload here...
krista@4327
    36
    pEp_identity* outgoing_ident = identity_dup(reset_ident);
krista@4327
    37
    if (!outgoing_ident)
krista@4327
    38
        return PEP_OUT_OF_MEMORY;
krista@4327
    39
    free(outgoing_ident->fpr);
krista@4327
    40
    outgoing_ident->fpr = strdup(old_fpr);
krista@4327
    41
    if (!outgoing_ident->fpr)
krista@4327
    42
        return PEP_OUT_OF_MEMORY;
krista@4327
    43
        
krista@4327
    44
    keyreset_command* kr_command = new_keyreset_command(outgoing_ident, new_fpr);
krista@4327
    45
    if (!kr_command)
krista@4327
    46
        return PEP_OUT_OF_MEMORY;
krista@4327
    47
    if (!*command_list)
krista@4327
    48
        *command_list = new_keyreset_command_list(kr_command);
krista@4327
    49
    else
krista@4327
    50
        if (keyreset_command_list_add(*command_list, kr_command) == NULL)
krista@4327
    51
            return PEP_OUT_OF_MEMORY;
krista@4327
    52
    
krista@4327
    53
    bloblist_t* keys = NULL;
krista@4327
    54
    
krista@4327
    55
    char* key_material_old = NULL;
krista@4327
    56
    char* key_material_new = NULL;   
krista@4327
    57
    char* key_material_priv = NULL;
krista@4327
    58
     
krista@4327
    59
    size_t datasize = 0;
krista@4327
    60
    
krista@4330
    61
    PEP_STATUS status = PEP_STATUS_OK;
krista@4330
    62
    
krista@4330
    63
    if (!include_secret) { // This isn't to own recips, so shipping the rev'd key is OK. Own keys are revoked on each device.
krista@4330
    64
        status = export_key(session, old_fpr, &key_material_old, &datasize);
krista@4330
    65
        if (datasize > 0 && key_material_old) {         
krista@4330
    66
            if (status != PEP_STATUS_OK)
krista@4330
    67
                return status;
krista@4327
    68
krista@4330
    69
            if (!keys)
krista@4330
    70
                keys = new_bloblist(key_material_old, datasize, 
krista@4330
    71
                                                "application/pgp-keys",
krista@4330
    72
                                                "file://pEpkey_old.asc");
krista@4330
    73
            else                                    
krista@4330
    74
                bloblist_add(keys, key_material_old, datasize, "application/pgp-keys",
krista@4330
    75
                                                                       "file://pEpkey_old.asc");
krista@4330
    76
        }
krista@4330
    77
        datasize = 0;
krista@4330
    78
    }                                                                  
krista@4327
    79
    status = export_key(session, new_fpr, &key_material_new, &datasize);
krista@4327
    80
krista@4327
    81
    if (datasize > 0 && key_material_new) {         
krista@4330
    82
        if (status != PEP_STATUS_OK)
krista@4327
    83
            return status;
krista@4327
    84
krista@4327
    85
        if (!keys)
krista@4327
    86
            keys = new_bloblist(key_material_new, datasize, 
krista@4327
    87
                                            "application/pgp-keys",
krista@4327
    88
                                            "file://pEpkey_new_pub.asc");
krista@4327
    89
        else                                    
krista@4327
    90
            bloblist_add(keys, key_material_new, datasize, "application/pgp-keys", "file://pEpkey_new_pub.asc");
krista@4327
    91
                        
krista@4327
    92
        datasize = 0;    
krista@4327
    93
        if (include_secret) {
krista@4327
    94
            status = export_secret_key(session, new_fpr, &key_material_priv, &datasize);    
krista@4330
    95
            if (status != PEP_STATUS_OK)
krista@4327
    96
                return status;
krista@4327
    97
            if (datasize > 0 && key_material_priv) {
krista@4327
    98
                bloblist_add(keys, key_material_priv, datasize, "application/pgp-keys",
krista@4327
    99
                                                                            "file://pEpkey_priv.asc");
krista@4327
   100
            }                                                      
krista@4327
   101
        }    
krista@4327
   102
    }
krista@4327
   103
    if (keys) {
krista@4327
   104
        if (*key_attachments)
krista@4327
   105
            bloblist_join(*key_attachments, keys);
krista@4327
   106
        else
krista@4327
   107
            *key_attachments = keys;
krista@4327
   108
    }        
krista@4327
   109
    return status;
krista@4327
   110
}
krista@4327
   111
krista@4327
   112
// For multiple idents under a single key
krista@4327
   113
// idents contain new fprs
krista@4327
   114
static PEP_STATUS _generate_own_commandlist_msg(PEP_SESSION session,
krista@4327
   115
                                                identity_list* from_idents,
krista@4327
   116
                                                const char* old_fpr,
krista@4327
   117
                                                message** dst) {                                                
krista@4327
   118
    PEP_STATUS status = PEP_STATUS_OK;
krista@4327
   119
    message* msg = NULL;                                                
krista@4327
   120
    identity_list* list_curr = from_idents;
krista@4327
   121
    keyreset_command_list* kr_commands = NULL;
krista@4327
   122
    bloblist_t* key_attachments = NULL;
krista@4327
   123
    
krista@4327
   124
    for ( ; list_curr && list_curr->ident; list_curr = list_curr->next) {
krista@4327
   125
        pEp_identity* curr_ident = list_curr->ident;
krista@4327
   126
        
krista@4327
   127
        if (curr_ident->flags & PEP_idf_devicegroup) {                
krista@4327
   128
        
krista@4327
   129
            PEP_STATUS status = _generate_reset_structs(session,
krista@4327
   130
                                                        curr_ident,
krista@4327
   131
                                                        old_fpr,
krista@4327
   132
                                                        curr_ident->fpr,
krista@4327
   133
                                                        &key_attachments,
krista@4327
   134
                                                        &kr_commands,
krista@4327
   135
                                                        true);
krista@4327
   136
            if (status != PEP_STATUS_OK)
krista@4327
   137
                return status; // FIXME
krista@4327
   138
            if (!key_attachments || !kr_commands)
krista@4327
   139
                return PEP_UNKNOWN_ERROR;
krista@4327
   140
        }        
krista@4327
   141
    }
krista@4329
   142
    
krista@4329
   143
    if (!kr_commands) {
krista@4329
   144
        // There was nothing for us to send to self - we could be ungrouped,
krista@4329
   145
        // etc
krista@4329
   146
        return PEP_STATUS_OK;
krista@4329
   147
    }    
krista@4327
   148
    char* payload = NULL;
krista@4327
   149
    size_t size = 0;
krista@4327
   150
    status = key_reset_commands_to_PER(kr_commands, &payload, &size);
krista@4327
   151
    if (status != PEP_STATUS_OK)
krista@4327
   152
        return status;
krista@4329
   153
        
krista@4327
   154
    // From and to our first ident - this only goes to us.
krista@4327
   155
    pEp_identity* from = identity_dup(from_idents->ident);
krista@4327
   156
    pEp_identity* to = identity_dup(from);    
krista@4327
   157
    status = base_prepare_message(session, from, to,
krista@4327
   158
                                  BASE_KEYRESET, payload, size, NULL,
krista@4327
   159
                                  &msg);
krista@4327
   160
krista@4327
   161
    if (status != PEP_STATUS_OK) {
krista@4327
   162
        free(msg);
krista@4327
   163
        return status;
krista@4327
   164
    }    
krista@4327
   165
    if (!msg)
krista@4327
   166
        return PEP_OUT_OF_MEMORY;
krista@4327
   167
    if (!msg->attachments)
krista@4327
   168
        return PEP_UNKNOWN_ERROR;
krista@4327
   169
    
krista@4327
   170
    if (!bloblist_join(msg->attachments, key_attachments))
krista@4327
   171
        return PEP_UNKNOWN_ERROR;
krista@4327
   172
krista@4327
   173
    if (msg)
krista@4327
   174
        *dst = msg;
krista@4327
   175
krista@4327
   176
    free_keyreset_command_list(kr_commands);
krista@4327
   177
        
krista@4327
   178
    return status;
krista@4327
   179
krista@4327
   180
}
krista@4327
   181
krista@4312
   182
static PEP_STATUS _generate_keyreset_command_message(PEP_SESSION session,
krista@4312
   183
                                                     const pEp_identity* from_ident,
krista@4312
   184
                                                     const pEp_identity* to_ident,
krista@4312
   185
                                                     const char* old_fpr,
krista@4312
   186
                                                     const char* new_fpr,
krista@4312
   187
                                                     bool is_private,
krista@4312
   188
                                                     message** dst) {
krista@4312
   189
                                                                                                                  
krista@4312
   190
    if (!session || !from_ident || !old_fpr || !new_fpr || !dst)
krista@4312
   191
        return PEP_ILLEGAL_VALUE;
krista@4312
   192
krista@4312
   193
    // safe cast
krista@4312
   194
    if (!is_me(session, (pEp_identity*)from_ident))
krista@4312
   195
        return PEP_ILLEGAL_VALUE;
krista@4312
   196
krista@4312
   197
    PEP_STATUS status = PEP_STATUS_OK;
krista@4312
   198
        
krista@4312
   199
    *dst = NULL;
krista@4321
   200
        
krista@4315
   201
    message* msg = NULL;
krista@4315
   202
    
krista@4312
   203
    // Ok, generate payload here...
krista@4312
   204
    pEp_identity* outgoing_ident = identity_dup(from_ident);
krista@4312
   205
    if (!outgoing_ident)
krista@4312
   206
        return PEP_OUT_OF_MEMORY;
krista@4312
   207
    free(outgoing_ident->fpr);
krista@4312
   208
    outgoing_ident->fpr = strdup(old_fpr);
krista@4312
   209
    if (!outgoing_ident->fpr)
krista@4312
   210
        return PEP_OUT_OF_MEMORY;
krista@4312
   211
        
krista@4327
   212
    keyreset_command_list* kr_list = NULL;
krista@4327
   213
    bloblist_t* key_attachments = NULL;
krista@4327
   214
            
krista@4327
   215
    // Check memory        
krista@4327
   216
    status = _generate_reset_structs(session,
krista@4327
   217
                                     outgoing_ident,
krista@4327
   218
                                     old_fpr,
krista@4327
   219
                                     new_fpr,
krista@4327
   220
                                     &key_attachments,
krista@4327
   221
                                     &kr_list,
krista@4327
   222
                                     is_private);
krista@4327
   223
    if (status != PEP_STATUS_OK)
krista@4327
   224
        return status; // FIXME
krista@4327
   225
    if (!key_attachments || !kr_list)
krista@4327
   226
        return PEP_UNKNOWN_ERROR;
krista@4327
   227
        
krista@4312
   228
    char* payload = NULL;
krista@4312
   229
    size_t size = 0;
krista@4312
   230
    status = key_reset_commands_to_PER(kr_list, &payload, &size);
krista@4312
   231
    status = base_prepare_message(session, outgoing_ident, to_ident,
krista@4312
   232
                                  BASE_KEYRESET, payload, size, NULL,
krista@4312
   233
                                  &msg);
krista@4312
   234
    if (status) {
krista@4312
   235
        free(msg);
krista@4312
   236
        return status;
krista@4312
   237
    }    
krista@4312
   238
    if (!msg)
krista@4312
   239
        return PEP_OUT_OF_MEMORY;
krista@4312
   240
    if (!msg->attachments)
krista@4312
   241
        return PEP_UNKNOWN_ERROR;
krista@4312
   242
    
krista@4315
   243
    if (msg)
krista@4315
   244
        *dst = msg;
krista@4312
   245
    return status;
krista@4312
   246
}
krista@4312
   247
krista@2947
   248
PEP_STATUS has_key_reset_been_sent(
krista@2947
   249
        PEP_SESSION session, 
krista@4312
   250
        const char* from_addr,
krista@2947
   251
        const char* user_id, 
krista@2947
   252
        const char* revoked_fpr,
krista@2947
   253
        bool* contacted)
krista@2947
   254
{
krista@2947
   255
    assert(session);
krista@2947
   256
    assert(contacted);
krista@2947
   257
    assert(user_id);
krista@2947
   258
    assert(revoked_fpr);
krista@2947
   259
    assert(!EMPTYSTR(user_id));
krista@2947
   260
krista@4312
   261
    if (!session || !contacted || EMPTYSTR(from_addr) || EMPTYSTR(revoked_fpr) || EMPTYSTR(user_id))
krista@2947
   262
        return PEP_ILLEGAL_VALUE;
krista@2947
   263
    
krista@2947
   264
    *contacted = false;
krista@2947
   265
                    
krista@2947
   266
    char* alias_default = NULL;
krista@2947
   267
    
krista@2947
   268
    PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
krista@2947
   269
    
krista@2947
   270
    if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
krista@2947
   271
        free(alias_default);
krista@2947
   272
        alias_default = strdup(user_id);
krista@2947
   273
    }
krista@2947
   274
    
krista@2947
   275
    sqlite3_reset(session->was_id_for_revoke_contacted);
krista@2947
   276
    sqlite3_bind_text(session->was_id_for_revoke_contacted, 1, revoked_fpr, -1,
krista@2947
   277
            SQLITE_STATIC);
krista@4312
   278
    sqlite3_bind_text(session->was_id_for_revoke_contacted, 2, from_addr, -1,
krista@4312
   279
            SQLITE_STATIC);        
krista@4312
   280
    sqlite3_bind_text(session->was_id_for_revoke_contacted, 3, user_id, -1,
krista@2947
   281
            SQLITE_STATIC);        
krista@4142
   282
    int result = sqlite3_step(session->was_id_for_revoke_contacted);
krista@2947
   283
    switch (result) {
krista@2947
   284
        case SQLITE_ROW: {
krista@2947
   285
            *contacted = (sqlite3_column_int(session->was_id_for_revoke_contacted, 0) != 0);
krista@2947
   286
            break;
krista@2947
   287
        }
krista@2947
   288
        default:
krista@2947
   289
            sqlite3_reset(session->was_id_for_revoke_contacted);
krista@2947
   290
            free(alias_default);
krista@2947
   291
            return PEP_UNKNOWN_DB_ERROR;
krista@2947
   292
    }
krista@2947
   293
krista@2947
   294
    sqlite3_reset(session->was_id_for_revoke_contacted);
krista@2947
   295
    return PEP_STATUS_OK;
krista@2947
   296
}
krista@2947
   297
krista@2947
   298
PEP_STATUS set_reset_contact_notified(
krista@2947
   299
        PEP_SESSION session,
krista@4312
   300
        const char* own_address,
krista@2947
   301
        const char* revoke_fpr,
krista@2947
   302
        const char* contact_id
krista@2947
   303
    )
krista@2947
   304
{
krista@2947
   305
    PEP_STATUS status = PEP_STATUS_OK;
krista@2947
   306
    
krista@4312
   307
    assert(session && !EMPTYSTR(own_address) && !EMPTYSTR(revoke_fpr) && !EMPTYSTR(contact_id));
krista@2947
   308
    
krista@4312
   309
    if (!session || EMPTYSTR(own_address) || EMPTYSTR(revoke_fpr) || EMPTYSTR(contact_id))
krista@2947
   310
        return PEP_ILLEGAL_VALUE;
krista@2947
   311
    
krista@2947
   312
    sqlite3_reset(session->set_revoke_contact_as_notified);
krista@2947
   313
    sqlite3_bind_text(session->set_revoke_contact_as_notified, 1, revoke_fpr, -1, 
krista@2947
   314
            SQLITE_STATIC);
krista@4312
   315
    sqlite3_bind_text(session->set_revoke_contact_as_notified, 2, own_address, -1, 
krista@4312
   316
            SQLITE_STATIC);            
krista@4312
   317
    sqlite3_bind_text(session->set_revoke_contact_as_notified, 3, contact_id, -1,
krista@2947
   318
            SQLITE_STATIC);
krista@2947
   319
krista@2947
   320
    int result;
krista@2947
   321
    
krista@4142
   322
    result = sqlite3_step(session->set_revoke_contact_as_notified);
krista@2947
   323
    switch (result) {
krista@2947
   324
        case SQLITE_DONE:
krista@2947
   325
            status = PEP_STATUS_OK;
krista@2947
   326
            break;
krista@2947
   327
            
krista@2947
   328
        default:
krista@2947
   329
            status = PEP_UNKNOWN_DB_ERROR;
krista@2947
   330
    }
krista@2947
   331
    
krista@2947
   332
    sqlite3_reset(session->set_revoke_contact_as_notified);
krista@2947
   333
    return status;    
krista@2947
   334
}
krista@2947
   335
krista@4312
   336
// FIXME: fpr ownership
krista@2947
   337
PEP_STATUS receive_key_reset(PEP_SESSION session,
krista@2947
   338
                             message* reset_msg) {
krista@2947
   339
krista@4312
   340
    if (!session || !reset_msg || !reset_msg->_sender_fpr)
krista@2947
   341
        return PEP_ILLEGAL_VALUE;
krista@2947
   342
krista@4312
   343
    PEP_STATUS status = PEP_STATUS_OK;
krista@4312
   344
krista@4312
   345
    stringlist_t* keylist = NULL;
krista@4312
   346
    
krista@4312
   347
    char* sender_fpr = reset_msg->_sender_fpr;
krista@4312
   348
krista@4312
   349
    bool revoked = false;
krista@4312
   350
krista@4315
   351
    // Check to see if sender fpr is revoked already - if this was 
krista@4315
   352
    // from us, we won't have done it yet for obvious reasons (i.e. 
krista@4315
   353
    // we need to verify it's from us before we accept someone telling
krista@4315
   354
    // us to reset our private key), and if this was from someone else,
krista@4315
   355
    // a key reset message will be signed by their new key, because 
krista@4315
   356
    // we presume the old one was compromised (and we remove trust from 
krista@4315
   357
    // the replacement key until verified)
krista@4312
   358
    status = key_revoked(session, sender_fpr, &revoked); 
krista@4312
   359
    
krista@4312
   360
    if (status != PEP_STATUS_OK)
krista@4312
   361
        return status;
krista@4312
   362
krista@4312
   363
    // Bail if revoked
krista@4312
   364
    if (revoked) {
krista@4312
   365
        return PEP_ILLEGAL_VALUE; // could be an attack            
krista@4312
   366
    }
krista@4312
   367
    // Otherwise, bail
krista@4312
   368
    else {
krista@4312
   369
        bool mistrusted = false;
krista@4312
   370
        status = is_mistrusted_key(session, sender_fpr, &mistrusted);
krista@4312
   371
        
krista@4312
   372
        if (status != PEP_STATUS_OK)
krista@4312
   373
            return status;
krista@4312
   374
        
krista@4312
   375
        if (mistrusted)
krista@4312
   376
            return PEP_ILLEGAL_VALUE;
krista@4312
   377
    }
krista@4312
   378
krista@4312
   379
    
krista@4312
   380
    // Parse reset message
krista@4312
   381
    
krista@2947
   382
    pEp_identity* sender_id = reset_msg->from;
krista@4312
   383
                            
krista@2947
   384
    if (!sender_id)
krista@2947
   385
        return PEP_MALFORMED_KEY_RESET_MSG;
krista@4312
   386
krista@4312
   387
    if (is_me(session, sender_id)) {
krista@4312
   388
        // first off, we need to make sure we're up-to-date
krista@4312
   389
        status = myself(session, sender_id);        
krista@4312
   390
    }
krista@4312
   391
    else {    
krista@4312
   392
        status = update_identity(session, sender_id);
krista@4312
   393
        if (!sender_id->user_id)
krista@4312
   394
            return PEP_UNKNOWN_ERROR;
krista@4312
   395
    }
krista@4312
   396
    
krista@4312
   397
    bool sender_own_key = false;
krista@4315
   398
    bool from_me = is_me(session, sender_id);
krista@4312
   399
    
krista@4312
   400
    if (is_me(session, sender_id)) {
krista@4312
   401
        // Do own-reset-checks
krista@4312
   402
        status = is_own_key(session, sender_fpr, &sender_own_key);
krista@2947
   403
        
krista@4312
   404
        if (status != PEP_STATUS_OK)
krista@4312
   405
            return status;
krista@2947
   406
        
krista@4312
   407
        // Should we mistrust the sender_fpr here??
krista@4312
   408
        if (!sender_own_key) 
krista@4312
   409
            return PEP_ILLEGAL_VALUE; // actually, this is an attack                
krista@2947
   410
        
krista@4312
   411
        // Make sure it's a TRUSTED own key
krista@4312
   412
        char* keyholder = sender_id->fpr;
krista@4312
   413
        
krista@4312
   414
        sender_id->fpr = sender_fpr;                     
krista@4312
   415
        status = get_trust(session, sender_id);
krista@4312
   416
        sender_id->fpr = keyholder;
krista@4312
   417
            
krista@4312
   418
        if (sender_id->comm_type < PEP_ct_pEp)
krista@4312
   419
            return PEP_ILLEGAL_VALUE;
krista@4312
   420
    }
krista@4312
   421
        
krista@2947
   422
    status = PEP_STATUS_OK;
krista@2947
   423
    char* old_fpr = NULL;
krista@2947
   424
    char* new_fpr = NULL;
krista@2947
   425
    
krista@4312
   426
    size_t size = 0;
krista@4312
   427
    const char* payload = NULL;
krista@4312
   428
krista@4315
   429
    char* not_used_fpr = NULL;
krista@4312
   430
    status = base_extract_message(session,
krista@4312
   431
                                  reset_msg,
krista@4312
   432
                                  BASE_KEYRESET,
krista@4312
   433
                                  &size,
krista@4312
   434
                                  &payload,
krista@4315
   435
                                  &not_used_fpr);
krista@4312
   436
                                  
krista@4312
   437
    if (status != PEP_STATUS_OK)
krista@4312
   438
        return status;
krista@4312
   439
        
krista@4312
   440
    if (!payload || size == 0)
krista@4312
   441
        return PEP_MALFORMED_KEY_RESET_MSG;
krista@4312
   442
        
krista@4312
   443
    keyreset_command_list* resets = NULL; 
krista@4312
   444
    
krista@4312
   445
    status = PER_to_key_reset_commands(payload, size, &resets);
krista@4312
   446
krista@4312
   447
    if (status != PEP_STATUS_OK)
krista@4312
   448
        return status;
krista@4312
   449
        
krista@4312
   450
    if (!resets)
krista@4312
   451
        return PEP_MALFORMED_KEY_RESET_MSG;
krista@4312
   452
krista@4312
   453
    keyreset_command_list* curr_cl = resets;
krista@4315
   454
krista@4328
   455
    stringpair_list_t* rev_pairs = NULL;
krista@4328
   456
    
krista@4315
   457
    // Ok, go through the list of reset commands. Right now, this 
krista@4315
   458
    // is actually only one, but could be more later.
krista@4312
   459
    for ( ; curr_cl && curr_cl->command; curr_cl = curr_cl->next) {    
krista@4312
   460
        keyreset_command* curr_cmd = curr_cl->command;
krista@4312
   461
        if (!curr_cmd || !curr_cmd->ident || !curr_cmd->ident->fpr ||
krista@4312
   462
            !curr_cmd->ident->address) {
krista@4312
   463
            return PEP_MALFORMED_KEY_RESET_MSG;        
krista@4312
   464
        }
krista@4315
   465
        pEp_identity* curr_ident = curr_cmd->ident;
krista@4315
   466
        
krista@4315
   467
        old_fpr = curr_ident->fpr;
krista@4321
   468
        new_fpr = strdup(curr_cmd->new_key);
krista@4321
   469
        
krista@4321
   470
        bool is_old_own = false;
krista@4321
   471
        // if it's our key and the old one is revoked, we skip it.
krista@4321
   472
        // Sorry, them's the rules/
krista@4321
   473
        if (sender_own_key) {
krista@4321
   474
            status = is_own_key(session, old_fpr, &is_old_own);
krista@4321
   475
            if (is_old_own) {
krista@4321
   476
                bool old_revoked = false;
krista@4321
   477
                status = key_revoked(session, old_fpr, &old_revoked);
krista@4321
   478
                if (old_revoked)
krista@4321
   479
                    continue;
krista@4321
   480
            }
krista@4321
   481
        }
krista@4315
   482
krista@4312
   483
        // Make sure that this key is at least one we associate 
krista@4312
   484
        // with the sender. FIXME: check key election interaction
krista@4312
   485
        // N.B. If we ever allow ourselves to send resets to ourselves
krista@4312
   486
        // for not-own stuff, this will have to be revised
krista@4312
   487
        
krista@4312
   488
        status = find_keys(session, new_fpr, &keylist);
krista@4312
   489
        if (status != PEP_STATUS_OK)
krista@4312
   490
            goto pEp_free;
krista@4312
   491
        if (!keylist) {
krista@4312
   492
            status = PEP_MALFORMED_KEY_RESET_MSG;
krista@4312
   493
            goto pEp_free;
krista@4312
   494
        }
krista@4312
   495
        
krista@4312
   496
        // We need to update the identity to get the user_id
krista@4312
   497
        curr_ident->fpr = NULL; // ensure old_fpr is preserved
krista@4315
   498
        free(curr_ident->user_id);
krista@4315
   499
        curr_ident->user_id = NULL;
krista@4312
   500
        status = update_identity(session, curr_ident);
krista@4312
   501
        
krista@4315
   502
        // Ok, now check the old fpr to see if we have an entry for it
krista@4312
   503
        // temp fpr set for function call
krista@4315
   504
        curr_ident->fpr = old_fpr;
krista@4312
   505
        status = get_trust(session, curr_ident);
krista@4315
   506
        if (status != PEP_STATUS_OK)
krista@4315
   507
            return status;
krista@4312
   508
        
krista@4312
   509
        PEP_comm_type ct_result = curr_ident->comm_type;
krista@4312
   510
krista@4312
   511
        // Basically, see if fpr is even in the database
krista@4312
   512
        // for this user - we'll get PEP_ct_unknown if it isn't
krista@4315
   513
        if (ct_result == PEP_ct_unknown)
krista@4312
   514
            return PEP_KEY_NOT_RESET;
krista@4315
   515
        
krista@4315
   516
        // Alright, so we have a key to reset. Good.
krista@4315
   517
        
krista@4315
   518
        // If this is a non-own user, for NOW, we presume key reset 
krista@4315
   519
        // by email for non-own keys is ONLY in case of revoke-and-replace. 
krista@4315
   520
        // This means we have, at a *minimum*, an object that once 
krista@4315
   521
        // required the initial private key in order to replace that key 
krista@4315
   522
        // with another.
krista@4315
   523
        //
krista@4315
   524
        // The limitations on what this guarantees are known - this does 
krista@4315
   525
        // not prevent, for example, replay attacks from someone with 
krista@4315
   526
        // access to the original revocation cert are possible if they 
krista@4315
   527
        // get to us before we receive this object from the original sender.
krista@4315
   528
        // The best we can do in this case is to NOT trust the new key.
krista@4315
   529
        // It will be used by default, but if the original was trusted,
krista@4315
   530
        // the rating will visibly change for the sender, and even if it was 
krista@4315
   531
        // not, if we do use it, the sender can report unreadable mails to us 
krista@4315
   532
        // and detect it that way. FIXME: We may need to have some kind 
krista@4315
   533
        // of even alert the user when such a change occurs for their contacts
krista@4315
   534
        //
krista@4315
   535
        // If this is from US, we already made sure that the sender_fpr 
krista@4315
   536
        // was a valid own key, so we don't consider it here.
krista@4315
   537
        if (!from_me) {
krista@4315
   538
            revoked = false;
krista@4315
   539
            status = key_revoked(session, old_fpr, &revoked); 
krista@4315
   540
krista@4315
   541
            if (!revoked)
krista@4315
   542
                return PEP_KEY_NOT_RESET;            
krista@4315
   543
krista@4315
   544
            // Also don't let someone change the replacement fpr 
krista@4315
   545
            // if the replacement fpr was also revoked - we really need 
krista@4315
   546
            // to detect that something fishy is going on at this point
krista@4315
   547
            // FIXME: ensure that PEP_KEY_NOT_RESET responses to 
krista@4315
   548
            // automated key reset functions are propagated upward - 
krista@4315
   549
            // app should be made aware if someone is trying to reset someone 
krista@4315
   550
            // else's key and it's failing for some reason.
krista@4315
   551
            revoked = false;
krista@4315
   552
            status = key_revoked(session, new_fpr, &revoked); 
krista@4315
   553
krista@4315
   554
            if (revoked)
krista@4315
   555
                return PEP_KEY_NOT_RESET;                        
krista@4315
   556
        }
krista@4315
   557
        
krista@4312
   558
        // Hooray! We apparently now are dealing with keys 
krista@4315
   559
        // belonging to the user from a message at least marginally
krista@4315
   560
        // from the user
krista@4312
   561
        if (!sender_own_key) {
krista@4315
   562
            // Clear all info (ALSO REMOVES OLD KEY RIGHT NOW!!!)            
krista@4312
   563
            status = key_reset(session, old_fpr, curr_ident);
krista@4312
   564
            if (status != PEP_STATUS_OK)
krista@4312
   565
                return status;
krista@4312
   566
                                
krista@4312
   567
            // Make new key the default    
krista@4312
   568
            curr_ident->fpr = new_fpr;
krista@2947
   569
    
krista@4312
   570
            // This only sets as the default, does NOT TRUST IN ANY WAY
krista@4315
   571
            PEP_comm_type new_key_rating = PEP_ct_unknown;
krista@4315
   572
            
krista@4315
   573
            // No key is ever returned as "confirmed" from here - it's based on raw key
krista@4315
   574
            status = get_key_rating(session, new_fpr, &new_key_rating);
krista@4315
   575
            if (status != PEP_STATUS_OK)
krista@4315
   576
                return status;
krista@4315
   577
krista@4315
   578
            if (new_key_rating >= PEP_ct_strong_but_unconfirmed) {
krista@4315
   579
                bool is_pEp = false;
krista@4315
   580
                status = is_pEp_user(session, curr_ident, &is_pEp);
krista@4315
   581
                if (is_pEp)
krista@4315
   582
                    curr_ident->comm_type = PEP_ct_pEp_unconfirmed;
krista@4315
   583
                else    
krista@4315
   584
                    curr_ident->comm_type = new_key_rating & (~PEP_ct_confirmed);
krista@4316
   585
            }
krista@4316
   586
            else
krista@4316
   587
                curr_ident->comm_type = new_key_rating;
krista@4316
   588
                
krista@4312
   589
            status = set_identity(session, curr_ident);  
krista@4312
   590
            if (status != PEP_STATUS_OK)
krista@4312
   591
                goto pEp_free; 
krista@4312
   592
        }    
krista@4312
   593
        else {
krista@4312
   594
            // set new key as the default for this identity
krista@4312
   595
            // N.B. If for some reason this is only a pubkey,
krista@4312
   596
            // then so be it - but we need to double-check to 
krista@4312
   597
            // ensure that in this case, we end up with a private one,
krista@4312
   598
            // so talk to vb about this.
krista@4312
   599
            // Make new key the default    
krista@4322
   600
            
krista@4322
   601
            // This is REQUIRED for set_own_key (see doc)
krista@4322
   602
            curr_ident->fpr = NULL;
krista@4322
   603
            
krista@4312
   604
            status = set_own_key(session, curr_ident, new_fpr);
krista@2947
   605
            
krista@4312
   606
            if (status != PEP_STATUS_OK)
krista@4312
   607
                return status;
krista@4321
   608
            
krista@4321
   609
            status = myself(session, curr_ident);
krista@4321
   610
krista@4328
   611
            char* old_copy = NULL;
krista@4328
   612
            char* new_copy = NULL;
krista@4328
   613
            old_copy = strdup(old_fpr);
krista@4328
   614
            new_copy = strdup(new_fpr);
krista@4328
   615
            if (!old_copy || !new_copy)
krista@4328
   616
                return PEP_OUT_OF_MEMORY;
krista@4328
   617
krista@4328
   618
            stringpair_t* revp = new_stringpair(old_copy, new_copy);                
krista@4328
   619
            if (!rev_pairs) {
krista@4328
   620
                rev_pairs = new_stringpair_list(revp);
krista@4328
   621
                if (!rev_pairs)
krista@4328
   622
                    return PEP_OUT_OF_MEMORY;
krista@4328
   623
            }
krista@4328
   624
            else    
krista@4328
   625
                stringpair_list_add(rev_pairs, revp);
krista@4328
   626
                            
krista@4328
   627
        }    
krista@4321
   628
        
krista@4312
   629
        old_fpr = NULL;
krista@4321
   630
        free(new_fpr);
krista@4312
   631
        new_fpr = NULL;    
krista@2947
   632
    }
krista@2947
   633
krista@4328
   634
    // actually revoke
krista@4328
   635
    stringpair_list_t* curr_rev_pair = rev_pairs;
krista@4328
   636
    while (curr_rev_pair && curr_rev_pair->value) {
krista@4328
   637
        char* rev_key = curr_rev_pair->value->key;
krista@4328
   638
        char* new_key = curr_rev_pair->value->value;
krista@4328
   639
        if (EMPTYSTR(rev_key) || EMPTYSTR(new_key))
krista@4328
   640
            return PEP_UNKNOWN_ERROR;
krista@4328
   641
        bool revoked = false;
krista@4328
   642
        status = key_revoked(session, rev_key, &revoked);
krista@4328
   643
        if (!revoked) {
krista@4328
   644
            // key reset on old key
krista@4328
   645
            status = revoke_key(session, rev_key, NULL);
krista@4328
   646
krista@4328
   647
            if (status != PEP_STATUS_OK)
krista@4328
   648
                goto pEp_free;    
krista@4328
   649
        }
krista@4328
   650
        // N.B. This sort of sucks because we overwrite this every time.
krista@4328
   651
        // But this case is infrequent and we don't rely on the binding.
krista@4328
   652
krista@4328
   653
        if (status == PEP_STATUS_OK) 
krista@4328
   654
            status = set_revoked(session, rev_key, new_key, time(NULL));            
krista@4328
   655
krista@4328
   656
        if (status != PEP_STATUS_OK)
krista@4328
   657
            goto pEp_free;        
krista@4328
   658
        curr_rev_pair = curr_rev_pair->next;    
krista@4328
   659
    }
krista@4328
   660
krista@4328
   661
krista@2956
   662
pEp_free:    
krista@2947
   663
    free_stringlist(keylist);    
krista@4328
   664
    free_stringpair_list(rev_pairs);
krista@2947
   665
    free(old_fpr);
krista@2947
   666
    free(new_fpr);
krista@2947
   667
    return status;
krista@2947
   668
}
krista@2947
   669
krista@2947
   670
PEP_STATUS create_standalone_key_reset_message(PEP_SESSION session,
krista@2947
   671
                                               message** dst, 
krista@4312
   672
                                               pEp_identity* own_identity,
krista@2947
   673
                                               pEp_identity* recip,
krista@2947
   674
                                               const char* old_fpr,
krista@2947
   675
                                               const char* new_fpr) {
krista@2947
   676
                                                   
krista@4312
   677
    if (!dst || !own_identity || EMPTYSTR(own_identity->address) 
krista@4312
   678
             || !recip || EMPTYSTR(recip->user_id) 
krista@4312
   679
             || EMPTYSTR(recip->address))
krista@2947
   680
        return PEP_ILLEGAL_VALUE;
krista@2947
   681
krista@4312
   682
    if (EMPTYSTR(old_fpr) || EMPTYSTR(new_fpr))
krista@2947
   683
        return PEP_ILLEGAL_VALUE;
krista@2947
   684
        
krista@2947
   685
    *dst = NULL;
krista@2947
   686
    
krista@4312
   687
    message* reset_msg = NULL;
krista@4312
   688
    
krista@4312
   689
    PEP_STATUS status = _generate_keyreset_command_message(session, own_identity,
krista@4312
   690
                                                           recip,
krista@4312
   691
                                                           old_fpr, new_fpr, false,
krista@4312
   692
                                                           &reset_msg);
krista@4312
   693
                            
krista@2947
   694
    if (status != PEP_STATUS_OK)
krista@4312
   695
        goto pEp_free;
krista@2947
   696
    
krista@4312
   697
    if (!reset_msg)
krista@4312
   698
        return PEP_ILLEGAL_VALUE;
krista@4312
   699
                                                                         
krista@4312
   700
    if (!reset_msg->attachments)
krista@4312
   701
        return PEP_UNKNOWN_ERROR;
krista@2947
   702
    
krista@2947
   703
    message* output_msg = NULL;
krista@2947
   704
    
krista@4312
   705
    status = encrypt_message(session, reset_msg, NULL,
krista@2947
   706
                             &output_msg, PEP_enc_PGP_MIME,
krista@2947
   707
                             PEP_encrypt_flag_key_reset_only);
krista@2947
   708
krista@2947
   709
    if (status == PEP_STATUS_OK)
krista@2947
   710
        *dst = output_msg;
krista@2947
   711
        
krista@4312
   712
pEp_free:
krista@4312
   713
        
krista@4312
   714
    free_message(reset_msg);    
krista@2947
   715
    return status;
krista@2947
   716
}
krista@2947
   717
krista@2947
   718
PEP_STATUS send_key_reset_to_recents(PEP_SESSION session,
krista@4312
   719
                                     pEp_identity* from_ident,
krista@2947
   720
                                     const char* old_fpr, 
krista@2947
   721
                                     const char* new_fpr) {
krista@2947
   722
    assert(old_fpr);
krista@2947
   723
    assert(new_fpr);
krista@2947
   724
    assert(session);
krista@2956
   725
    assert(session->messageToSend);
krista@2947
   726
    
krista@2947
   727
    if (!session || !old_fpr || !new_fpr)
krista@2947
   728
        return PEP_ILLEGAL_VALUE;
krista@2947
   729
krista@2956
   730
    messageToSend_t send_cb = session->messageToSend;
krista@2947
   731
    if (!send_cb)
krista@2947
   732
        return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
krista@2947
   733
        
krista@2947
   734
    identity_list* recent_contacts = NULL;
krista@2947
   735
    message* reset_msg = NULL;
krista@2947
   736
krista@2947
   737
    PEP_STATUS status = get_last_contacted(session, &recent_contacts);
krista@2947
   738
    
krista@2947
   739
    if (status != PEP_STATUS_OK)
krista@2956
   740
        goto pEp_free;
krista@2947
   741
                    
krista@2947
   742
    identity_list* curr_id_ptr = recent_contacts;
krista@2947
   743
krista@2947
   744
    for (curr_id_ptr = recent_contacts; curr_id_ptr; curr_id_ptr = curr_id_ptr->next) {
krista@2947
   745
        pEp_identity* curr_id = curr_id_ptr->ident;
krista@2947
   746
        
krista@2947
   747
        if (!curr_id)
krista@2947
   748
            break;
krista@2947
   749
    
krista@2947
   750
        const char* user_id = curr_id->user_id;
krista@2947
   751
        
krista@2947
   752
        // Should be impossible, but?
krista@2947
   753
        if (!user_id)
krista@2947
   754
            continue;
krista@2947
   755
        
krista@2947
   756
        // Check if it's us - if so, pointless...
krista@2947
   757
        if (is_me(session, curr_id))
krista@2947
   758
            continue;
krista@2947
   759
            
krista@2947
   760
        // Check if they've already been told - this shouldn't be the case, but...
krista@2947
   761
        bool contacted = false;
krista@4312
   762
        status = has_key_reset_been_sent(session, from_ident->address, user_id, old_fpr, &contacted);
krista@2947
   763
        if (status != PEP_STATUS_OK)
krista@2956
   764
            goto pEp_free;
krista@2947
   765
    
krista@2947
   766
        if (contacted)
krista@2947
   767
            continue;
krista@2947
   768
            
krista@4312
   769
        // Make sure they've ever *contacted* this address    
krista@4312
   770
        bool in_contact_w_this_address = false;
krista@4315
   771
        status = has_partner_contacted_address(session, curr_id->user_id, from_ident->address,  
krista@4312
   772
                                               &in_contact_w_this_address);
krista@4312
   773
        
krista@4312
   774
        if (!in_contact_w_this_address)
krista@4312
   775
            continue;
krista@4312
   776
            
krista@2947
   777
        // if not, make em a message    
krista@2947
   778
        reset_msg = NULL;
krista@2947
   779
        
krista@2947
   780
        status = create_standalone_key_reset_message(session,
krista@2947
   781
                                                     &reset_msg,
krista@4312
   782
                                                     from_ident,
krista@2947
   783
                                                     curr_id,
krista@2947
   784
                                                     old_fpr,
krista@2947
   785
                                                     new_fpr);
krista@2947
   786
krista@2947
   787
        if (status == PEP_CANNOT_FIND_IDENTITY) { // this is ok, just means we never mailed them 
krista@2947
   788
            status = PEP_STATUS_OK;
krista@2947
   789
            continue; 
krista@2947
   790
        }
krista@2947
   791
            
krista@2947
   792
        if (status != PEP_STATUS_OK) {
krista@2947
   793
            free(reset_msg);
krista@2956
   794
            goto pEp_free;
krista@2947
   795
        }
krista@2947
   796
        
krista@2947
   797
        // insert into queue
krista@2956
   798
        status = send_cb(reset_msg);
krista@2947
   799
krista@2947
   800
        if (status != PEP_STATUS_OK) {
krista@2947
   801
            free(reset_msg);
krista@2956
   802
            goto pEp_free;            
krista@2947
   803
        }
krista@2947
   804
            
krista@2947
   805
        // Put into notified DB
krista@4312
   806
        status = set_reset_contact_notified(session, from_ident->address, old_fpr, user_id);
krista@2947
   807
        if (status != PEP_STATUS_OK)
krista@2956
   808
            goto pEp_free;            
krista@2947
   809
    }
krista@2947
   810
    
krista@2956
   811
pEp_free:
krista@2947
   812
    free_identity_list(recent_contacts);
krista@2947
   813
    return status;
krista@2947
   814
}
krista@2947
   815
krista@3495
   816
DYNAMIC_API PEP_STATUS key_reset_identity(
krista@3495
   817
        PEP_SESSION session,
krista@3503
   818
        pEp_identity* ident,
krista@3503
   819
        const char* fpr        
krista@3495
   820
    )
krista@3495
   821
{
krista@3503
   822
    if (!session || !ident || (ident && (EMPTYSTR(ident->user_id) || EMPTYSTR(ident->address))))
krista@3495
   823
        return PEP_ILLEGAL_VALUE;
krista@3495
   824
    
krista@4312
   825
    return key_reset(session, fpr, ident);    
krista@3495
   826
}
krista@3495
   827
krista@3495
   828
DYNAMIC_API PEP_STATUS key_reset_user(
krista@3495
   829
        PEP_SESSION session,
krista@3503
   830
        const char* user_id,
krista@3503
   831
        const char* fpr        
krista@3495
   832
    )
krista@3495
   833
{
krista@3503
   834
    if (!session || EMPTYSTR(user_id))
krista@3495
   835
        return PEP_ILLEGAL_VALUE;
krista@3495
   836
krista@3503
   837
    pEp_identity* input_ident = new_identity(NULL, NULL, user_id, NULL);
krista@3503
   838
    if (!input_ident)
krista@3503
   839
        return PEP_OUT_OF_MEMORY;
krista@3503
   840
        
krista@3503
   841
    if (is_me(session, input_ident) && EMPTYSTR(fpr))
krista@3503
   842
        return PEP_ILLEGAL_VALUE;
krista@3495
   843
        
krista@4312
   844
    PEP_STATUS status = key_reset(session, fpr, input_ident);
krista@3503
   845
    free_identity(input_ident);
krista@3503
   846
    return status;
krista@3503
   847
}
krista@3495
   848
krista@3503
   849
DYNAMIC_API PEP_STATUS key_reset_all_own_keys(PEP_SESSION session) {
krista@4312
   850
    return key_reset(session, NULL, NULL);
krista@4312
   851
}
krista@4312
   852
krista@4350
   853
static PEP_STATUS _dup_grouped_only(identity_list* idents, identity_list** filtered) {
krista@4350
   854
    if (!idents)
krista@4350
   855
        return PEP_STATUS_OK;
krista@4350
   856
        
krista@4350
   857
    identity_list* id_node;
krista@4350
   858
    pEp_identity* curr_ident = NULL;
krista@4350
   859
    
krista@4350
   860
    identity_list* ret_list = NULL;
krista@4350
   861
    identity_list** ret_list_pp = &ret_list;
krista@4350
   862
    
krista@4350
   863
    for (id_node = idents; id_node && id_node->ident; id_node = id_node->next) {
krista@4350
   864
        curr_ident = id_node->ident;
krista@4350
   865
        if (curr_ident->flags & PEP_idf_devicegroup) {
krista@4350
   866
            pEp_identity* new_ident = identity_dup(curr_ident);
krista@4350
   867
            if (!new_ident) {
krista@4350
   868
                free_identity_list(ret_list);
krista@4350
   869
                return PEP_OUT_OF_MEMORY;
krista@4350
   870
            }
krista@4350
   871
            identity_list* new_ident_il = new_identity_list(new_ident);
krista@4350
   872
            if (!new_ident_il) {
krista@4350
   873
                free(new_ident);
krista@4350
   874
                free_identity_list(ret_list);
krista@4350
   875
                return PEP_OUT_OF_MEMORY;
krista@4350
   876
            }
krista@4350
   877
                
krista@4350
   878
            *ret_list_pp = new_ident_il;
krista@4350
   879
            ret_list_pp = &(new_ident_il->next);                
krista@4350
   880
        }
krista@4350
   881
    }
krista@4350
   882
    *filtered = ret_list;
krista@4350
   883
    return PEP_STATUS_OK;    
krista@4344
   884
}
krista@4312
   885
krista@4312
   886
static PEP_STATUS _key_reset_device_group_for_shared_key(PEP_SESSION session, 
krista@4312
   887
                                                         identity_list* key_idents, 
krista@4350
   888
                                                         const char* old_key,
krista@4350
   889
                                                         bool grouped_only) {
krista@4312
   890
    assert(session);
krista@4312
   891
    assert(key_idents);
krista@4312
   892
    assert(old_key);
krista@4312
   893
    
krista@4312
   894
    if (!session || !key_idents || EMPTYSTR(old_key))
krista@4312
   895
        return PEP_ILLEGAL_VALUE;
krista@4312
   896
        
krista@4312
   897
    messageToSend_t send_cb = session->messageToSend;
krista@4312
   898
    if (!send_cb)
krista@4312
   899
        return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
krista@4312
   900
        
krista@4312
   901
    PEP_STATUS status = PEP_STATUS_OK;
krista@4312
   902
        
krista@4350
   903
    // if we only want grouped identities, we do this:
krista@4350
   904
    if (grouped_only) {
krista@4350
   905
        identity_list* new_list = NULL;        
krista@4350
   906
        status = _dup_grouped_only(key_idents, &new_list);
krista@4350
   907
        if (status != PEP_STATUS_OK)
krista@4350
   908
            return status;
krista@4350
   909
        key_idents = new_list; // local var change, won't impact caller    
krista@4350
   910
    }
krista@4350
   911
    
krista@4350
   912
    if (!key_idents)
krista@4350
   913
        return PEP_STATUS_OK;
krista@4350
   914
        
krista@4312
   915
    // each of these has the same key and needs a new one.
krista@4312
   916
    identity_list* curr_ident;
krista@4312
   917
    for (curr_ident = key_idents; curr_ident && curr_ident->ident; curr_ident = curr_ident->next) {
krista@4329
   918
        pEp_identity* ident = curr_ident->ident;
krista@4329
   919
        free(ident->fpr);
krista@4329
   920
        ident->fpr = NULL;
krista@4334
   921
        status = _generate_keypair(session, ident, true);
krista@4329
   922
        if (status != PEP_STATUS_OK)
krista@4329
   923
            return status;            
krista@4312
   924
    }
krista@4312
   925
        
krista@4312
   926
    // Ok, everyone's got a new keypair. Hoorah! 
krista@4312
   927
    // generate, sign, and push messages into queue
krista@4327
   928
    message* outmsg = NULL;
krista@4327
   929
    status = _generate_own_commandlist_msg(session,
krista@4327
   930
                                           key_idents,
krista@4327
   931
                                           old_key,
krista@4327
   932
                                           &outmsg);
krista@4329
   933
                                           
krista@4329
   934
    // Following will only be true if some idents were grouped,
krista@4329
   935
    // and will only include grouped idents!                                       
krista@4329
   936
    if (outmsg) {    
krista@4329
   937
        message* enc_msg = NULL;
krista@4329
   938
        
krista@4329
   939
        // encrypt this baby and get out
krista@4329
   940
        // extra keys???
krista@4329
   941
        status = encrypt_message(session, outmsg, NULL, &enc_msg, PEP_enc_PGP_MIME, PEP_encrypt_flag_key_reset_only);
krista@4329
   942
        
krista@4329
   943
        if (status != PEP_STATUS_OK) {
krista@4329
   944
            goto pEp_free;
krista@4329
   945
        }
krista@4329
   946
krista@4329
   947
        // insert into queue
krista@4329
   948
        status = send_cb(enc_msg);
krista@4329
   949
krista@4329
   950
        if (status != PEP_STATUS_OK) {
krista@4329
   951
            free(enc_msg);
krista@4329
   952
            goto pEp_free;            
krista@4329
   953
        }                         
krista@4327
   954
    }
krista@4312
   955
    
krista@4312
   956
    // Ok, we've signed everything we need to with the old key,
krista@4312
   957
    // Revoke that baby.
krista@4312
   958
    status = revoke_key(session, old_key, NULL);
krista@4312
   959
krista@4321
   960
    if (status != PEP_STATUS_OK)
krista@4312
   961
        goto pEp_free;
krista@4312
   962
        
krista@4312
   963
    for (curr_ident = key_idents; curr_ident && curr_ident->ident; curr_ident = curr_ident->next) {
krista@4312
   964
        if (curr_ident->ident->flags & PEP_idf_devicegroup) {
krista@4312
   965
            pEp_identity* ident = curr_ident->ident;
krista@4312
   966
            
krista@4328
   967
            // set own key, you fool.
krista@4328
   968
            // Grab ownership first.
krista@4328
   969
            char* new_key = ident->fpr;
krista@4328
   970
            ident->fpr = NULL;
krista@4328
   971
            status = set_own_key(session, ident, new_key);
krista@4328
   972
            if (status != PEP_STATUS_OK) {
krista@4328
   973
                // scream loudly and cry, then hang head in shame
krista@4328
   974
                return status;
krista@4328
   975
            }
krista@4328
   976
            free(ident->fpr);
krista@4328
   977
            // release ownership to the struct again
krista@4328
   978
            ident->fpr = new_key;
krista@4328
   979
                
krista@4312
   980
            // N.B. This sort of sucks because we overwrite this every time.
krista@4312
   981
            // But this case is infrequent and we don't rely on the binding.
krista@4312
   982
            if (status == PEP_STATUS_OK) 
krista@4328
   983
                status = set_revoked(session, old_key, new_key, time(NULL));            
krista@4312
   984
krista@4321
   985
            if (status != PEP_STATUS_OK)
krista@4312
   986
                goto pEp_free;
krista@4312
   987
                
krista@4312
   988
            pEp_identity* tmp_ident = identity_dup(ident);
krista@4312
   989
            if (!tmp_ident) {
krista@4312
   990
                status = PEP_OUT_OF_MEMORY;
krista@4312
   991
                goto pEp_free;
krista@4312
   992
            }    
krista@4312
   993
            free(tmp_ident->fpr);    
krista@4312
   994
            
krista@4312
   995
            // for all active communication partners:
krista@4312
   996
            //      active_send revocation            
krista@4312
   997
            tmp_ident->fpr = strdup(old_key); // freed in free_identity
krista@4312
   998
            if (status == PEP_STATUS_OK)
krista@4312
   999
                status = send_key_reset_to_recents(session, tmp_ident, old_key, ident->fpr);        
krista@4312
  1000
            free_identity(tmp_ident);
krista@4312
  1001
        }    
krista@4312
  1002
    }    
krista@4327
  1003
    
krista@4327
  1004
    if (status == PEP_STATUS_OK)
krista@4327
  1005
        // cascade that mistrust for anyone using this key
krista@4327
  1006
        status = mark_as_compromised(session, old_key);
krista@4327
  1007
        
krista@4327
  1008
    if (status == PEP_STATUS_OK)
krista@4327
  1009
        status = remove_fpr_as_default(session, old_key);
krista@4327
  1010
    if (status == PEP_STATUS_OK)
krista@4327
  1011
        status = add_mistrusted_key(session, old_key);
krista@4327
  1012
    
krista@4312
  1013
pEp_free:
krista@4312
  1014
    return status;
krista@3495
  1015
}
krista@3495
  1016
krista@4350
  1017
krista@4350
  1018
DYNAMIC_API PEP_STATUS key_reset_own_grouped_keys(PEP_SESSION session) {
krista@4350
  1019
    assert(session);
krista@4350
  1020
    
krista@4350
  1021
    if (!session)
krista@4350
  1022
        return PEP_ILLEGAL_VALUE;
krista@4350
  1023
krista@4350
  1024
    stringlist_t* keys = NULL;
krista@4350
  1025
    char* user_id = NULL;    
krista@4350
  1026
    PEP_STATUS status = get_default_own_userid(session, &user_id);
krista@4350
  1027
krista@4350
  1028
    if (status != PEP_STATUS_OK || !user_id)
krista@4350
  1029
        goto pEp_free;                    
krista@4350
  1030
krista@4350
  1031
    
krista@4350
  1032
    status = get_all_keys_for_user(session, user_id, &keys);
krista@4350
  1033
krista@4350
  1034
    // TODO: free
krista@4350
  1035
    if (status == PEP_STATUS_OK) {
krista@4350
  1036
        stringlist_t* curr_key;
krista@4350
  1037
        
krista@4350
  1038
        for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
krista@4350
  1039
            identity_list* key_idents = NULL;
krista@4350
  1040
            const char* own_key = curr_key->value;
krista@4350
  1041
            status = get_identities_by_main_key_id(session, own_key, &key_idents);
krista@4350
  1042
            
krista@4356
  1043
            if (status == PEP_CANNOT_FIND_IDENTITY) {
krista@4356
  1044
                status = PEP_STATUS_OK;
krista@4353
  1045
                continue;
krista@4356
  1046
            }    
krista@4353
  1047
            else if (status == PEP_STATUS_OK)    
krista@4353
  1048
                status = _key_reset_device_group_for_shared_key(session, key_idents, own_key, true);            
krista@4353
  1049
            else 
krista@4350
  1050
                goto pEp_free;
krista@4350
  1051
            
krista@4350
  1052
            free_identity_list(key_idents);    
krista@4350
  1053
        }
krista@4350
  1054
    }
krista@4350
  1055
    goto pEp_free;
krista@4350
  1056
krista@4350
  1057
pEp_free:
krista@4350
  1058
    free_stringlist(keys);
krista@4350
  1059
    free(user_id);
krista@4350
  1060
    return status;
krista@4350
  1061
}
krista@4350
  1062
krista@3495
  1063
// Notes to integrate into header:
krista@3495
  1064
// IF there is an ident, it must have a user_id.
krista@3495
  1065
PEP_STATUS key_reset(
krista@2947
  1066
        PEP_SESSION session,
krista@2947
  1067
        const char* key_id,
krista@4312
  1068
        pEp_identity* ident
krista@2947
  1069
    )
krista@2947
  1070
{
krista@3495
  1071
    if (!session || (ident && EMPTYSTR(ident->user_id)))
krista@2947
  1072
        return PEP_ILLEGAL_VALUE;
krista@2947
  1073
        
krista@2947
  1074
    PEP_STATUS status = PEP_STATUS_OK;
krista@2947
  1075
        
krista@2947
  1076
    char* fpr_copy = NULL;
krista@2947
  1077
    char* own_id = NULL;
krista@3495
  1078
    char* user_id = NULL;
krista@2947
  1079
    char* new_key = NULL;
krista@3495
  1080
    pEp_identity* tmp_ident = NULL;
krista@2947
  1081
    identity_list* key_idents = NULL;
krista@2947
  1082
    stringlist_t* keys = NULL;
krista@2947
  1083
    
krista@2947
  1084
    if (!EMPTYSTR(key_id)) {
krista@2947
  1085
        fpr_copy = strdup(key_id);
krista@2947
  1086
        if (!fpr_copy)
krista@2947
  1087
            return PEP_OUT_OF_MEMORY;
krista@2947
  1088
    }
krista@3495
  1089
krista@3495
  1090
    // This is true when we don't have a user_id and address and the fpr isn't specified
krista@3495
  1091
    bool reset_all_for_user = !fpr_copy && (!ident || EMPTYSTR(ident->address));
krista@3495
  1092
krista@3495
  1093
    // FIXME: does this need to be done everywhere?> I think not.
krista@3495
  1094
    if (ident) {
krista@3495
  1095
        user_id = strdup(ident->user_id);
krista@3495
  1096
        if (!user_id) {
krista@3495
  1097
            status = PEP_OUT_OF_MEMORY;
krista@2956
  1098
            goto pEp_free;
krista@3495
  1099
        }
krista@3495
  1100
    }
krista@3495
  1101
    else {
krista@3495
  1102
        status = get_default_own_userid(session, &user_id);
krista@3495
  1103
        if (status != PEP_STATUS_OK || !user_id)
krista@3495
  1104
            goto pEp_free;                    
krista@3495
  1105
    }
krista@3495
  1106
    
krista@3495
  1107
    // FIXME: Make sure this can't result in a double-free in recursive calls
krista@3495
  1108
    tmp_ident = (ident ? identity_dup(ident) : new_identity(NULL, NULL, user_id, NULL));
krista@3495
  1109
    
krista@3495
  1110
    if (reset_all_for_user) {
krista@3495
  1111
        status = get_all_keys_for_user(session, user_id, &keys);
krista@3495
  1112
        // TODO: free
krista@3495
  1113
        if (status == PEP_STATUS_OK) {
krista@3495
  1114
            stringlist_t* curr_key;
krista@2947
  1115
            
krista@3495
  1116
            for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
krista@3495
  1117
                // FIXME: Is the ident really necessary?
krista@4312
  1118
                status = key_reset(session, curr_key->value, tmp_ident);
krista@4316
  1119
                if (status != PEP_STATUS_OK && status != PEP_CANNOT_FIND_IDENTITY)
krista@3495
  1120
                    break;
krista@4316
  1121
                else 
krista@4316
  1122
                    status = PEP_STATUS_OK;
krista@2947
  1123
            }
krista@2947
  1124
        }
krista@3495
  1125
        goto pEp_free;
krista@3495
  1126
    }                   
krista@3495
  1127
    else {
krista@3495
  1128
        // tmp_ident => tmp_ident->user_id (was checked)
krista@3495
  1129
        //
krista@3495
  1130
        // !(EMPTYSTR(fpr) && (!tmp_ident || EMPTYSTR(tmp_ident->address)))
krista@3495
  1131
        // => fpr || (tmp_ident && tmp_ident->address)
krista@3495
  1132
        //
krista@3495
  1133
        // so: We have an fpr or we have an ident with user_id and address
krista@3495
  1134
        //     or both
krista@3495
  1135
        if (!fpr_copy) {
krista@3495
  1136
            // We are guaranteed to have an ident w/ id + addr here.
krista@3495
  1137
            // Get the default key.
krista@3495
  1138
            pEp_identity* stored_ident = NULL;
krista@3495
  1139
            status = get_identity(session, tmp_ident->address, 
krista@3495
  1140
                                  tmp_ident->user_id, &stored_ident);
krista@3495
  1141
krista@3495
  1142
            // FIXME FIXME FIXME
krista@3495
  1143
            if (status == PEP_STATUS_OK) {
krista@3495
  1144
                // transfer ownership
krista@3495
  1145
                fpr_copy = stored_ident->fpr;
krista@3495
  1146
                stored_ident->fpr = NULL;
krista@3495
  1147
                free_identity(stored_ident);                
krista@3495
  1148
            }
krista@3174
  1149
            
krista@3495
  1150
            if (!fpr_copy || status == PEP_CANNOT_FIND_IDENTITY) {
krista@3495
  1151
                // There's no identity default. Try resetting user default
krista@3495
  1152
                status = get_user_default_key(session, tmp_ident->user_id, &fpr_copy);
krista@3495
  1153
            }            
krista@4117
  1154
                        
krista@3495
  1155
            if (!fpr_copy || status != PEP_STATUS_OK) // No default to free. We're done here.
krista@3495
  1156
                goto pEp_free;            
krista@3495
  1157
        }
krista@3495
  1158
        
krista@3495
  1159
        // Ok - now we have at least an ident with user_id and an fpr.
krista@3495
  1160
        // Now it matters if we're talking about ourselves or a partner.
krista@3495
  1161
        bool is_own_private = false;
krista@3495
  1162
        if (is_me(session, tmp_ident)) {
krista@3495
  1163
            bool own_key = false;            
krista@3495
  1164
            status = is_own_key(session, fpr_copy, &own_key);
krista@3495
  1165
krista@3495
  1166
            if (status != PEP_STATUS_OK)
krista@3495
  1167
                goto pEp_free;
krista@3495
  1168
            if (!own_key) {
krista@3495
  1169
                status = PEP_ILLEGAL_VALUE;
krista@3495
  1170
                goto pEp_free;
krista@3495
  1171
            }
krista@3495
  1172
krista@3495
  1173
            status = contains_priv_key(session, fpr_copy, &is_own_private);
krista@3507
  1174
            if (status != PEP_STATUS_OK && status != PEP_KEY_NOT_FOUND)
krista@3495
  1175
                goto pEp_free;
krista@3495
  1176
        }
krista@3495
  1177
        
krista@3495
  1178
        // Up to this point, we haven't cared about whether or not we 
krista@3495
  1179
        // had a full identity. Now we have to deal with that in the 
krista@3495
  1180
        // case of own identities with private keys.
krista@3495
  1181
        
krista@3495
  1182
        if (is_own_private) {
krista@3495
  1183
            
krista@4320
  1184
            // This is now the "is_own" base case - we don't do this 
krista@4320
  1185
            // per-identity, because all identities using this key will 
krista@4320
  1186
            // need new ones. That said, this is really only a problem 
krista@4320
  1187
            // with manual key management, something which we only support 
krista@4320
  1188
            // to a limited extent in any event.
krista@4320
  1189
            
krista@4320
  1190
            bool is_grouped = false;
krista@4320
  1191
            status = deviceGrouped(session, &is_grouped);
krista@4320
  1192
             
krista@4320
  1193
            // Regardless of the single identity this is for, for own keys, we do this 
krista@4320
  1194
            // for all keys associated with the identity.
krista@4320
  1195
            status = get_identities_by_main_key_id(session, fpr_copy, &key_idents);
krista@4320
  1196
            
krista@4320
  1197
            if (status != PEP_CANNOT_FIND_IDENTITY) {
krista@4320
  1198
                if (is_grouped) 
krista@4350
  1199
                    status = _key_reset_device_group_for_shared_key(session, key_idents, fpr_copy, false);
krista@4320
  1200
                else if (status == PEP_STATUS_OK) {
krista@4320
  1201
                    // now have ident list, or should
krista@4320
  1202
                    identity_list* curr_ident;
krista@3495
  1203
krista@4320
  1204
                    for (curr_ident = key_idents; curr_ident && curr_ident->ident; 
krista@4320
  1205
                                                    curr_ident = curr_ident->next) {
krista@4320
  1206
                        
krista@4320
  1207
                        // Do the full reset on this identity        
krista@4320
  1208
                        // Base case for is_own_private starts here
krista@4320
  1209
                        // tmp ident is an actual identity now (not just a skeleton?)
krista@4320
  1210
                        status = revoke_key(session, fpr_copy, NULL);
krista@4320
  1211
                        
krista@4320
  1212
                        // If we have a full identity, we have some cleanup and generation tasks here
krista@4320
  1213
                        if (!EMPTYSTR(tmp_ident->address)) {
krista@4320
  1214
                            // generate new key
krista@4320
  1215
                            if (status == PEP_STATUS_OK) {
krista@4320
  1216
                                tmp_ident->fpr = NULL;
krista@4320
  1217
                                status = myself(session, tmp_ident);
krista@4312
  1218
                            }
krista@4320
  1219
                            if (status == PEP_STATUS_OK && tmp_ident->fpr && strcmp(fpr_copy, tmp_ident->fpr) != 0)
krista@4320
  1220
                                new_key = strdup(tmp_ident->fpr);
krista@4320
  1221
                            // Error handling?    
krista@4320
  1222
                            
krista@4320
  1223
                            // mistrust fpr from trust
krista@4320
  1224
                            tmp_ident->fpr = fpr_copy;
krista@4320
  1225
                                                            
krista@4320
  1226
                            tmp_ident->comm_type = PEP_ct_mistrusted;
krista@4320
  1227
                            status = set_trust(session, tmp_ident);
krista@4320
  1228
                            tmp_ident->fpr = NULL;
krista@4320
  1229
                            
krista@4320
  1230
                            // Done with old use of ident.
krista@4320
  1231
                            if (status == PEP_STATUS_OK) {
krista@4320
  1232
                                // Update fpr for outgoing
krista@4320
  1233
                                status = myself(session, tmp_ident);
krista@4320
  1234
                            }
krista@4320
  1235
                        }    
krista@4320
  1236
                        
krista@4320
  1237
                        if (status == PEP_STATUS_OK)
krista@4320
  1238
                            // cascade that mistrust for anyone using this key
krista@4320
  1239
                            status = mark_as_compromised(session, fpr_copy);
krista@4320
  1240
                            
krista@4320
  1241
                        if (status == PEP_STATUS_OK)
krista@4320
  1242
                            status = remove_fpr_as_default(session, fpr_copy);
krista@4320
  1243
                        if (status == PEP_STATUS_OK)
krista@4320
  1244
                            status = add_mistrusted_key(session, fpr_copy);
krista@4320
  1245
krista@4320
  1246
                        // If there's a new key, do the DB linkage with the revoked one, and 
krista@4320
  1247
                        // send the key reset mail opportunistically to recently contacted
krista@4320
  1248
                        // partners
krista@4320
  1249
                        if (new_key) {
krista@4320
  1250
                            // add to revocation list 
krista@4320
  1251
                            if (status == PEP_STATUS_OK) 
krista@4320
  1252
                                status = set_revoked(session, fpr_copy, new_key, time(NULL));            
krista@4320
  1253
                            // for all active communication partners:
krista@4320
  1254
                            //      active_send revocation
krista@4320
  1255
                            
krista@4320
  1256
                            tmp_ident->fpr = fpr_copy;
krista@4320
  1257
                            if (status == PEP_STATUS_OK)
krista@4320
  1258
                                status = send_key_reset_to_recents(session, tmp_ident, fpr_copy, new_key);        
krista@4320
  1259
                            tmp_ident->fpr = NULL;    
krista@4320
  1260
                        }                    
krista@4320
  1261
                        // Ident list gets freed below, do not free here!
krista@2947
  1262
                    }
krista@4316
  1263
                }
krista@4320
  1264
                // Ok, we've either now reset for each own identity with this key, or 
krista@4320
  1265
                // we got an error and want to bail anyway.
krista@4320
  1266
                goto pEp_free;
krista@2947
  1267
            }
krista@4320
  1268
            else 
krista@4320
  1269
                return PEP_CANNOT_FIND_IDENTITY;
krista@3495
  1270
        } // end is_own_private
krista@3495
  1271
        else {
krista@4120
  1272
            // if it's mistrusted, make it not be so.
krista@4120
  1273
            bool mistrusted_key = false;
krista@4120
  1274
            is_mistrusted_key(session, fpr_copy, &mistrusted_key);
krista@4120
  1275
krista@4120
  1276
            if (mistrusted_key)
krista@4120
  1277
                delete_mistrusted_key(session, fpr_copy);
krista@4120
  1278
            
krista@4121
  1279
            if (tmp_ident->user_id)
krista@4121
  1280
                status = clear_trust_info(session, tmp_ident->user_id, fpr_copy);
krista@4121
  1281
krista@3495
  1282
            // This is a public key (or a private key that isn't ours, which means
krista@3495
  1283
            // we want it gone anyway)
krista@3495
  1284
            //
krista@3495
  1285
            // Delete this key from the keyring.
krista@4245
  1286
            // FIXME: when key election disappears, so should this!
krista@3495
  1287
            status = delete_keypair(session, fpr_copy);
krista@2947
  1288
        }
krista@3495
  1289
krista@3495
  1290
        // REGARDLESS OF WHO OWNS THE KEY, WE NOW NEED TO REMOVE IT AS A DEFAULT.
krista@3495
  1291
        PEP_STATUS cached_status = status;
krista@3495
  1292
        // remove fpr from all identities
krista@3495
  1293
        // remove fpr from all users
krista@3495
  1294
        status = remove_fpr_as_default(session, fpr_copy);
krista@3495
  1295
        // delete key from DB - this does NOT touch the keyring!
krista@3495
  1296
        // Note: for own priv keys, we cannot do this. But we'll never encrypt to/from it.
krista@3495
  1297
        if (status == PEP_STATUS_OK && !is_own_private) {
krista@3495
  1298
            status = remove_key(session, fpr_copy);
krista@2947
  1299
        }
krista@3495
  1300
        if (status == PEP_STATUS_OK)
krista@3495
  1301
            status = cached_status;
krista@3495
  1302
    }           
krista@3495
  1303
        
krista@2956
  1304
pEp_free:
krista@3495
  1305
    if (!ident)
krista@3495
  1306
        free_identity(tmp_ident);
krista@2947
  1307
    free(fpr_copy);
krista@2947
  1308
    free(own_id);
krista@2947
  1309
    free_identity_list(key_idents);
krista@2947
  1310
    free_stringlist(keys);
krista@2947
  1311
    free(new_key);    
krista@2947
  1312
    return status;
krista@2947
  1313
}
krista@4245
  1314
vb@4269
  1315
Distribution_t *Distribution_from_keyreset_command_list(
vb@4269
  1316
        const keyreset_command_list *command_list,
vb@4269
  1317
        Distribution_t *dist
vb@4269
  1318
    )
vb@4256
  1319
{
vb@4269
  1320
    bool allocated = !dist;
vb@4257
  1321
vb@4269
  1322
    assert(command_list);
vb@4269
  1323
    if (!command_list)
vb@4269
  1324
        return NULL;
vb@4257
  1325
vb@4269
  1326
    if (allocated)
vb@4269
  1327
        dist = (Distribution_t *) calloc(1, sizeof(Distribution_t));
vb@4261
  1328
vb@4261
  1329
    assert(dist);
vb@4261
  1330
    if (!dist)
vb@4261
  1331
        goto enomem;
vb@4261
  1332
vb@4261
  1333
    dist->present = Distribution_PR_keyreset;
vb@4261
  1334
    dist->choice.keyreset.present = KeyReset_PR_commands;
vb@4261
  1335
vb@4275
  1336
    long *major = malloc(sizeof(long));
vb@4275
  1337
    assert(major);
vb@4275
  1338
    if (!major)
vb@4275
  1339
        goto enomem;
vb@4275
  1340
    *major = KEY_RESET_MAJOR_VERSION;
vb@4275
  1341
    dist->choice.keyreset.choice.commands.version.major = major;
vb@4275
  1342
vb@4275
  1343
    long *minor = malloc(sizeof(long));
vb@4275
  1344
    assert(minor);
vb@4275
  1345
    if (!minor)
vb@4275
  1346
        goto enomem;
vb@4275
  1347
    *minor = KEY_RESET_MINOR_VERSION;
vb@4275
  1348
    dist->choice.keyreset.choice.commands.version.minor = minor;
vb@4275
  1349
vb@4257
  1350
    for (const keyreset_command_list *cl = command_list; cl && cl->command; cl = cl->next) {
vb@4260
  1351
        Command_t *c = (Command_t *) calloc(1, sizeof(Command_t));
vb@4257
  1352
        assert(c);
vb@4257
  1353
        if (!c)
vb@4257
  1354
            goto enomem;
vb@4257
  1355
vb@4257
  1356
        if (!Identity_from_Struct(cl->command->ident, &c->ident)) {
vb@4257
  1357
            free(c);
vb@4257
  1358
            goto enomem;
vb@4257
  1359
        }
vb@4257
  1360
vb@4257
  1361
        if (OCTET_STRING_fromString(&c->newkey, cl->command->new_key)) {
vb@4261
  1362
            ASN_STRUCT_FREE(asn_DEF_Command, c);
vb@4257
  1363
            goto enomem;
vb@4257
  1364
        }
vb@4261
  1365
vb@4261
  1366
        if (ASN_SEQUENCE_ADD(&dist->choice.keyreset.choice.commands.commandlist, c)) {
vb@4261
  1367
            ASN_STRUCT_FREE(asn_DEF_Command, c);
vb@4261
  1368
            goto enomem;
vb@4261
  1369
        }
vb@4257
  1370
    }
vb@4257
  1371
vb@4269
  1372
    return dist;
vb@4269
  1373
vb@4269
  1374
enomem:
vb@4269
  1375
    ASN_STRUCT_FREE(asn_DEF_Distribution, dist);
vb@4269
  1376
    return NULL;
vb@4269
  1377
}
vb@4269
  1378
krista@4312
  1379
vb@4269
  1380
PEP_STATUS key_reset_commands_to_PER(const keyreset_command_list *command_list, char **cmds, size_t *size)
vb@4269
  1381
{
vb@4269
  1382
    PEP_STATUS status = PEP_STATUS_OK;
vb@4269
  1383
vb@4269
  1384
    assert(command_list && cmds);
vb@4269
  1385
    if (!(command_list && cmds))
vb@4269
  1386
        return PEP_ILLEGAL_VALUE;
vb@4269
  1387
vb@4269
  1388
    *cmds = NULL;
vb@4269
  1389
    *size = 0;
vb@4269
  1390
vb@4271
  1391
    // convert from pEp engine struct
vb@4269
  1392
vb@4269
  1393
    Distribution_t *dist = Distribution_from_keyreset_command_list(command_list, NULL);
vb@4269
  1394
    assert(dist);
vb@4269
  1395
    if (!dist)
vb@4269
  1396
        goto enomem;
vb@4269
  1397
vb@4261
  1398
    // encode
vb@4261
  1399
vb@4261
  1400
    char *_cmds;
vb@4261
  1401
    size_t _size;
vb@4261
  1402
    status = encode_Distribution_message(dist, &_cmds, &_size);
vb@4261
  1403
    if (status)
vb@4261
  1404
        goto the_end;
vb@4261
  1405
vb@4266
  1406
    // return result
vb@4266
  1407
vb@4261
  1408
    *cmds = _cmds;
vb@4261
  1409
    *size = _size;
vb@4261
  1410
    goto the_end;
vb@4261
  1411
vb@4257
  1412
enomem:
vb@4257
  1413
    status = PEP_OUT_OF_MEMORY;
vb@4257
  1414
vb@4257
  1415
the_end:
vb@4261
  1416
    ASN_STRUCT_FREE(asn_DEF_Distribution, dist);
vb@4257
  1417
    return status;
vb@4257
  1418
}
vb@4257
  1419
vb@4269
  1420
keyreset_command_list * Distribution_to_keyreset_command_list(
vb@4269
  1421
        Distribution_t *dist,
vb@4269
  1422
        keyreset_command_list *command_list
vb@4269
  1423
    )
vb@4269
  1424
{
vb@4269
  1425
    bool allocated = !command_list;
vb@4269
  1426
vb@4269
  1427
    assert(dist);
vb@4269
  1428
    if (!dist)
vb@4269
  1429
        return NULL;
vb@4269
  1430
vb@4269
  1431
    if (allocated)
vb@4269
  1432
        command_list = new_keyreset_command_list(NULL);
vb@4269
  1433
    if (!command_list)
vb@4269
  1434
        goto enomem;
vb@4269
  1435
vb@4269
  1436
    struct Commands__commandlist *cl = &dist->choice.keyreset.choice.commands.commandlist;
vb@4269
  1437
    keyreset_command_list *_result = command_list;
vb@4269
  1438
    for (int i=0; i<cl->list.count; i++) {
vb@4269
  1439
        pEp_identity *ident = Identity_to_Struct(&cl->list.array[i]->ident, NULL);
vb@4269
  1440
        if (!ident)
vb@4269
  1441
            goto enomem;
vb@4269
  1442
vb@4269
  1443
        const char *new_key = (const char *) cl->list.array[i]->newkey.buf;
vb@4269
  1444
vb@4269
  1445
        keyreset_command *command = new_keyreset_command(ident, new_key);
vb@4269
  1446
        if (!command) {
vb@4269
  1447
            free_identity(ident);
vb@4269
  1448
            goto enomem;
vb@4269
  1449
        }
vb@4269
  1450
vb@4269
  1451
        _result = keyreset_command_list_add(_result, command);
vb@4269
  1452
        free_identity(ident);
vb@4269
  1453
        if (!_result)
vb@4269
  1454
            goto enomem;
vb@4269
  1455
    }
vb@4269
  1456
vb@4269
  1457
    return command_list;
vb@4269
  1458
vb@4269
  1459
enomem:
vb@4269
  1460
    if (allocated)
vb@4269
  1461
        free_keyreset_command_list(command_list);
vb@4269
  1462
    return NULL;
vb@4269
  1463
}
vb@4269
  1464
vb@4261
  1465
PEP_STATUS PER_to_key_reset_commands(const char *cmds, size_t size, keyreset_command_list **command_list)
vb@4257
  1466
{
vb@4257
  1467
    assert(command_list && cmds);
vb@4257
  1468
    if (!(command_list && cmds))
vb@4256
  1469
        return PEP_ILLEGAL_VALUE;
vb@4256
  1470
vb@4262
  1471
    *command_list = NULL;
vb@4262
  1472
vb@4266
  1473
    // decode
vb@4266
  1474
vb@4262
  1475
    Distribution_t *dist = NULL;
vb@4262
  1476
    PEP_STATUS status = decode_Distribution_message(cmds, size, &dist);
vb@4262
  1477
    if (status)
vb@4262
  1478
        goto the_end;
vb@4262
  1479
vb@4266
  1480
    // check if these are key reset commands or not
vb@4266
  1481
vb@4265
  1482
    assert(dist && dist->present == Distribution_PR_keyreset
vb@4265
  1483
            && dist->choice.keyreset.present == KeyReset_PR_commands);
vb@4265
  1484
vb@4262
  1485
    if (!(dist && dist->present == Distribution_PR_keyreset
vb@4262
  1486
            && dist->choice.keyreset.present == KeyReset_PR_commands)) {
vb@4265
  1487
        status = PEP_ILLEGAL_VALUE;
vb@4262
  1488
        goto the_end;
vb@4262
  1489
    }
vb@4262
  1490
vb@4271
  1491
    // convert to pEp engine struct
vb@4266
  1492
vb@4269
  1493
    keyreset_command_list *result = Distribution_to_keyreset_command_list(dist, NULL);
vb@4262
  1494
    if (!result)
vb@4262
  1495
        goto enomem;
vb@4262
  1496
vb@4266
  1497
    // return result
vb@4266
  1498
vb@4263
  1499
    *command_list = result;
vb@4262
  1500
    goto the_end;
vb@4262
  1501
vb@4262
  1502
enomem:
vb@4262
  1503
    status = PEP_OUT_OF_MEMORY;
vb@4264
  1504
    free_keyreset_command_list(result);
vb@4262
  1505
vb@4262
  1506
the_end:
vb@4262
  1507
    ASN_STRUCT_FREE(asn_DEF_Distribution, dist);
vb@4262
  1508
    return status;
vb@4256
  1509
}