Merged in fixes for ENGINE-352, ENGINE-345, a bunch of trust/mistrust issues, and general mayhem.
authorKrista Bennett <krista@pep-project.org>
Sun, 04 Feb 2018 15:26:28 +0100
changeset 24765a4da2a7f99b
parent 2466 339399330a9b
parent 2473 6ca62f99148e
child 2477 45e8ed722fec
child 2484 93b9a267675f
Merged in fixes for ENGINE-352, ENGINE-345, a bunch of trust/mistrust issues, and general mayhem.
     1.1 --- a/src/keymanagement.c	Mon Jan 29 16:52:54 2018 +0100
     1.2 +++ b/src/keymanagement.c	Sun Feb 04 15:26:28 2018 +0100
     1.3 @@ -77,8 +77,11 @@
     1.4                      _comm_type_key > identity->comm_type)
     1.5                  {
     1.6                      bool blacklisted;
     1.7 -                    status = blacklist_is_listed(session, _keylist->value, &blacklisted);
     1.8 -                    if (status == PEP_STATUS_OK && !blacklisted) {
     1.9 +                    bool mistrusted;
    1.10 +                    status = is_mistrusted_key(session, _keylist->value, &mistrusted);
    1.11 +                    if (status == PEP_STATUS_OK)
    1.12 +                        status = blacklist_is_listed(session, _keylist->value, &blacklisted);
    1.13 +                    if (status == PEP_STATUS_OK && !mistrusted && !blacklisted) {
    1.14                          identity->comm_type = _comm_type_key;
    1.15                          _fpr = _keylist->value;
    1.16                      }
    1.17 @@ -88,10 +91,14 @@
    1.18      }
    1.19      free(identity->fpr);
    1.20  
    1.21 -    identity->fpr = strdup(_fpr);
    1.22 -    if (identity->fpr == NULL) {
    1.23 -        free_stringlist(keylist);
    1.24 -        return PEP_OUT_OF_MEMORY;
    1.25 +    if (!_fpr || _fpr[0] == '\0')
    1.26 +        identity->fpr = NULL;
    1.27 +    else {    
    1.28 +        identity->fpr = strdup(_fpr);
    1.29 +        if (identity->fpr == NULL) {
    1.30 +            free_stringlist(keylist);
    1.31 +            return PEP_OUT_OF_MEMORY;
    1.32 +        }
    1.33      }
    1.34      
    1.35      free_stringlist(keylist);
    1.36 @@ -199,6 +206,7 @@
    1.37              status = update_trust_for_fpr(session, 
    1.38                                            fpr, 
    1.39                                            ct);
    1.40 +        case PEP_ct_mistrusted:                                  
    1.41              free(ident->fpr);
    1.42              ident->fpr = NULL;
    1.43              ident->comm_type = ct;            
    1.44 @@ -369,14 +377,15 @@
    1.45              stored_ident->comm_type = ct;
    1.46          }
    1.47      }
    1.48 +    else {
    1.49 +        if (stored_ident->comm_type == PEP_ct_unknown)
    1.50 +            stored_ident->comm_type = PEP_ct_key_not_found;
    1.51 +    }
    1.52      free(return_id->fpr);
    1.53      return_id->fpr = NULL;
    1.54      if (status == PEP_STATUS_OK && !EMPTYSTR(stored_ident->fpr))
    1.55          return_id->fpr = strdup(stored_ident->fpr);
    1.56          
    1.57 -    // This is outside the if block ON PURPOSE - we return an empty FPR +
    1.58 -    // the reason why a key wasn't used in the comm_type string if we can't
    1.59 -    // find or use one.
    1.60      return_id->comm_type = stored_ident->comm_type;
    1.61                  
    1.62      // We patch the DB with the input username, but if we didn't have
    1.63 @@ -1064,6 +1073,8 @@
    1.64              status = mark_as_compromized(session, ident->fpr);
    1.65          if (status == PEP_STATUS_OK)
    1.66              status = remove_fpr_as_default(session, ident->fpr);
    1.67 +        if (status == PEP_STATUS_OK)
    1.68 +            status = add_mistrusted_key(session, ident->fpr);
    1.69      }
    1.70  
    1.71      return status;
    1.72 @@ -1082,12 +1093,15 @@
    1.73      if (!cached_ident)
    1.74          status = PEP_CANNOT_FIND_IDENTITY;
    1.75      else {
    1.76 -        status = set_identity(session, cached_ident);            
    1.77 -        free_identity(session->cached_mistrusted);
    1.78 +        status = delete_mistrusted_key(session, cached_ident->fpr);
    1.79 +        if (status == PEP_STATUS_OK) {
    1.80 +            status = set_identity(session, cached_ident);            
    1.81 +            free_identity(session->cached_mistrusted);
    1.82 +        }
    1.83      }
    1.84      
    1.85      session->cached_mistrusted = NULL;
    1.86 -
    1.87 +    
    1.88      return status;
    1.89  }
    1.90  
    1.91 @@ -1128,7 +1142,19 @@
    1.92      if (status != PEP_STATUS_OK)
    1.93          goto pep_free;
    1.94  
    1.95 +    bool mistrusted_key = false;
    1.96          
    1.97 +    status = is_mistrusted_key(session, ident->fpr, &mistrusted_key);
    1.98 +
    1.99 +    if (status != PEP_STATUS_OK)
   1.100 +        goto pep_free;
   1.101 +    
   1.102 +    if (mistrusted_key)
   1.103 +        status = delete_mistrusted_key(session, ident->fpr);
   1.104 +
   1.105 +    if (status != PEP_STATUS_OK)
   1.106 +        goto pep_free;
   1.107 +    
   1.108      input_copy->comm_type = new_trust;
   1.109          
   1.110      tmp_ident = new_identity(ident->address, NULL, ident->user_id, NULL);
   1.111 @@ -1568,3 +1594,80 @@
   1.112  
   1.113      return session->cryptotech[PEP_crypt_OpenPGP].contains_priv_key(session, fpr, has_private);
   1.114  }
   1.115 +
   1.116 +PEP_STATUS add_mistrusted_key(PEP_SESSION session, const char* fpr)
   1.117 +{
   1.118 +    int result;
   1.119 +
   1.120 +    assert(!EMPTYSTR(fpr));
   1.121 +    
   1.122 +    if (!(session) || EMPTYSTR(fpr))
   1.123 +        return PEP_ILLEGAL_VALUE;
   1.124 +
   1.125 +    sqlite3_reset(session->add_mistrusted_key);
   1.126 +    sqlite3_bind_text(session->add_mistrusted_key, 1, fpr, -1,
   1.127 +            SQLITE_STATIC);
   1.128 +
   1.129 +    result = sqlite3_step(session->add_mistrusted_key);
   1.130 +    sqlite3_reset(session->add_mistrusted_key);
   1.131 +
   1.132 +    if (result != SQLITE_DONE)
   1.133 +        return PEP_CANNOT_SET_PGP_KEYPAIR; // FIXME: Better status?
   1.134 +
   1.135 +    return PEP_STATUS_OK;
   1.136 +}
   1.137 +
   1.138 +PEP_STATUS delete_mistrusted_key(PEP_SESSION session, const char* fpr)
   1.139 +{
   1.140 +    int result;
   1.141 +
   1.142 +    assert(!EMPTYSTR(fpr));
   1.143 +    
   1.144 +    if (!(session) || EMPTYSTR(fpr))
   1.145 +        return PEP_ILLEGAL_VALUE;
   1.146 +
   1.147 +    sqlite3_reset(session->delete_mistrusted_key);
   1.148 +    sqlite3_bind_text(session->delete_mistrusted_key, 1, fpr, -1,
   1.149 +            SQLITE_STATIC);
   1.150 +
   1.151 +    result = sqlite3_step(session->delete_mistrusted_key);
   1.152 +    sqlite3_reset(session->delete_mistrusted_key);
   1.153 +
   1.154 +    if (result != SQLITE_DONE)
   1.155 +        return PEP_UNKNOWN_ERROR; // FIXME: Better status?
   1.156 +
   1.157 +    return PEP_STATUS_OK;
   1.158 +}
   1.159 +
   1.160 +PEP_STATUS is_mistrusted_key(PEP_SESSION session, const char* fpr,
   1.161 +                             bool* mistrusted)
   1.162 +{
   1.163 +    PEP_STATUS status = PEP_STATUS_OK;
   1.164 +
   1.165 +    assert(session);
   1.166 +    assert(!EMPTYSTR(fpr));
   1.167 +
   1.168 +    if (!(session && fpr))
   1.169 +        return PEP_ILLEGAL_VALUE;
   1.170 +
   1.171 +    *mistrusted = false;
   1.172 +
   1.173 +    sqlite3_reset(session->is_mistrusted_key);
   1.174 +    sqlite3_bind_text(session->is_mistrusted_key, 1, fpr, -1, SQLITE_STATIC);
   1.175 +
   1.176 +    int result;
   1.177 +
   1.178 +    result = sqlite3_step(session->is_mistrusted_key);
   1.179 +    switch (result) {
   1.180 +    case SQLITE_ROW:
   1.181 +        *mistrusted = sqlite3_column_int(session->is_mistrusted_key, 0);
   1.182 +        status = PEP_STATUS_OK;
   1.183 +        break;
   1.184 +
   1.185 +    default:
   1.186 +        status = PEP_UNKNOWN_ERROR;
   1.187 +    }
   1.188 +
   1.189 +    sqlite3_reset(session->is_mistrusted_key);
   1.190 +    return status;
   1.191 +}
     2.1 --- a/src/keymanagement.h	Mon Jan 29 16:52:54 2018 +0100
     2.2 +++ b/src/keymanagement.h	Sun Feb 04 15:26:28 2018 +0100
     2.3 @@ -344,6 +344,11 @@
     2.4  
     2.5  PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags);
     2.6  
     2.7 +PEP_STATUS add_mistrusted_key(PEP_SESSION session, const char* fpr);
     2.8 +PEP_STATUS delete_mistrusted_key(PEP_SESSION session, const char* fpr);
     2.9 +PEP_STATUS is_mistrusted_key(PEP_SESSION session, const char* fpr, bool* mistrusted);
    2.10 +
    2.11 +
    2.12  #ifdef __cplusplus
    2.13  }
    2.14  #endif
     3.1 --- a/src/message_api.c	Mon Jan 29 16:52:54 2018 +0100
     3.2 +++ b/src/message_api.c	Sun Feb 04 15:26:28 2018 +0100
     3.3 @@ -20,6 +20,12 @@
     3.4  #define _MAX(A, B) ((B) > (A) ? (B) : (A))
     3.5  #endif
     3.6  
     3.7 +// These are globals used in generating message IDs and should only be
     3.8 +// computed once, as they're either really constants or OS-dependent
     3.9 +
    3.10 +int _pEp_rand_max_bits;
    3.11 +double _pEp_log2_36;
    3.12 +
    3.13  static bool is_a_pEpmessage(const message *msg)
    3.14  {
    3.15      for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
    3.16 @@ -1495,6 +1501,8 @@
    3.17      }
    3.18  
    3.19      bool dest_keys_found = true;
    3.20 +    bool has_pep_user = false;
    3.21 +    
    3.22      PEP_comm_type max_comm_type = PEP_ct_pEp;
    3.23  
    3.24      identity_list * _il;
    3.25 @@ -1518,6 +1526,8 @@
    3.26                  _il->ident->comm_type = PEP_ct_key_not_found;
    3.27                  _status = PEP_STATUS_OK;
    3.28              }
    3.29 +            if (!has_pep_user)
    3.30 +                is_pep_user(session, _il->ident, &has_pep_user);
    3.31          }
    3.32          else
    3.33              _status = myself(session, _il->ident);
    3.34 @@ -1548,6 +1558,8 @@
    3.35                      _il->ident->comm_type = PEP_ct_key_not_found;
    3.36                      _status = PEP_STATUS_OK;
    3.37                  }
    3.38 +                if (!has_pep_user)
    3.39 +                    is_pep_user(session, _il->ident, &has_pep_user);
    3.40              }
    3.41              else
    3.42                  _status = myself(session, _il->ident);
    3.43 @@ -1577,6 +1589,8 @@
    3.44                      _il->ident->comm_type = PEP_ct_key_not_found;
    3.45                      _status = PEP_STATUS_OK;
    3.46                  }
    3.47 +                if (!has_pep_user)
    3.48 +                    is_pep_user(session, _il->ident, &has_pep_user);
    3.49              }
    3.50              else
    3.51                  _status = myself(session, _il->ident);
    3.52 @@ -1606,7 +1620,7 @@
    3.53                  PEP_rating_undefined) < PEP_rating_reliable)
    3.54      {
    3.55          free_stringlist(keys);
    3.56 -        if (!session->passive_mode && 
    3.57 +        if ((has_pep_user || !session->passive_mode) && 
    3.58              !(flags & PEP_encrypt_flag_force_no_attached_key)) {
    3.59              attach_own_key(session, src);
    3.60              decorate_message(src, PEP_rating_undefined, NULL, true);
    3.61 @@ -1823,31 +1837,31 @@
    3.62      return ADD_TO_LOG(status);
    3.63  }
    3.64  
    3.65 -static PEP_STATUS _update_identity_for_incoming_message(
    3.66 -        PEP_SESSION session,
    3.67 -        const message *src
    3.68 -    )
    3.69 -{
    3.70 -    PEP_STATUS status;
    3.71 -
    3.72 -    if (src->from && src->from->address) {
    3.73 -        if (!is_me(session, src->from))
    3.74 -            status = update_identity(session, src->from);
    3.75 -        else
    3.76 -            status = myself(session, src->from);
    3.77 -        if (status == PEP_STATUS_OK
    3.78 -                && is_a_pEpmessage(src)
    3.79 -                && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
    3.80 -                && src->from->comm_type != PEP_ct_pEp_unconfirmed
    3.81 -                && src->from->comm_type != PEP_ct_pEp)
    3.82 -        {
    3.83 -            src->from->comm_type |= PEP_ct_pEp_unconfirmed;
    3.84 -            status = set_identity(session, src->from);
    3.85 -        }
    3.86 -        return status;
    3.87 -    }
    3.88 -    return PEP_ILLEGAL_VALUE;
    3.89 -}
    3.90 +// static PEP_STATUS _update_identity_for_incoming_message(
    3.91 +//         PEP_SESSION session,
    3.92 +//         const message *src
    3.93 +//     )
    3.94 +// {
    3.95 +//     PEP_STATUS status;
    3.96 +// 
    3.97 +//     if (src->from && src->from->address) {
    3.98 +//         if (!is_me(session, src->from))
    3.99 +//             status = update_identity(session, src->from);
   3.100 +//         else
   3.101 +//             status = myself(session, src->from);
   3.102 +//         if (status == PEP_STATUS_OK
   3.103 +//                 && is_a_pEpmessage(src)
   3.104 +//                 && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
   3.105 +//                 && src->from->comm_type != PEP_ct_pEp_unconfirmed
   3.106 +//                 && src->from->comm_type != PEP_ct_pEp)
   3.107 +//         {
   3.108 +//             src->from->comm_type |= PEP_ct_pEp_unconfirmed;
   3.109 +//             status = set_identity(session, src->from);
   3.110 +//         }
   3.111 +//         return status;
   3.112 +//     }
   3.113 +//     return PEP_ILLEGAL_VALUE;
   3.114 +// }
   3.115  
   3.116  
   3.117  static PEP_STATUS _get_detached_signature(message* msg, 
   3.118 @@ -2037,7 +2051,7 @@
   3.119          }
   3.120          else {
   3.121              pEp_identity *_sender = new_identity(sender->address, fpr,
   3.122 -                                               sender->user_id, sender->username);
   3.123 +                                                 sender->user_id, sender->username);
   3.124              if (_sender == NULL)
   3.125                  return PEP_OUT_OF_MEMORY;
   3.126  
   3.127 @@ -2426,6 +2440,58 @@
   3.128      return status;
   3.129  }
   3.130  
   3.131 +static PEP_STATUS update_sender_to_pep_trust(
   3.132 +        PEP_SESSION session, 
   3.133 +        pEp_identity* sender, 
   3.134 +        stringlist_t* keylist) 
   3.135 +{
   3.136 +    assert(session);
   3.137 +    assert(sender);
   3.138 +    assert(keylist && !EMPTYSTR(keylist->value));
   3.139 +    
   3.140 +    if (!session || !sender || !keylist || EMPTYSTR(keylist->value))
   3.141 +        return PEP_ILLEGAL_VALUE;
   3.142 +        
   3.143 +    free(sender->fpr);
   3.144 +    sender->fpr = NULL;
   3.145 +    
   3.146 +    PEP_STATUS status = 
   3.147 +            is_me(session, sender) ? myself(session, sender) : update_identity(session, sender);
   3.148 +    
   3.149 +    if (EMPTYSTR(sender->fpr) || strcmp(sender->fpr, keylist->value) != 0) {
   3.150 +        free(sender->fpr);
   3.151 +        sender->fpr = strdup(keylist->value);
   3.152 +        if (!sender->fpr)
   3.153 +            return PEP_OUT_OF_MEMORY;
   3.154 +        status = get_trust(session, sender);
   3.155 +        
   3.156 +        if (status == PEP_CANNOT_FIND_IDENTITY || sender->comm_type == PEP_ct_unknown) {
   3.157 +            PEP_comm_type ct = PEP_ct_unknown;
   3.158 +            status = get_key_rating(session, sender->fpr, &ct);
   3.159 +            if (status != PEP_STATUS_OK)
   3.160 +                return status;
   3.161 +                
   3.162 +            sender->comm_type = ct;    
   3.163 +        }
   3.164 +    }
   3.165 +    
   3.166 +    // Could be done elegantly, but we do this explicitly here for readability.
   3.167 +    // This file's code is difficult enough to parse. But change at will.
   3.168 +    switch (sender->comm_type) {
   3.169 +        case PEP_ct_OpenPGP_unconfirmed:
   3.170 +            status = set_trust(session, sender->user_id, sender->fpr, PEP_ct_pEp_unconfirmed);
   3.171 +            break;
   3.172 +        case PEP_ct_OpenPGP:
   3.173 +            status = set_trust(session, sender->user_id, sender->fpr, PEP_ct_pEp);
   3.174 +            break;
   3.175 +        default:
   3.176 +            break;
   3.177 +    }
   3.178 +    
   3.179 +    return status;
   3.180 +}
   3.181 +
   3.182 +
   3.183  DYNAMIC_API PEP_STATUS _decrypt_message(
   3.184          PEP_SESSION session,
   3.185          message *src,
   3.186 @@ -2456,36 +2522,58 @@
   3.187      char *ptext = NULL;
   3.188      size_t psize;
   3.189      stringlist_t *_keylist = NULL;
   3.190 +    char* signer_fpr = NULL;
   3.191 +    bool is_pep_msg = is_a_pEpmessage(src);
   3.192  
   3.193      *dst = NULL;
   3.194      *keylist = NULL;
   3.195      *rating = PEP_rating_undefined;
   3.196  
   3.197      *flags = 0;
   3.198 +    
   3.199      /*** End init ***/
   3.200  
   3.201 +    // Ok, before we do anything, if it's a pEp message, regardless of whether it's
   3.202 +    // encrypted or not, we set the sender as a pEp user. This has NOTHING to do
   3.203 +    // with the key.
   3.204 +    if (src->from && !(is_me(session, src->from))) {
   3.205 +        if (is_pep_msg) {
   3.206 +            pEp_identity* tmp_from = src->from;
   3.207 +            
   3.208 +            // Ensure there's a user id
   3.209 +            if (EMPTYSTR(tmp_from->user_id) && tmp_from->address) {
   3.210 +                status = update_identity(session, tmp_from);
   3.211 +                if (status == PEP_CANNOT_FIND_IDENTITY) {
   3.212 +                    tmp_from->user_id = calloc(1, strlen(tmp_from->address) + 6);
   3.213 +                    if (!tmp_from->user_id)
   3.214 +                        return PEP_OUT_OF_MEMORY;
   3.215 +                    snprintf(tmp_from->user_id, strlen(tmp_from->address) + 6,
   3.216 +                             "TOFU_%s", tmp_from->address);        
   3.217 +                    status = PEP_STATUS_OK;
   3.218 +                }
   3.219 +            }
   3.220 +            if (status == PEP_STATUS_OK) {
   3.221 +                // Now set user as PEP (may also create an identity if none existed yet)
   3.222 +                status = set_as_pep_user(session, tmp_from);
   3.223 +            }
   3.224 +        }
   3.225 +    }
   3.226 +    // We really need key used in signing to do anything further on the pEp comm_type.
   3.227 +    // So we can't adjust the rating of the sender just yet.
   3.228 +
   3.229      /*** Begin Import any attached public keys and update identities accordingly ***/
   3.230 -
   3.231      // Private key in unencrypted mail are ignored -> NULL
   3.232      bool imported_keys = import_attached_keys(session, src, NULL);
   3.233  
   3.234 -    // Update src->from in case we just imported a key
   3.235 -    // we would need to check signature
   3.236 -    status = _update_identity_for_incoming_message(session, src);
   3.237 -    
   3.238 -    if (status == PEP_ILLEGAL_VALUE && src->from && is_me(session, src->from)) {
   3.239 -        // the above function should fail if it's us.
   3.240 -        // We don't need to update, as any revocations or expirations
   3.241 -        // of our own key imported above, which are all that we 
   3.242 -        // would care about for anything imported,
   3.243 -        // SHOULD get caught when they matter later.
   3.244 -        // (Private keys imported above are not stored in the trust DB)
   3.245 -        status = PEP_STATUS_OK;
   3.246 -    }
   3.247 +    // FIXME: is this really necessary here?
   3.248 +    if (!is_me(session, src->from))
   3.249 +        status = update_identity(session, src->from);
   3.250 +    else
   3.251 +        status = myself(session, src->from);
   3.252          
   3.253      if (status != PEP_STATUS_OK)
   3.254          return ADD_TO_LOG(status);
   3.255 -
   3.256 +    
   3.257      /*** End Import any attached public keys and update identities accordingly ***/
   3.258      
   3.259      /*** Begin get detached signatures that are attached to the encrypted message ***/
   3.260 @@ -2519,7 +2607,7 @@
   3.261      status = get_crypto_text(src, &ctext, &csize);
   3.262      if (status != PEP_STATUS_OK)
   3.263          return status;
   3.264 -    
   3.265 +        
   3.266      /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
   3.267      status = cryptotech[crypto].decrypt_and_verify(session, ctext,
   3.268                                                     csize, dsig_text, dsig_size,
   3.269 @@ -2677,12 +2765,17 @@
   3.270          }
   3.271          
   3.272          *rating = decrypt_rating(decrypt_status);
   3.273 +        
   3.274 +        // Ok, so if it was signed and it's all verified, we can update
   3.275 +        // eligible signer comm_types to PEP_ct_pEp_*
   3.276 +        if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && is_pep_msg)
   3.277 +            status = update_sender_to_pep_trust(session, src->from, _keylist);
   3.278  
   3.279          /* Ok, now we have a keylist used for decryption/verification.
   3.280             now we need to update the message rating with the 
   3.281             sender and recipients in mind */
   3.282          status = amend_rating_according_to_sender_and_recipients(session,
   3.283 -                rating, src->from, _keylist);
   3.284 +                 rating, src->from, _keylist);
   3.285  
   3.286          if (status != PEP_STATUS_OK)
   3.287              GOTO(pep_error);
   3.288 @@ -2741,6 +2834,7 @@
   3.289  
   3.290  pep_error:
   3.291      free(ptext);
   3.292 +    free(signer_fpr);
   3.293      free_message(msg);
   3.294      free_stringlist(_keylist);
   3.295  
     4.1 --- a/src/pEpEngine.c	Mon Jan 29 16:52:54 2018 +0100
     4.2 +++ b/src/pEpEngine.c	Sun Feb 04 15:26:28 2018 +0100
     4.3 @@ -104,14 +104,26 @@
     4.4      "      where id = ?1), upper(replace(?4,' ','')))),"
     4.5      "    (select device_group from person where id = ?1)) ;";
     4.6  
     4.7 +static const char *sql_set_as_pep_user =
     4.8 +    "update person set is_pep_user = 1 "
     4.9 +    "   where id = ?1 ; ";
    4.10 +
    4.11 +static const char *sql_is_pep_user =
    4.12 +    "select is_pep_user from person "
    4.13 +    "   where id = ?1 ; ";
    4.14 +
    4.15 +static const char* sql_exists_person = 
    4.16 +    "select count(*) from person "
    4.17 +    "   where id = ?1 ;";
    4.18 +
    4.19  static const char *sql_set_device_group = 
    4.20      "update person set device_group = ?1 "
    4.21 -    "where id = ?2;";
    4.22 +    "   where id = ?2;";
    4.23  
    4.24  // This will cascade to identity and trust
    4.25  static const char* sql_replace_userid =
    4.26      "update person set id = ?1 " 
    4.27 -    "where id = ?2;";
    4.28 +    "   where id = ?2;";
    4.29  
    4.30  static const char *sql_replace_main_user_fpr =  
    4.31      "update person "
    4.32 @@ -294,6 +306,17 @@
    4.33      "select default_id from alternate_user_id "
    4.34      "   where alternate_id = ?1 ; ";
    4.35  
    4.36 +// Revocation tracking
    4.37 +static const char *sql_add_mistrusted_key =
    4.38 +    "insert or replace into mistrusted_keys (fpr) "
    4.39 +    "   values (upper(replace(?1,' ',''))) ;";
    4.40 +        
    4.41 +static const char *sql_delete_mistrusted_key = 
    4.42 +    "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
    4.43 +
    4.44 +static const char *sql_is_mistrusted_key = 
    4.45 +    "select count(*) from mistrusted_keys where fpr = upper(replace(?1,' ','')) ;";
    4.46 +
    4.47  static const char *sql_add_userid_alias =
    4.48      "insert or replace into alternate_user_id (default_id, alternate_id) "
    4.49      "values (?1, ?2) ;";
    4.50 @@ -468,7 +491,7 @@
    4.51      sqlite3_busy_timeout(_session->system_db, 1000);
    4.52  
    4.53  // increment this when patching DDL
    4.54 -#define _DDL_USER_VERSION "6"
    4.55 +#define _DDL_USER_VERSION "7"
    4.56  
    4.57      if (in_first) {
    4.58  
    4.59 @@ -515,7 +538,8 @@
    4.60                  "       on delete set null,\n"
    4.61                  "   lang text,\n"
    4.62                  "   comment text,\n"
    4.63 -                "   device_group text\n"
    4.64 +                "   device_group text,\n"
    4.65 +                "   is_pep_user integer default 0\n"
    4.66                  ");\n"
    4.67                  "create table if not exists identity (\n"
    4.68                  "   address text,\n"
    4.69 @@ -564,6 +588,10 @@
    4.70                  "       on delete cascade on update cascade,\n"
    4.71                  "    alternate_id text primary key\n"
    4.72                  ");\n"
    4.73 +                // mistrusted keys
    4.74 +                "create table if not exists mistrusted_keys (\n"
    4.75 +                "    fpr text primary key\n"
    4.76 +                ");\n"
    4.77                  ,
    4.78              NULL,
    4.79              NULL,
    4.80 @@ -600,8 +628,11 @@
    4.81          // is really necessary...
    4.82          if (version == 1) {
    4.83              bool version_changed = true;
    4.84 -            
    4.85 -            if (table_contains_column(_session, "identity", "is_own") > 0) {
    4.86 +
    4.87 +            if (table_contains_column(_session, "person", "is_pep_user") > 0) {
    4.88 +                version = 7;
    4.89 +            }            
    4.90 +            else if (table_contains_column(_session, "identity", "is_own") > 0) {
    4.91                  version = 6;
    4.92              }
    4.93              else if (table_contains_column(_session, "sequences", "own") > 0) {
    4.94 @@ -777,7 +808,45 @@
    4.95                  );
    4.96                  assert(int_result == SQLITE_OK);    
    4.97              }
    4.98 -        }
    4.99 +            if (version < 7) {
   4.100 +                int_result = sqlite3_exec(
   4.101 +                    _session->db,
   4.102 +                    "alter table person\n"
   4.103 +                    "   add column is_pep_user integer default 0;\n",
   4.104 +                    NULL,
   4.105 +                    NULL,
   4.106 +                    NULL
   4.107 +                );
   4.108 +                assert(int_result == SQLITE_OK);
   4.109 +                int_result = sqlite3_exec(
   4.110 +                    _session->db,
   4.111 +                    "update person\n"
   4.112 +                    "   set is_pep_user = 1\n"
   4.113 +                    "   where id = "
   4.114 +                    "       (select distinct id from person "
   4.115 +                    "               join trust on id = user_id "
   4.116 +                    "               where (case when (comm_type = 127) then (id) "
   4.117 +                    "                           when (comm_type = 255) then (id) "
   4.118 +                    "                           else 0"
   4.119 +                    "                      end) = id );\n",
   4.120 +                    NULL,
   4.121 +                    NULL,
   4.122 +                    NULL
   4.123 +                );
   4.124 +                assert(int_result == SQLITE_OK);
   4.125 +                
   4.126 +                int_result = sqlite3_exec(
   4.127 +                    _session->db,
   4.128 +                    "create table if not exists mistrusted_keys (\n"
   4.129 +                    "    fpr text primary key\n"
   4.130 +                    ");\n",            
   4.131 +                    NULL,
   4.132 +                    NULL,
   4.133 +                    NULL
   4.134 +                );
   4.135 +                assert(int_result == SQLITE_OK);    
   4.136 +            }
   4.137 +        }        
   4.138          else { 
   4.139              // Version from DB was 0, it means this is initial setup.
   4.140              // DB has just been created, and all tables are empty.
   4.141 @@ -870,6 +939,18 @@
   4.142              (int)strlen(sql_set_person), &_session->set_person, NULL);
   4.143      assert(int_result == SQLITE_OK);
   4.144  
   4.145 +    int_result = sqlite3_prepare_v2(_session->db, sql_set_as_pep_user,
   4.146 +            (int)strlen(sql_set_as_pep_user), &_session->set_as_pep_user, NULL);
   4.147 +    assert(int_result == SQLITE_OK);
   4.148 +    
   4.149 +    int_result = sqlite3_prepare_v2(_session->db, sql_is_pep_user,
   4.150 +            (int)strlen(sql_is_pep_user), &_session->is_pep_user, NULL);
   4.151 +    assert(int_result == SQLITE_OK);
   4.152 +
   4.153 +    int_result = sqlite3_prepare_v2(_session->db, sql_exists_person,
   4.154 +            (int)strlen(sql_exists_person), &_session->exists_person, NULL);
   4.155 +    assert(int_result == SQLITE_OK);
   4.156 +
   4.157      int_result = sqlite3_prepare_v2(_session->db, sql_set_device_group,
   4.158              (int)strlen(sql_set_device_group), &_session->set_device_group, NULL);
   4.159      assert(int_result == SQLITE_OK);
   4.160 @@ -1000,6 +1081,18 @@
   4.161              (int)strlen(sql_get_revoked), &_session->get_revoked, NULL);
   4.162      assert(int_result == SQLITE_OK);
   4.163      
   4.164 +    int_result = sqlite3_prepare_v2(_session->db, sql_add_mistrusted_key,
   4.165 +            (int)strlen(sql_add_mistrusted_key), &_session->add_mistrusted_key, NULL);
   4.166 +    assert(int_result == SQLITE_OK);
   4.167 +
   4.168 +    int_result = sqlite3_prepare_v2(_session->db, sql_delete_mistrusted_key,
   4.169 +            (int)strlen(sql_delete_mistrusted_key), &_session->delete_mistrusted_key, NULL);
   4.170 +    assert(int_result == SQLITE_OK);
   4.171 +
   4.172 +    int_result = sqlite3_prepare_v2(_session->db, sql_is_mistrusted_key,
   4.173 +            (int)strlen(sql_is_mistrusted_key), &_session->is_mistrusted_key, NULL);
   4.174 +    assert(int_result == SQLITE_OK);
   4.175 +    
   4.176      status = init_cryptotech(_session, in_first);
   4.177      if (status != PEP_STATUS_OK)
   4.178          goto pep_error;
   4.179 @@ -1096,6 +1189,12 @@
   4.180                  sqlite3_finalize(session->remove_fpr_as_default);            
   4.181              if (session->set_person)
   4.182                  sqlite3_finalize(session->set_person);
   4.183 +            if (session->set_as_pep_user)
   4.184 +                sqlite3_finalize(session->set_as_pep_user);
   4.185 +            if (session->is_pep_user)
   4.186 +                sqlite3_finalize(session->is_pep_user);
   4.187 +            if (session->exists_person)
   4.188 +                sqlite3_finalize(session->exists_person);                        
   4.189              if (session->set_device_group)
   4.190                  sqlite3_finalize(session->set_device_group);
   4.191              if (session->get_device_group)
   4.192 @@ -1159,6 +1258,13 @@
   4.193              if (session->get_revoked)
   4.194                  sqlite3_finalize(session->get_revoked);
   4.195  
   4.196 +            if (session->add_mistrusted_key)
   4.197 +                sqlite3_finalize(session->add_mistrusted_key);
   4.198 +            if (session->delete_mistrusted_key)
   4.199 +                sqlite3_finalize(session->delete_mistrusted_key);
   4.200 +            if (session->is_mistrusted_key)
   4.201 +                sqlite3_finalize(session->is_mistrusted_key);
   4.202 +
   4.203              if (session->db)
   4.204                  sqlite3_close_v2(session->db);
   4.205              if (session->system_db)
   4.206 @@ -1824,6 +1930,18 @@
   4.207          assert(identity->lang[2] == 0);
   4.208      }
   4.209  
   4.210 +    if (has_fpr) {
   4.211 +        sqlite3_reset(session->set_pgp_keypair);
   4.212 +        sqlite3_bind_text(session->set_pgp_keypair, 1, identity->fpr, -1,
   4.213 +                SQLITE_STATIC);
   4.214 +        result = sqlite3_step(session->set_pgp_keypair);
   4.215 +        sqlite3_reset(session->set_pgp_keypair);
   4.216 +        if (result != SQLITE_DONE) {
   4.217 +            sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   4.218 +            return PEP_CANNOT_SET_PGP_KEYPAIR;
   4.219 +        }
   4.220 +    }
   4.221 +
   4.222      sqlite3_reset(session->set_person);
   4.223      sqlite3_bind_text(session->set_person, 1, identity->user_id, -1,
   4.224              SQLITE_STATIC);
   4.225 @@ -1843,18 +1961,6 @@
   4.226          return PEP_CANNOT_SET_PERSON;
   4.227      }
   4.228  
   4.229 -    if (has_fpr) {
   4.230 -        sqlite3_reset(session->set_pgp_keypair);
   4.231 -        sqlite3_bind_text(session->set_pgp_keypair, 1, identity->fpr, -1,
   4.232 -                SQLITE_STATIC);
   4.233 -        result = sqlite3_step(session->set_pgp_keypair);
   4.234 -        sqlite3_reset(session->set_pgp_keypair);
   4.235 -        if (result != SQLITE_DONE) {
   4.236 -            sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   4.237 -            return PEP_CANNOT_SET_PGP_KEYPAIR;
   4.238 -        }
   4.239 -    }
   4.240 -
   4.241      sqlite3_reset(session->set_identity);
   4.242      sqlite3_bind_text(session->set_identity, 1, identity->address, -1,
   4.243              SQLITE_STATIC);
   4.244 @@ -1893,6 +1999,146 @@
   4.245          return PEP_COMMIT_FAILED;
   4.246  }
   4.247  
   4.248 +// This ONLY sets the user flag, and creates a shell identity if necessary.
   4.249 +PEP_STATUS set_as_pep_user(PEP_SESSION session, pEp_identity* user) {
   4.250 +
   4.251 +    assert(session);
   4.252 +    assert(user);
   4.253 +    assert(user->address);
   4.254 +    assert(!EMPTYSTR(user->user_id));
   4.255 +    
   4.256 +    char* user_id = user->user_id;
   4.257 +    
   4.258 +    if (!session || !user || user->address || EMPTYSTR(user_id))
   4.259 +        return PEP_ILLEGAL_VALUE;
   4.260 +            
   4.261 +    PEP_STATUS status = PEP_STATUS_OK;
   4.262 +    
   4.263 +    char* alias_default = NULL;
   4.264 +    
   4.265 +    bool person_exists = false;
   4.266 +    
   4.267 +    status = exists_person(session, user_id, &alias_default, &person_exists);
   4.268 +    
   4.269 +    if (status != PEP_STATUS_OK)
   4.270 +        return status;
   4.271 +        
   4.272 +    if (!person_exists) {
   4.273 +        if (!user->address)
   4.274 +            return PEP_ILLEGAL_VALUE;
   4.275 +            
   4.276 +        // create shell identity
   4.277 +        pEp_identity* tmp_id = new_identity(user->address, NULL, user->user_id, user->username);
   4.278 +        status = set_identity(session, tmp_id); // this creates the person
   4.279 +        free_identity(tmp_id);
   4.280 +        if (status != PEP_STATUS_OK)
   4.281 +            return status;
   4.282 +        alias_default = strdup(user->user_id);
   4.283 +    }
   4.284 +        
   4.285 +    // Ok, let's set it.
   4.286 +    sqlite3_reset(session->set_as_pep_user);
   4.287 +    sqlite3_bind_text(session->set_as_pep_user, 1, alias_default, -1,
   4.288 +            SQLITE_STATIC);
   4.289 +    int result = sqlite3_step(session->set_as_pep_user);
   4.290 +    sqlite3_reset(session->set_as_pep_user);
   4.291 +    
   4.292 +    if (result != SQLITE_DONE)
   4.293 +        return PEP_CANNOT_SET_PERSON;
   4.294 +        
   4.295 +    return PEP_STATUS_OK;    
   4.296 +}
   4.297 +
   4.298 +PEP_STATUS exists_person(PEP_SESSION session, const char* user_id,
   4.299 +                         char** default_id, bool* exists) {
   4.300 +    assert(session);
   4.301 +    assert(exists);
   4.302 +    assert(!EMPTYSTR(user_id));
   4.303 +        
   4.304 +    if (!session || !exists || EMPTYSTR(user_id))
   4.305 +        return PEP_ILLEGAL_VALUE;
   4.306 +    
   4.307 +    *exists = false;
   4.308 +    
   4.309 +    char* alias_default = NULL;
   4.310 +    
   4.311 +    PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
   4.312 +    
   4.313 +    if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
   4.314 +        free(alias_default);
   4.315 +        alias_default = NULL;
   4.316 +        sqlite3_reset(session->exists_person);
   4.317 +        sqlite3_bind_text(session->exists_person, 1, user_id, -1,
   4.318 +                SQLITE_STATIC);
   4.319 +        int result = sqlite3_step(session->exists_person);
   4.320 +        switch (result) {
   4.321 +            case SQLITE_ROW: {
   4.322 +                // yeah yeah, I know, we could be lazy here, but it looks bad.
   4.323 +                *exists = (sqlite3_column_int(session->exists_person, 0) != 0);
   4.324 +                break;
   4.325 +            }
   4.326 +            default:
   4.327 +                return PEP_UNKNOWN_ERROR;
   4.328 +        }
   4.329 +        if (*exists)
   4.330 +            alias_default = strdup(user_id);
   4.331 +    }
   4.332 +    else
   4.333 +        *exists = true; // thank you, delete on cascade!
   4.334 +
   4.335 +    if (!default_id)
   4.336 +        free(alias_default);
   4.337 +    else    
   4.338 +        *default_id = alias_default;
   4.339 +    
   4.340 +    return PEP_STATUS_OK;
   4.341 +}
   4.342 +
   4.343 +PEP_STATUS is_pep_user(PEP_SESSION session, pEp_identity *identity, bool* is_pep)
   4.344 +{
   4.345 +    assert(session);
   4.346 +    assert(is_pep);
   4.347 +    assert(identity);
   4.348 +    assert(!EMPTYSTR(identity->user_id));
   4.349 +
   4.350 +    if (!session || !is_pep || !identity || EMPTYSTR(identity->user_id))
   4.351 +        return PEP_ILLEGAL_VALUE;
   4.352 +    
   4.353 +    *is_pep = false;
   4.354 +    
   4.355 +    const char* user_id = identity->user_id;
   4.356 +    
   4.357 +    if (!session || EMPTYSTR(user_id))
   4.358 +        return PEP_ILLEGAL_VALUE;
   4.359 +        
   4.360 +    char* alias_default = NULL;
   4.361 +    
   4.362 +    PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
   4.363 +    
   4.364 +    if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
   4.365 +        free(alias_default);
   4.366 +        alias_default = strdup(user_id);
   4.367 +    }
   4.368 +    
   4.369 +    sqlite3_reset(session->is_pep_user);
   4.370 +    sqlite3_bind_text(session->is_pep_user, 1, user_id, -1,
   4.371 +            SQLITE_STATIC);
   4.372 +    int result = sqlite3_step(session->is_pep_user);
   4.373 +    switch (result) {
   4.374 +        case SQLITE_ROW: {
   4.375 +            // yeah yeah, I know, we could be lazy here, but it looks bad.
   4.376 +            *is_pep = (sqlite3_column_int(session->is_pep_user, 0) != 0);
   4.377 +            break;
   4.378 +        }
   4.379 +        default:
   4.380 +            free(alias_default);
   4.381 +            return PEP_CANNOT_FIND_PERSON;
   4.382 +    }
   4.383 +
   4.384 +    return PEP_STATUS_OK;
   4.385 +}
   4.386 +
   4.387 +
   4.388  PEP_STATUS remove_fpr_as_default(PEP_SESSION session, 
   4.389                                   const char* fpr) 
   4.390  {
     5.1 --- a/src/pEpEngine.h	Mon Jan 29 16:52:54 2018 +0100
     5.2 +++ b/src/pEpEngine.h	Sun Feb 04 15:26:28 2018 +0100
     5.3 @@ -1231,6 +1231,21 @@
     5.4  
     5.5  PEP_STATUS import_trusted_own_keys(PEP_SESSION session);
     5.6  
     5.7 +// This ONLY sets the *user* flag, and creates a shell identity if necessary.
     5.8 +PEP_STATUS set_as_pep_user(PEP_SESSION session, pEp_identity* user);
     5.9 +
    5.10 +// returns true (by reference) if a person with this user_id exists; if default_id != NULL,
    5.11 +// function will also return by reference a copy of the default id which
    5.12 +// is this user_id is aliased to (which will usually, but not always, 
    5.13 +// string equivalent to the user_id)
    5.14 +PEP_STATUS exists_person(PEP_SESSION session, const char* user_id,
    5.15 +                         char** default_id, bool* exists);
    5.16 +
    5.17 +// returns true if the USER corresponding to this identity has been listed in
    5.18 +// the *person* table as a pEp user. This *does not check comm_type*                         
    5.19 +PEP_STATUS is_pep_user(PEP_SESSION session, pEp_identity *identity, bool* is_pep);
    5.20 +
    5.21 +
    5.22  #ifdef __cplusplus
    5.23  }
    5.24  #endif
     6.1 --- a/src/pEp_internal.h	Mon Jan 29 16:52:54 2018 +0100
     6.2 +++ b/src/pEp_internal.h	Sun Feb 04 15:26:28 2018 +0100
     6.3 @@ -131,6 +131,9 @@
     6.4      sqlite3_stmt *refresh_userid_default_key;
     6.5      sqlite3_stmt *remove_fpr_as_default;
     6.6      sqlite3_stmt *set_person;
     6.7 +    sqlite3_stmt *set_as_pep_user;
     6.8 +    sqlite3_stmt *is_pep_user;
     6.9 +    sqlite3_stmt *exists_person;
    6.10      sqlite3_stmt *set_device_group;
    6.11      sqlite3_stmt *get_device_group;
    6.12      sqlite3_stmt *set_pgp_keypair;
    6.13 @@ -173,6 +176,11 @@
    6.14      sqlite3_stmt *set_revoked;
    6.15      sqlite3_stmt *get_revoked;
    6.16  
    6.17 +    // mistrusted
    6.18 +    sqlite3_stmt* add_mistrusted_key;
    6.19 +    sqlite3_stmt* is_mistrusted_key;    
    6.20 +    sqlite3_stmt* delete_mistrusted_key;
    6.21 +    
    6.22      // aliases
    6.23      sqlite3_stmt *get_userid_alias_default;
    6.24      sqlite3_stmt *add_userid_alias;
    6.25 @@ -405,8 +413,8 @@
    6.26  // These are globals used in generating message IDs and should only be
    6.27  // computed once, as they're either really constants or OS-dependent
    6.28  
    6.29 -int _pEp_rand_max_bits;
    6.30 -double _pEp_log2_36;
    6.31 +extern int _pEp_rand_max_bits;
    6.32 +extern double _pEp_log2_36;
    6.33  
    6.34  static inline void _init_globals() {
    6.35      _pEp_rand_max_bits = ceil(log2(RAND_MAX));
     7.1 --- a/test/mistrust_undo_test.cc	Mon Jan 29 16:52:54 2018 +0100
     7.2 +++ b/test/mistrust_undo_test.cc	Sun Feb 04 15:26:28 2018 +0100
     7.3 @@ -58,8 +58,12 @@
     7.4      assert(status == PEP_STATUS_OK);
     7.5      status = update_identity(session,recip1);
     7.6      assert(status == PEP_STATUS_OK);
     7.7 +    assert(recip1->comm_type == PEP_ct_key_not_found);
     7.8 +    recip1->fpr = strdup("BACC7A60A88A39A25D99B4A545D7542F39E5DAB5");
     7.9 +    status = get_trust(session, recip1);
    7.10      assert(recip1->comm_type == PEP_ct_mistrusted);
    7.11 -    cout << "Mistrusted mistrust.undo.test@pep-project.org (BACC7A60A88A39A25D99B4A545D7542F39E5DAB5) and comm_type set to PEP_ct_mistrusted)." << endl  << endl;    
    7.12 +     
    7.13 +    cout << "Mistrusted mistrust.undo.test@pep-project.org (BACC7A60A88A39A25D99B4A545D7542F39E5DAB5) and comm_type IN DB set to PEP_ct_mistrusted)." << endl  << endl;    
    7.14      
    7.15      cout << "Undo mistrust (restore identity and trust in DB)" << endl;
    7.16      // Undo it
     8.1 --- a/test/new_update_id_and_myself_test.cc	Mon Jan 29 16:52:54 2018 +0100
     8.2 +++ b/test/new_update_id_and_myself_test.cc	Sun Feb 04 15:26:28 2018 +0100
     8.3 @@ -38,7 +38,7 @@
     8.4      
     8.5      cout << uniqname << "\n";
     8.6      
     8.7 -    const char* own_user_id = "FineOwnIdentitiesOfBuckTFerris";
     8.8 +    const char* own_user_id = get_new_uuid();
     8.9      const char* start_username = "Unser Testkandidat";
    8.10  
    8.11      pEp_identity * new_me = new_identity(uniqname, NULL, own_user_id, start_username);
    8.12 @@ -481,28 +481,130 @@
    8.13  
    8.14  
    8.15      cout << "****************************************************************************************" << endl;
    8.16 -    cout << "* III: 2. key election: get identity for user with only revoked keys " << endl;
    8.17 +    cout << "* III: 2. key election: get identity for user with only revoked or mistrusted keys " << endl;
    8.18      cout << "****************************************************************************************" << endl << endl;
    8.19 +
    8.20 +    // Create id with no key
    8.21 +    cout << "Creating new id with no key for : ";
    8.22 +    char *uniqname_10000 = strdup("AAAAtestuser@testdomain.org");
    8.23 +    srandom(time(NULL));
    8.24 +    for(int i=0; i < 4;i++)
    8.25 +        uniqname_10000[i] += random() & 0xf;
    8.26      
    8.27 -    status = revoke_key(session, new_fpr, "Because it's more fun to revoke ALL of someone's keys");
    8.28 +    cout << uniqname_10000 << "\n";
    8.29 +
    8.30 +    char* revoke_uuid = get_new_uuid();
    8.31 +
    8.32 +    pEp_identity * revokemaster_3000 = new_identity(uniqname_10000, NULL, revoke_uuid, start_username);
    8.33 +    
    8.34 +    cout << "Generate three keys for "  << uniqname_10000 << " who has user_id " << revoke_uuid << endl; 
    8.35 +
    8.36 +    char* revoke_fpr_arr[3];
    8.37 +    
    8.38 +    status = generate_keypair(session, revokemaster_3000);
    8.39 +    assert(status == PEP_STATUS_OK && revokemaster_3000->fpr);
    8.40 +    revoke_fpr_arr[0] = strdup(revokemaster_3000->fpr);
    8.41 +    free(revokemaster_3000->fpr);
    8.42 +    revokemaster_3000->fpr = NULL;
    8.43 +    
    8.44 +    status = generate_keypair(session, revokemaster_3000);
    8.45 +    assert(status == PEP_STATUS_OK && revokemaster_3000->fpr);
    8.46 +    revoke_fpr_arr[1] = strdup(revokemaster_3000->fpr);
    8.47 +    free(revokemaster_3000->fpr);
    8.48 +    revokemaster_3000->fpr = NULL;
    8.49 +    
    8.50 +    status = generate_keypair(session, revokemaster_3000);
    8.51 +    assert(status == PEP_STATUS_OK && revokemaster_3000->fpr);
    8.52 +    revoke_fpr_arr[2] = strdup(revokemaster_3000->fpr);
    8.53 +    free(revokemaster_3000->fpr);
    8.54 +    revokemaster_3000->fpr = NULL;
    8.55 +    
    8.56 +    cout << "Trust "  << revoke_fpr_arr[2] << " (default for identity) and " << revoke_fpr_arr[0] << endl;
    8.57 +    
    8.58 +    free(revokemaster_3000->fpr);
    8.59 +    revokemaster_3000->fpr = strdup(revoke_fpr_arr[2]);
    8.60 +    status = trust_personal_key(session, revokemaster_3000);
    8.61 +    assert(status == PEP_STATUS_OK); 
    8.62 +    assert(revokemaster_3000->comm_type & PEP_ct_confirmed);
    8.63 +
    8.64 +    free(revokemaster_3000->fpr);
    8.65 +    revokemaster_3000->fpr = strdup(revoke_fpr_arr[0]);
    8.66 +    status = trust_personal_key(session, revokemaster_3000);
    8.67 +    assert(status == PEP_STATUS_OK);
    8.68 +    assert(revokemaster_3000->comm_type & PEP_ct_confirmed);
    8.69 +    
    8.70 +    status = update_identity(session, revokemaster_3000);
    8.71 +    assert(status == PEP_STATUS_OK);
    8.72 +    assert(revokemaster_3000->fpr);
    8.73 +    assert(strcmp(revokemaster_3000->fpr, revoke_fpr_arr[2]) == 0);
    8.74 +    assert(revokemaster_3000->comm_type & PEP_ct_confirmed);
    8.75 +
    8.76 +    cout << "update_identity returns the correct identity default." << endl;
    8.77 +    
    8.78 +    cout << "Ok, now... we revoke the default..." << endl;
    8.79 +    
    8.80 +    cout << "Revoking " << revoke_fpr_arr[2] << endl;
    8.81 +
    8.82 +    status = revoke_key(session, revoke_fpr_arr[2], "This little pubkey went to market");
    8.83      assert (status == PEP_STATUS_OK);
    8.84 +
    8.85 +    bool is_revoked;
    8.86 +    status = key_revoked(session, revokemaster_3000->fpr, &is_revoked);    
    8.87 +    assert(status == PEP_STATUS_OK);
    8.88 +    assert(is_revoked);
    8.89 +
    8.90 +    cout << "Success revoking " << revoke_fpr_arr[2] << "!!! get_trust for this fpr gives us " << revokemaster_3000->comm_type << endl;
    8.91      
    8.92 -    new_me = new_identity(uniqname, NULL, NULL, NULL);
    8.93 +    cout << "Now see if update_identity gives us " << revoke_fpr_arr[0] << ", the only trusted key left." << endl;
    8.94 +    status = update_identity(session, revokemaster_3000);
    8.95 +    assert(status == PEP_STATUS_OK);
    8.96 +    assert(revokemaster_3000->fpr);
    8.97 +    assert(strcmp(revokemaster_3000->fpr, revoke_fpr_arr[0]) == 0);
    8.98 +    assert(revokemaster_3000->comm_type & PEP_ct_confirmed);    
    8.99      
   8.100 -    status = update_identity(session, new_me);
   8.101 +    cout << "Success! So let's mistrust it, because seriously, that key was so uncool." << endl;
   8.102 +    
   8.103 +    status = key_mistrusted(session, revokemaster_3000);
   8.104 +    assert(status == PEP_STATUS_OK);
   8.105 +
   8.106 +    status = get_trust(session, revokemaster_3000);
   8.107 +    assert(status == PEP_STATUS_OK);
   8.108 +    assert(revokemaster_3000->comm_type == PEP_ct_mistrusted);
   8.109 +    
   8.110 +    cout << "Success! get_trust for this fpr gives us " << revokemaster_3000->comm_type << endl;
   8.111 +
   8.112 +    cout << "The only fpr left is an untrusted one - let's make sure this is what we get from update_identity." << endl;
   8.113 +
   8.114 +    status = update_identity(session, revokemaster_3000);
   8.115 +    assert(status == PEP_STATUS_OK);
   8.116 +    assert(revokemaster_3000->fpr);
   8.117 +    assert(strcmp(revokemaster_3000->fpr, revoke_fpr_arr[1]) == 0);
   8.118 +    assert(!(revokemaster_3000->comm_type & PEP_ct_confirmed));    
   8.119 +
   8.120 +    cout << "Success! We got " << revoke_fpr_arr[1] << "as the fpr with comm_type " << revokemaster_3000->comm_type << endl;
   8.121 +    
   8.122 +    cout << "But, you know... let's revoke that one too and see what update_identity gives us." << endl;
   8.123 +
   8.124 +    status = revoke_key(session, revoke_fpr_arr[1], "Because it's more fun to revoke ALL of someone's keys");
   8.125 +    assert (status == PEP_STATUS_OK);
   8.126 +
   8.127 +    status = key_revoked(session, revokemaster_3000->fpr, &is_revoked);    
   8.128 +    assert(status == PEP_STATUS_OK);
   8.129 +    assert(is_revoked);
   8.130 +    
   8.131 +    cout << "Success! get_trust for this fpr gives us " << revokemaster_3000->comm_type << endl;
   8.132 +
   8.133 +    cout << "Call update_identity - we expect nothing, plus an error comm type." << endl;
   8.134 +
   8.135 +    status = update_identity(session, revokemaster_3000);
   8.136      assert(status != PEP_STATUS_OK);
   8.137 -    assert(!new_me->fpr);
   8.138 -    assert(new_me->username);
   8.139 -    assert(strcmp(new_me->username, start_username) == 0);
   8.140 -    assert(new_me->user_id);
   8.141 -    assert(strcmp(new_me->user_id, default_own_id) == 0);
   8.142 -    assert(new_me->me);
   8.143 -    assert(new_me->comm_type == PEP_ct_key_revoked);
   8.144 -    
   8.145 -    cout << "PASS: update_identity() correctly rejected two revoked keys with PEP_KEY_UNSUITABLE and PEP_ct_key_revoked";
   8.146 -    cout << endl << endl;
   8.147 +    assert(!revokemaster_3000->fpr);
   8.148 +    assert(revokemaster_3000->username);
   8.149 +    assert(strcmp(revokemaster_3000->user_id, revoke_uuid) == 0);
   8.150 +    assert(revokemaster_3000->comm_type == PEP_ct_key_not_found);
   8.151 +    cout << "Success! No key found. The comm_status error was " << revokemaster_3000->comm_type << "and the return status was " << tl_status_string(status) << endl;
   8.152  
   8.153 -    free_identity(new_me);
   8.154 +    free_identity(revokemaster_3000);
   8.155  
   8.156      cout << "****************************************************************************************" << endl;
   8.157      cout << "* III: 100000000. key election: more to come " << endl;
     9.1 --- a/test/pEpEngineTest.cc	Mon Jan 29 16:52:54 2018 +0100
     9.2 +++ b/test/pEpEngineTest.cc	Sun Feb 04 15:26:28 2018 +0100
     9.3 @@ -32,7 +32,7 @@
     9.4          return sstr.str();
     9.5  }
     9.6  
     9.7 -// no C++11, yet? So do our own implementation:
     9.8 +// no C++11, yet? So do our own implementation:1G
     9.9  namespace{
    9.10      std::string to_string(unsigned long u)
    9.11      {
    9.12 @@ -270,6 +270,7 @@
    9.13  
    9.14      cout << "\nsetting identity...\n";
    9.15      PEP_STATUS pep_set_result = set_identity(session, identity);
    9.16 +    cout << pep_set_result << endl;
    9.17      assert(pep_set_result == PEP_STATUS_OK);
    9.18      free_identity(identity);
    9.19      get_identity(session, "leon.schumacher@digitalekho.com", "23", &identity);