Merged in adjusted key_reset (ENGINE-536) sync
authorKrista 'DarthMama' Bennett <krista@pep.foundation>
Wed, 10 Apr 2019 19:20:00 +0200
branchsync
changeset 3497f0afea7fbc1b
parent 3477 4fb698bc3f66
parent 3496 26ede9aa59fe
child 3498 9c7f5f60094e
Merged in adjusted key_reset (ENGINE-536)
     1.1 --- a/src/key_reset.c	Tue Apr 09 11:33:09 2019 +0200
     1.2 +++ b/src/key_reset.c	Wed Apr 10 19:20:00 2019 +0200
     1.3 @@ -323,20 +323,60 @@
     1.4      return status;
     1.5  }
     1.6  
     1.7 -DYNAMIC_API PEP_STATUS key_reset(
     1.8 +DYNAMIC_API PEP_STATUS key_reset_identity(
     1.9 +        PEP_SESSION session,
    1.10 +        const char* fpr,
    1.11 +        pEp_identity* ident
    1.12 +    )
    1.13 +{
    1.14 +    if (!session || !ident || EMPTYSTR(ident->user_id) || EMPTYSTR(ident->address))
    1.15 +        return PEP_ILLEGAL_VALUE;
    1.16 +    
    1.17 +    return key_reset(session, fpr, ident);    
    1.18 +}
    1.19 +
    1.20 +DYNAMIC_API PEP_STATUS key_reset_user(
    1.21 +        PEP_SESSION session,
    1.22 +        const char* fpr,
    1.23 +        const char* user_id
    1.24 +    )
    1.25 +{
    1.26 +    if (!session)
    1.27 +        return PEP_ILLEGAL_VALUE;
    1.28 +
    1.29 +    pEp_identity* input_ident = NULL;
    1.30 +    
    1.31 +    if (!EMPTYSTR(user_id)) {
    1.32 +        input_ident = new_identity(NULL, NULL, NULL, user_id);
    1.33 +
    1.34 +        if (!input_ident)
    1.35 +            return PEP_OUT_OF_MEMORY;
    1.36 +    }
    1.37 +        
    1.38 +    PEP_STATUS status = key_reset(session, fpr, input_ident);
    1.39 +
    1.40 +    free_identity(input_ident);
    1.41 +    return status;            
    1.42 +}
    1.43 +
    1.44 +// Notes to integrate into header:
    1.45 +// IF there is an ident, it must have a user_id.
    1.46 +PEP_STATUS key_reset(
    1.47          PEP_SESSION session,
    1.48          const char* key_id,
    1.49          pEp_identity* ident
    1.50      )
    1.51  {
    1.52 -    if (!session)
    1.53 +    if (!session || (ident && EMPTYSTR(ident->user_id)))
    1.54          return PEP_ILLEGAL_VALUE;
    1.55          
    1.56      PEP_STATUS status = PEP_STATUS_OK;
    1.57          
    1.58      char* fpr_copy = NULL;
    1.59      char* own_id = NULL;
    1.60 +    char* user_id = NULL;
    1.61      char* new_key = NULL;
    1.62 +    pEp_identity* tmp_ident = NULL;
    1.63      identity_list* key_idents = NULL;
    1.64      stringlist_t* keys = NULL;
    1.65      
    1.66 @@ -345,133 +385,205 @@
    1.67          if (!fpr_copy)
    1.68              return PEP_OUT_OF_MEMORY;
    1.69      }
    1.70 -        
    1.71 -    if (!ident) {
    1.72 -        // Get list of own identities
    1.73 -        status = get_default_own_userid(session, &own_id);
    1.74 -        if (status != PEP_STATUS_OK)
    1.75 +
    1.76 +    // This is true when we don't have a user_id and address and the fpr isn't specified
    1.77 +    bool reset_all_for_user = !fpr_copy && (!ident || EMPTYSTR(ident->address));
    1.78 +
    1.79 +    // FIXME: does this need to be done everywhere?> I think not.
    1.80 +    if (ident) {
    1.81 +        user_id = strdup(ident->user_id);
    1.82 +        if (!user_id) {
    1.83 +            status = PEP_OUT_OF_MEMORY;
    1.84              goto pEp_free;
    1.85 +        }
    1.86 +    }
    1.87 +    else {
    1.88 +        status = get_default_own_userid(session, &user_id);
    1.89 +        if (status != PEP_STATUS_OK || !user_id)
    1.90 +            goto pEp_free;                    
    1.91 +    }
    1.92 +    
    1.93 +    // FIXME: Make sure this can't result in a double-free in recursive calls
    1.94 +    tmp_ident = (ident ? identity_dup(ident) : new_identity(NULL, NULL, user_id, NULL));
    1.95 +    
    1.96 +    if (reset_all_for_user) {
    1.97 +        status = get_all_keys_for_user(session, user_id, &keys);
    1.98 +        // TODO: free
    1.99 +        if (status == PEP_STATUS_OK) {
   1.100 +            stringlist_t* curr_key;
   1.101              
   1.102 -        if (EMPTYSTR(fpr_copy)) {
   1.103 -            status = get_all_keys_for_user(session, own_id, &keys);
   1.104 -            if (status == PEP_STATUS_OK) {
   1.105 -                stringlist_t* curr_key;
   1.106 -                for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
   1.107 -                    status = key_reset(session, curr_key->value, NULL);
   1.108 -                    if (status != PEP_STATUS_OK)
   1.109 -                        break;
   1.110 -                }
   1.111 -            }
   1.112 -            goto pEp_free;
   1.113 -        } // otherwise, we have a specific fpr to process
   1.114 -
   1.115 -        // fpr_copy exists, so... let's go.
   1.116 -        // Process own identities with this fpr
   1.117 -        status = get_identities_by_main_key_id(session, fpr_copy, &key_idents);
   1.118 -        
   1.119 -        if (status == PEP_STATUS_OK) {
   1.120 -            // have ident list, or should
   1.121 -            identity_list* curr_ident;
   1.122 -            for (curr_ident = key_idents; curr_ident && curr_ident->ident; 
   1.123 -                 curr_ident = curr_ident->next) {
   1.124 -                pEp_identity* this_identity = curr_ident->ident;
   1.125 -                status = key_reset(session, fpr_copy, this_identity);
   1.126 +            for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
   1.127 +                // FIXME: Is the ident really necessary?
   1.128 +                status = key_reset(session, curr_key->value, tmp_ident);
   1.129                  if (status != PEP_STATUS_OK)
   1.130 -                    break;                    
   1.131 +                    break;
   1.132              }
   1.133          }
   1.134 -        else if (status == PEP_CANNOT_FIND_IDENTITY) // not an error
   1.135 -            status = PEP_STATUS_OK;
   1.136 +        goto pEp_free;
   1.137 +    }                   
   1.138 +    else {
   1.139 +        // tmp_ident => tmp_ident->user_id (was checked)
   1.140 +        //
   1.141 +        // !(EMPTYSTR(fpr) && (!tmp_ident || EMPTYSTR(tmp_ident->address)))
   1.142 +        // => fpr || (tmp_ident && tmp_ident->address)
   1.143 +        //
   1.144 +        // so: We have an fpr or we have an ident with user_id and address
   1.145 +        //     or both
   1.146 +        if (!fpr_copy) {
   1.147 +            // We are guaranteed to have an ident w/ id + addr here.
   1.148 +            // Get the default key.
   1.149 +            pEp_identity* stored_ident = NULL;
   1.150 +            status = get_identity(session, tmp_ident->address, 
   1.151 +                                  tmp_ident->user_id, &stored_ident);
   1.152 +
   1.153 +            // FIXME FIXME FIXME
   1.154 +            if (status == PEP_STATUS_OK) {
   1.155 +                // transfer ownership
   1.156 +                fpr_copy = stored_ident->fpr;
   1.157 +                stored_ident->fpr = NULL;
   1.158 +                free_identity(stored_ident);                
   1.159 +            }
   1.160              
   1.161 -        goto pEp_free;
   1.162 -    }
   1.163 -    else { // an identity was specified.       
   1.164 -        if (is_me(session, ident)) {            
   1.165 -            // FIXME: make sure this IS our fpr?
   1.166 +            if (!fpr_copy || status == PEP_CANNOT_FIND_IDENTITY) {
   1.167 +                // There's no identity default. Try resetting user default
   1.168 +                status = get_user_default_key(session, tmp_ident->user_id, &fpr_copy);
   1.169 +            }            
   1.170              
   1.171 -            // If it got sent in with an empty fpr...
   1.172 -            if (EMPTYSTR(fpr_copy)) {
   1.173 -                //
   1.174 -                // if (!EMPTYSTR(ident->fpr))
   1.175 -                //     fpr_copy = strdup(ident->fpr);
   1.176 -                status = _myself(session, ident, false, true, true);
   1.177 -                if (status == PEP_STATUS_OK && ident->fpr)
   1.178 -                    fpr_copy = strdup(ident->fpr);
   1.179 -                else {
   1.180 -                    // last resort?
   1.181 -                    // Get list of own identities
   1.182 -                    char* own_id = NULL;
   1.183 -                    status = get_default_own_userid(session, &own_id);
   1.184 -                    if (status == PEP_STATUS_OK)
   1.185 -                        status = get_user_default_key(session, own_id, &fpr_copy);
   1.186 -                    if (status != PEP_STATUS_OK || EMPTYSTR(fpr_copy))  {
   1.187 -                        free(own_id);
   1.188 -                        return (status == PEP_STATUS_OK ? PEP_KEY_NOT_FOUND : status);
   1.189 +            if (!fpr_copy || status != PEP_STATUS_OK) // No default to free. We're done here.
   1.190 +                goto pEp_free;            
   1.191 +        }
   1.192 +        
   1.193 +        // Ok - now we have at least an ident with user_id and an fpr.
   1.194 +        // Now it matters if we're talking about ourselves or a partner.
   1.195 +        bool is_own_private = false;
   1.196 +        if (is_me(session, tmp_ident)) {
   1.197 +            bool own_key = false;            
   1.198 +            status = is_own_key(session, fpr_copy, &own_key);
   1.199 +
   1.200 +            if (status != PEP_STATUS_OK)
   1.201 +                goto pEp_free;
   1.202 +            if (!own_key) {
   1.203 +                status = PEP_ILLEGAL_VALUE;
   1.204 +                goto pEp_free;
   1.205 +            }
   1.206 +
   1.207 +            status = contains_priv_key(session, fpr_copy, &is_own_private);
   1.208 +            if (status != PEP_STATUS_OK)
   1.209 +                goto pEp_free;
   1.210 +        }
   1.211 +        
   1.212 +        // Up to this point, we haven't cared about whether or not we 
   1.213 +        // had a full identity. Now we have to deal with that in the 
   1.214 +        // case of own identities with private keys.
   1.215 +        
   1.216 +        if (is_own_private) {
   1.217 +            
   1.218 +            // If there's no address, we want to reset this key for every identity 
   1.219 +            // it's a part of. Since this means generating new keys, we have to 
   1.220 +            // grab all the identities associated with it.
   1.221 +            if (EMPTYSTR(tmp_ident->address)) {
   1.222 +                status = get_identities_by_main_key_id(session, fpr_copy, &key_idents);
   1.223 +                
   1.224 +                if (status != PEP_CANNOT_FIND_IDENTITY) {
   1.225 +                    if (status == PEP_STATUS_OK) {
   1.226 +                        // now have ident list, or should
   1.227 +                        identity_list* curr_ident;
   1.228 +                        
   1.229 +                        for (curr_ident = key_idents; curr_ident && curr_ident->ident; 
   1.230 +                                                        curr_ident = curr_ident->next) {
   1.231 +                            
   1.232 +                            pEp_identity* this_identity = curr_ident->ident;
   1.233 +                            // Do the full reset on this identity        
   1.234 +                            status = key_reset(session, fpr_copy, this_identity);
   1.235 +                            
   1.236 +                            // Ident list gets freed below, do not free here!
   1.237 +
   1.238 +                            if (status != PEP_STATUS_OK)
   1.239 +                                break;
   1.240 +                            
   1.241 +                        }
   1.242                      }
   1.243 -                }
   1.244 +                    // Ok, we've either now reset for each own identity with this key, or 
   1.245 +                    // we got an error and want to bail anyway.
   1.246 +                    goto pEp_free;
   1.247 +                }    
   1.248              }
   1.249 -                        
   1.250 -            free(ident->fpr);
   1.251 -            ident->fpr = fpr_copy;            
   1.252 +            
   1.253              // Create revocation
   1.254              status = revoke_key(session, fpr_copy, NULL);
   1.255 -            // generate new key
   1.256 -            if (status == PEP_STATUS_OK) {
   1.257 -                ident->fpr = NULL;
   1.258 -                status = generate_keypair(session, ident);
   1.259 -            }
   1.260 -            if (status == PEP_STATUS_OK) {
   1.261 -                new_key = strdup(ident->fpr);
   1.262 -                status = set_own_key(session, ident, new_key);
   1.263 -            }
   1.264 -            // mistrust fpr from trust
   1.265 -            ident->fpr = fpr_copy;
   1.266              
   1.267 -            ident->comm_type = PEP_ct_mistrusted;
   1.268 -            status = set_trust(session, ident);
   1.269 -            ident->fpr = NULL;
   1.270 -            
   1.271 -            // Done with old use of ident.
   1.272 -            if (status == PEP_STATUS_OK) {
   1.273 -                // Update fpr for outgoing
   1.274 -                status = myself(session, ident);
   1.275 -            }
   1.276 +            // If we have a full identity, we have some cleanup and generation tasks here
   1.277 +            if (!EMPTYSTR(tmp_ident->address)) {
   1.278 +                // generate new key
   1.279 +                if (status == PEP_STATUS_OK) {
   1.280 +                    tmp_ident->fpr = NULL;
   1.281 +                    status = generate_keypair(session, tmp_ident);
   1.282 +                }
   1.283 +                if (status == PEP_STATUS_OK) {
   1.284 +                    new_key = strdup(tmp_ident->fpr);
   1.285 +                    status = set_own_key(session, tmp_ident, new_key);
   1.286 +                }
   1.287 +                // mistrust fpr from trust
   1.288 +                tmp_ident->fpr = fpr_copy;
   1.289 +                
   1.290 +                tmp_ident->comm_type = PEP_ct_mistrusted;
   1.291 +                status = set_trust(session, tmp_ident);
   1.292 +                tmp_ident->fpr = NULL;
   1.293 +                
   1.294 +                // Done with old use of ident.
   1.295 +                if (status == PEP_STATUS_OK) {
   1.296 +                    // Update fpr for outgoing
   1.297 +                    status = myself(session, tmp_ident);
   1.298 +                }
   1.299 +            }    
   1.300              
   1.301              if (status == PEP_STATUS_OK)
   1.302                  // cascade that mistrust for anyone using this key
   1.303                  status = mark_as_compromised(session, fpr_copy);
   1.304 +                
   1.305              if (status == PEP_STATUS_OK)
   1.306                  status = remove_fpr_as_default(session, fpr_copy);
   1.307              if (status == PEP_STATUS_OK)
   1.308                  status = add_mistrusted_key(session, fpr_copy);
   1.309 -            // add to revocation list 
   1.310 -            if (status == PEP_STATUS_OK) 
   1.311 -                status = set_revoked(session, fpr_copy, new_key, time(NULL));            
   1.312 -            // for all active communication partners:
   1.313 -            //      active_send revocation
   1.314 -            if (status == PEP_STATUS_OK)
   1.315 -                status = send_key_reset_to_recents(session, fpr_copy, new_key);
   1.316 -                
   1.317 +
   1.318 +            // If there's a new key, do the DB linkage with the revoked one, and 
   1.319 +            // send the key reset mail opportunistically to recently contacted
   1.320 +            // partners
   1.321 +            if (new_key) {
   1.322 +                // add to revocation list 
   1.323 +                if (status == PEP_STATUS_OK) 
   1.324 +                    status = set_revoked(session, fpr_copy, new_key, time(NULL));            
   1.325 +                // for all active communication partners:
   1.326 +                //      active_send revocation
   1.327 +                if (status == PEP_STATUS_OK)
   1.328 +                    status = send_key_reset_to_recents(session, fpr_copy, new_key);        
   1.329 +            }        
   1.330 +        } // end is_own_private
   1.331 +        else {
   1.332 +            // This is a public key (or a private key that isn't ours, which means
   1.333 +            // we want it gone anyway)
   1.334 +            //
   1.335 +            // Delete this key from the keyring.
   1.336 +            status = delete_keypair(session, fpr_copy);
   1.337          }
   1.338 -        else { // not is_me
   1.339 -            // TODO: Decide what this means. We have a non-own identity, we don't
   1.340 -            //       have an fpr. Do we reset all keys for that identity?
   1.341 -            if (EMPTYSTR(fpr_copy)) {
   1.342 -                NOT_IMPLEMENTED
   1.343 -            }
   1.344 -                
   1.345 -            // remove fpr from all identities
   1.346 -            // remove fpr from all users
   1.347 -            if (status == PEP_STATUS_OK)
   1.348 -                status = remove_fpr_as_default(session, fpr_copy);
   1.349 -            // delete key from DB
   1.350 -            if (status == PEP_STATUS_OK) {
   1.351 -                status = remove_key(session, fpr_copy);
   1.352 -            };
   1.353 +
   1.354 +        // REGARDLESS OF WHO OWNS THE KEY, WE NOW NEED TO REMOVE IT AS A DEFAULT.
   1.355 +        PEP_STATUS cached_status = status;
   1.356 +        // remove fpr from all identities
   1.357 +        // remove fpr from all users
   1.358 +        status = remove_fpr_as_default(session, fpr_copy);
   1.359 +        // delete key from DB - this does NOT touch the keyring!
   1.360 +        // Note: for own priv keys, we cannot do this. But we'll never encrypt to/from it.
   1.361 +        if (status == PEP_STATUS_OK && !is_own_private) {
   1.362 +            status = remove_key(session, fpr_copy);
   1.363          }
   1.364 -    }
   1.365 -    
   1.366 +        if (status == PEP_STATUS_OK)
   1.367 +            status = cached_status;
   1.368 +    }           
   1.369 +        
   1.370  pEp_free:
   1.371 +    if (!ident)
   1.372 +        free_identity(tmp_ident);
   1.373      free(fpr_copy);
   1.374      free(own_id);
   1.375      free_identity_list(key_idents);
     2.1 --- a/src/key_reset.h	Tue Apr 09 11:33:09 2019 +0200
     2.2 +++ b/src/key_reset.h	Wed Apr 10 19:20:00 2019 +0200
     2.3 @@ -15,6 +15,70 @@
     2.4  extern "C" {
     2.5  #endif
     2.6  
     2.7 +// key_reset_identity() - resets trust status for this identity and fpr, and remove
     2.8 +//                        this fpr as a default for all identities and users and from 
     2.9 +//                        the keyring.
    2.10 +//                        
    2.11 +//                        If the fpr is NULL, we will reset the identity default fpr
    2.12 +//                        as above. When that does not exist, then we do it for 
    2.13 +//                        the user default. 
    2.14 +//
    2.15 +//                        For own identities, when the fpr has a private key part,
    2.16 +//                        also revoke the key and communicate the revocation and new key 
    2.17 +//                        to partners we have sent mail to recently from the specific identity 
    2.18 +//                        (i.e. address/user_id) that contacted them. We also in this case 
    2.19 +//                        set up information so that if someone we mail uses the wrong key 
    2.20 +//                        and wasn't yet contacted, we can send them the reset information 
    2.21 +//                        from the right address. 
    2.22 +//
    2.23 +//  parameters:
    2.24 +//      session (in)            session handle
    2.25 +//      fpr (in)                fingerprint of key to reset. If NULL, we reset the default key
    2.26 +//                              this user, if there is one.
    2.27 +//      ident (in)              identity for which the key reset should occur. Must contain 
    2.28 +//                              user_id and address.
    2.29 +//
    2.30 +//                              fpr field will be ignored. Cannot be NULL.
    2.31 +//
    2.32 +//      Note: ident->fpr is always ignored
    2.33 +//
    2.34 +//
    2.35 +DYNAMIC_API PEP_STATUS key_reset_identity(
    2.36 +        PEP_SESSION session,
    2.37 +        const char* fpr,
    2.38 +        pEp_identity* ident
    2.39 +    );
    2.40 +
    2.41 +// key_reset_user() - reset the default key database status for each identity 
    2.42 +//                    corresponding to this user and fpr (if present), and remove from 
    2.43 +//                    the keyring. This will also remove the key(s) from all other 
    2.44 +//                    users and identities. If no fpr is present, reset all default keys 
    2.45 +//                    corresponding to this user and its identities.
    2.46 +//           
    2.47 +//                    For own keys, also revoke the key(s) and communicate the 
    2.48 +//                    revocation and new key(s) to partners we have sent mail to 
    2.49 +//                    recently from the specific identities (i.e. address/user_id) 
    2.50 +//                    that contacted them. We also in this case set up information 
    2.51 +//                    so that if someone we mail uses the wrong key and wasn't 
    2.52 +//                    yet contacted, we can send them the reset information 
    2.53 +//                    from the right address.
    2.54 +//
    2.55 +//                    If the user_id is NULL and fpr is NULL, we reset all keys for the own user. 
    2.56 +//
    2.57 +//  parameters:
    2.58 +//      session (in)            session handle
    2.59 +//      fpr (in)                fingerprint of key to reset. If NULL and user_id is NULL,
    2.60 +//                              we reset all keys for the own user. If NULL, we reset all default 
    2.61 +//                              keys for this user and all of its identities.
    2.62 +//      user_id (in)            user_id for which the key reset should occur.
    2.63 +//                              If the user_id is NULL, we reset keys for the own user.
    2.64 +//
    2.65 +DYNAMIC_API PEP_STATUS key_reset_user(
    2.66 +        PEP_SESSION session,
    2.67 +        const char* fpr,
    2.68 +        const char* user_id
    2.69 +    );
    2.70 +
    2.71  // key_reset() - reset the database status for a key, removing all trust information
    2.72  //               and default database connections. For own keys, also revoke the key
    2.73  //               and communicate the revocation and new key to partners we have sent
    2.74 @@ -32,10 +96,8 @@
    2.75  //                              an own identity, we reset the default key for that
    2.76  //                              identity. If that own identity has no default key, we
    2.77  //                              reset the user default.
    2.78 -//                              if it is NULL and there is a non-own identity, this is
    2.79 -//                              currently undefined and will return an error. Later, we
    2.80 -//                              may decide on semantics for it (e.g. remove all keys
    2.81 -//                              in the DB for that identity)
    2.82 +//                              if it is NULL and there is a non-own identity, we will reset 
    2.83 +//                              the default key for this identity.
    2.84  //      ident (in)              identity for which the key reset should occur.
    2.85  //                              if NULL and fpr is non-NULL, we'll reset the key for all
    2.86  //                              associated identities. If both ident and fpr are NULL, see 
    2.87 @@ -43,13 +105,17 @@
    2.88  //
    2.89  //      Note: ident->fpr is always ignored
    2.90  //
    2.91 -//
    2.92 -DYNAMIC_API PEP_STATUS key_reset(
    2.93 +// Caveat: this is now used in large part for internal calls.
    2.94 +//         external apps should call key_reset_identity and key_reset_userdata
    2.95 +//         and this function should probably be removed from the dynamic api
    2.96 +PEP_STATUS key_reset(
    2.97          PEP_SESSION session,
    2.98          const char* fpr,
    2.99          pEp_identity* ident
   2.100      );
   2.101  
   2.102 +
   2.103 +
   2.104  PEP_STATUS has_key_reset_been_sent(
   2.105          PEP_SESSION session, 
   2.106          const char* user_id, 
     3.1 --- a/test/src/engine_tests/KeyResetMessageTests.cc	Tue Apr 09 11:33:09 2019 +0200
     3.2 +++ b/test/src/engine_tests/KeyResetMessageTests.cc	Wed Apr 10 19:20:00 2019 +0200
     3.3 @@ -468,7 +468,7 @@
     3.4      int int_result = sqlite3_exec(
     3.5          session->db,
     3.6          "update identity "
     3.7 -        "   set timestamp = 661008730 "
     3.8 +        "   set timestamp = '2018-04-10 16:48:33' "
     3.9          "   where address = 'pep-test-gabrielle@pep-project.org' ;",
    3.10          NULL,
    3.11          NULL,