Merged in ENGINE-332 and friends
authorKrista Bennett <krista@pep-project.org>
Thu, 25 Jan 2018 02:39:57 +0100
changeset 2448b51c2cbb5bf8
parent 2443 154269655c12
parent 2447 b817f153633c
child 2450 719ec5a51303
Merged in ENGINE-332 and friends
     1.1 --- a/src/keymanagement.c	Wed Jan 24 16:06:50 2018 +0100
     1.2 +++ b/src/keymanagement.c	Thu Jan 25 02:39:57 2018 +0100
     1.3 @@ -15,13 +15,8 @@
     1.4  #include "sync_fsm.h"
     1.5  #include "blacklist.h"
     1.6  
     1.7 -#ifndef EMPTYSTR
     1.8 -#define EMPTYSTR(STR) ((STR) == NULL || (STR)[0] == '\0')
     1.9 -#endif
    1.10 -
    1.11  #define KEY_EXPIRE_DELTA (60 * 60 * 24 * 365)
    1.12  
    1.13 -
    1.14  static bool key_matches_address(PEP_SESSION session, const char* address,
    1.15                                  const char* fpr) {
    1.16      if (!session || !address || !fpr)
    1.17 @@ -1056,7 +1051,16 @@
    1.18          if (session->cached_mistrusted)
    1.19              free(session->cached_mistrusted);
    1.20          session->cached_mistrusted = identity_dup(ident);
    1.21 -        status = mark_as_compromized(session, ident->fpr);
    1.22 +        
    1.23 +        // set mistrust for this user_id/keypair (even if there's not an
    1.24 +        // identity set yet, this is important, as we need to record the mistrust
    1.25 +        // action)
    1.26 +        status = set_trust(session, ident->user_id, ident->fpr, PEP_ct_mistrusted);
    1.27 +        if (status == PEP_STATUS_OK)
    1.28 +            // cascade that mistrust for anyone using this key
    1.29 +            status = mark_as_compromized(session, ident->fpr);
    1.30 +        if (status == PEP_STATUS_OK)
    1.31 +            status = remove_fpr_as_default(session, ident->fpr);
    1.32      }
    1.33  
    1.34      return status;
    1.35 @@ -1093,42 +1097,70 @@
    1.36  
    1.37      assert(session);
    1.38      assert(ident);
    1.39 -    assert(!ident->me);
    1.40      assert(!EMPTYSTR(ident->fpr));
    1.41      assert(!EMPTYSTR(ident->address));
    1.42      assert(!EMPTYSTR(ident->user_id));
    1.43  
    1.44 -    // Nope. We should be able to reset trust on an own key.
    1.45      if (!(session && ident && ident->fpr && ident->fpr[0] != '\0' && ident->address &&
    1.46              ident->user_id))
    1.47          return PEP_ILLEGAL_VALUE;
    1.48 -        
    1.49 -    bool me = is_me(session, ident); 
    1.50  
    1.51 -    if (me)
    1.52 -        status = myself(session, ident);
    1.53 -    else     
    1.54 -        status = update_identity(session, ident);
    1.55 -        
    1.56 -    if (status != PEP_STATUS_OK)
    1.57 -        return status;
    1.58 -
    1.59 -    if (ident->comm_type == PEP_ct_mistrusted)
    1.60 -        ident->comm_type = PEP_ct_unknown;
    1.61 -    else
    1.62 -        ident->comm_type &= ~PEP_ct_confirmed;
    1.63 -
    1.64 -    status = set_identity(session, ident);
    1.65 +    // we do not change the input struct at ALL.
    1.66 +    pEp_identity* input_copy = identity_dup(ident);
    1.67      
    1.68 -    // FIXME: remove key as default for user_id
    1.69 +    pEp_identity* tmp_ident = NULL;
    1.70 +    
    1.71 +    status = get_trust(session, input_copy);
    1.72      
    1.73      if (status != PEP_STATUS_OK)
    1.74 -        return status;
    1.75 +        goto pep_free;
    1.76 +        
    1.77 +    PEP_comm_type new_trust = PEP_ct_unknown;
    1.78  
    1.79 -    // FIXME: What is this point of this here??
    1.80 -    if (ident->comm_type == PEP_ct_unknown && !me) {
    1.81 -        status = update_identity(session, ident);
    1.82 +    if (input_copy->comm_type != PEP_ct_mistrusted)
    1.83 +        new_trust = input_copy->comm_type & ~PEP_ct_confirmed;
    1.84 +
    1.85 +    status = set_trust(session, ident->user_id, ident->fpr, new_trust);
    1.86 +    
    1.87 +    if (status != PEP_STATUS_OK)
    1.88 +        goto pep_free;
    1.89 +
    1.90 +        
    1.91 +    input_copy->comm_type = new_trust;
    1.92 +        
    1.93 +    tmp_ident = new_identity(ident->address, NULL, ident->user_id, NULL);
    1.94 +
    1.95 +    if (!tmp_ident)
    1.96 +        return PEP_OUT_OF_MEMORY;
    1.97 +    
    1.98 +    status = update_identity(session, tmp_ident);
    1.99 +    
   1.100 +    if (status != PEP_STATUS_OK)
   1.101 +        goto pep_free;
   1.102 +    
   1.103 +    // remove as default if necessary
   1.104 +    if (strcmp(tmp_ident->fpr, ident->fpr) == 0) {
   1.105 +        free(tmp_ident->fpr);
   1.106 +        tmp_ident->fpr = NULL;
   1.107 +        tmp_ident->comm_type = PEP_ct_unknown;
   1.108 +        status = set_identity(session, tmp_ident);
   1.109 +        if (status != PEP_STATUS_OK)
   1.110 +            goto pep_free;
   1.111      }
   1.112 +    
   1.113 +    char* user_default = NULL;
   1.114 +    status = get_main_user_fpr(session, tmp_ident->user_id, &user_default);
   1.115 +    
   1.116 +    if (!EMPTYSTR(user_default)) {
   1.117 +        if (strcmp(user_default, ident->fpr) == 0)
   1.118 +            status = refresh_userid_default_key(session, ident->user_id);
   1.119 +        if (status != PEP_STATUS_OK)
   1.120 +            goto pep_free;    
   1.121 +    }
   1.122 +            
   1.123 +pep_free:
   1.124 +    free_identity(tmp_ident);
   1.125 +    free_identity(input_copy);
   1.126      return status;
   1.127  }
   1.128  
   1.129 @@ -1149,39 +1181,99 @@
   1.130              EMPTYSTR(ident->fpr))
   1.131          return PEP_ILLEGAL_VALUE;
   1.132  
   1.133 +    //bool ident_has_trusted_default = false;
   1.134 +    char* ident_default_fpr = NULL;
   1.135 +
   1.136 +    // Before we do anything, be sure the input fpr is even eligible to be trusted
   1.137 +    PEP_comm_type input_default_ct = PEP_ct_unknown;
   1.138 +    status = get_key_rating(session, ident->fpr, &input_default_ct);
   1.139 +    if (input_default_ct < PEP_ct_strong_but_unconfirmed)
   1.140 +        return PEP_KEY_UNSUITABLE;
   1.141 +
   1.142 +    // Save the input fpr
   1.143 +    char* cached_fpr = strdup(ident->fpr);
   1.144 +    ident->fpr = NULL;
   1.145 +
   1.146      bool me = is_me(session, ident);
   1.147  
   1.148      if (me)
   1.149 -        status = myself(session, ident);
   1.150 -    else {
   1.151 -        char* saved_fpr = ident->fpr;
   1.152 -        ident->fpr = NULL;
   1.153 +        return myself(session, ident); // FIXME: Not the right thing if we 
   1.154 +                                       // don't always replace user default!!!
   1.155 +
   1.156 +    // First, set up a temp trusted identity for the input fpr without a comm type;
   1.157 +    pEp_identity* tmp_id = new_identity(ident->address, cached_fpr, ident->user_id, NULL);
   1.158 +    status = validate_fpr(session, tmp_id);
   1.159          
   1.160 +    if (status == PEP_STATUS_OK) {
   1.161 +        // Validate fpr gets trust DB or, when that fails, key comm type. we checked
   1.162 +        // above that the key was ok. (not revoked or expired), but we want the max.
   1.163 +        tmp_id->comm_type = _MAX(tmp_id->comm_type, input_default_ct) | PEP_ct_confirmed;
   1.164 +                                       
   1.165 +        // Get the default identity without setting the fpr
   1.166          status = update_identity(session, ident);
   1.167 -        
   1.168 -        if (EMPTYSTR(ident->fpr) || strcmp(ident->fpr, saved_fpr) != 0) {
   1.169 -            ident->fpr = saved_fpr;
   1.170 -            ident->comm_type = PEP_ct_unknown;
   1.171 -            status = set_identity(session, ident);
   1.172 -            if (status == PEP_STATUS_OK)
   1.173 -                status = update_identity(session, ident);
   1.174 +        ident_default_fpr = strdup(ident->fpr);
   1.175 +
   1.176 +        if (status == PEP_STATUS_OK) {
   1.177 +            bool trusted_default = false;
   1.178 +
   1.179 +            // If there's no default, or the default is different from the input...
   1.180 +            if (EMPTYSTR(ident_default_fpr) || strcmp(cached_fpr, ident_default_fpr) != 0) {
   1.181 +                
   1.182 +                // If the default fpr (if there is one) is trusted and key is strong enough,
   1.183 +                // don't replace, we just set the trusted bit on this key for this user_id...
   1.184 +                // (If there's no default fpr, this won't be true anyway.)
   1.185 +                if (ident->comm_type >= PEP_ct_strong_but_unconfirmed && 
   1.186 +                    (ident->comm_type & PEP_ct_confirmed)) {                        
   1.187 +
   1.188 +                    trusted_default = true;
   1.189 +                                    
   1.190 +                    status = set_trust(session, tmp_id->user_id, cached_fpr, tmp_id->comm_type);
   1.191 +                    input_default_ct = tmp_id->comm_type;                    
   1.192 +                }
   1.193 +                else {
   1.194 +                    free(ident->fpr);
   1.195 +                    ident->fpr = strdup(cached_fpr);
   1.196 +                    ident->comm_type = tmp_id->comm_type;
   1.197 +                    status = set_identity(session, ident); // replace identity default            
   1.198 +                }
   1.199 +            }
   1.200 +            else { // we're setting this on the default fpr
   1.201 +                ident->comm_type = tmp_id->comm_type;
   1.202 +                status = set_identity(session, ident);
   1.203 +                trusted_default = true;
   1.204 +            }
   1.205 +            if (status == PEP_STATUS_OK && !trusted_default) {
   1.206 +                // Ok, there wasn't a trusted default, so we replaced. Thus, we also
   1.207 +                // make sure there's a trusted default on the user_id. If there
   1.208 +                // is not, we make this the default.
   1.209 +                char* user_default = NULL;
   1.210 +                status = get_main_user_fpr(session, ident->user_id, &user_default);
   1.211 +            
   1.212 +                if (status == PEP_STATUS_OK && user_default) {
   1.213 +                    pEp_identity* tmp_user_ident = new_identity(ident->address, 
   1.214 +                                                                user_default, 
   1.215 +                                                                ident->user_id, 
   1.216 +                                                                NULL);
   1.217 +                    if (!tmp_user_ident)
   1.218 +                        status = PEP_OUT_OF_MEMORY;
   1.219 +                    else {
   1.220 +                        status = validate_fpr(session, tmp_user_ident);
   1.221 +                        
   1.222 +                        if (status != PEP_STATUS_OK ||
   1.223 +                            tmp_user_ident->comm_type < PEP_ct_strong_but_unconfirmed ||
   1.224 +                            !(tmp_user_ident->comm_type & PEP_ct_confirmed)) 
   1.225 +                        {
   1.226 +                            char* trusted_fpr = (trusted_default ? ident_default_fpr : cached_fpr);
   1.227 +                            status = replace_main_user_fpr(session, ident->user_id, trusted_fpr);
   1.228 +                        } 
   1.229 +                    }
   1.230 +                }
   1.231 +            }
   1.232          }
   1.233 -        // either saved_fpr got copied in update_identity and we're done
   1.234 -        // with it, or it's not referenced anymore because we didn't call
   1.235 -        // it.
   1.236 -        free(saved_fpr);            
   1.237 -    } 
   1.238 -    if (status != PEP_STATUS_OK)
   1.239 -        return status;
   1.240 -
   1.241 -    if (ident->comm_type > PEP_ct_strong_but_unconfirmed) {
   1.242 -        ident->comm_type |= PEP_ct_confirmed;
   1.243 -        status = set_identity(session, ident);
   1.244 -    }
   1.245 -    else {
   1.246 -        // MISSING: S/MIME has to be handled depending on trusted CAs
   1.247 -        status = PEP_CANNOT_SET_TRUST;
   1.248 -    }
   1.249 +        free(ident_default_fpr);
   1.250 +        free(cached_fpr);
   1.251 +        free_identity(tmp_id);
   1.252 +    }    
   1.253  
   1.254      return status;
   1.255  }
     2.1 --- a/src/keymanagement.h	Wed Jan 24 16:06:50 2018 +0100
     2.2 +++ b/src/keymanagement.h	Thu Jan 25 02:39:57 2018 +0100
     2.3 @@ -189,6 +189,15 @@
     2.4  //  parameters:
     2.5  //      session (in)        session to use
     2.6  //      ident (in)          person and key which was compromised
     2.7 +//  caveat:
     2.8 +//      ident is INPUT ONLY. If you want updated trust on the identity, you'll have
     2.9 +//      to call update_identity or myself respectively after this.
    2.10 +//      N.B. If you are calling this on a key that is the identity or user default,
    2.11 +//      it will be removed as the default key for ANY identity and user for which
    2.12 +//      it is the default. Please keep in mind that the undo in undo_last_mistrust
    2.13 +//      will only undo the current identity's / it's user's default, not any
    2.14 +//      other identities which may be impacted (this will not affect most use
    2.15 +//      cases)
    2.16  
    2.17  DYNAMIC_API PEP_STATUS key_mistrusted(
    2.18          PEP_SESSION session,
    2.19 @@ -214,7 +223,7 @@
    2.20  DYNAMIC_API PEP_STATUS undo_last_mistrust(PEP_SESSION session);
    2.21  
    2.22  
    2.23 -// trust_personal_key() - mark a key as trusted with a person
    2.24 +// trust_personal_key() - mark a key as trusted for a user
    2.25  //
    2.26  //  parameters:
    2.27  //      session (in)        session to use
    2.28 @@ -222,6 +231,11 @@
    2.29  //
    2.30  //  caveat:
    2.31  //      the fields user_id, address and fpr must be supplied
    2.32 +//      for non-own users, this will 1) set the trust bit on its comm type in the DN,
    2.33 +//      2) set this key as the identity default if the current identity default
    2.34 +//      is not trusted, and 3) set this key as the user default if the current
    2.35 +//      user default is not trusted.
    2.36 +//      For an own user, this is simply a call to myself().
    2.37  
    2.38  DYNAMIC_API PEP_STATUS trust_personal_key(
    2.39          PEP_SESSION session,
    2.40 @@ -229,12 +243,18 @@
    2.41      );
    2.42  
    2.43  
    2.44 -// key_reset_trust() - undo trust_personal_key and key_mistrusted() for keys
    2.45 -//                     we don't own
    2.46 -//
    2.47 +// key_reset_trust() - reset trust bit or explicitly mistrusted status for an identity and
    2.48 +//                     its accompanying key/user_id pair.
    2.49  //  parameters:
    2.50  //      session (in)        session to use
    2.51 -//      ident (in)          person and key which was compromized
    2.52 +//      ident (in)          identity for person and key whose trust status is to be reset
    2.53 +//
    2.54 +//  caveat:
    2.55 +//      ident is INPUT ONLY. If you want updated trust on the identity, you'll have
    2.56 +//      to call update_identity or myself respectively after this.
    2.57 +//      N.B. If you are calling this on a key that is the identity or user default,
    2.58 +//      it will be removed as the default key for the identity and user (but is still
    2.59 +//      available for key election, it is just not the cached default anymore)
    2.60  
    2.61  DYNAMIC_API PEP_STATUS key_reset_trust(
    2.62          PEP_SESSION session,
     3.1 --- a/src/message_api.c	Wed Jan 24 16:06:50 2018 +0100
     3.2 +++ b/src/message_api.c	Thu Jan 25 02:39:57 2018 +0100
     3.3 @@ -2029,7 +2029,6 @@
     3.4              status = get_trust(session, _sender);
     3.5              if (_sender->comm_type == PEP_ct_unknown) {
     3.6                  get_key_rating(session, fpr, &_sender->comm_type);
     3.7 -                
     3.8              }
     3.9              if (_sender->comm_type != PEP_ct_unknown) {
    3.10                  *rating = keylist_rating(session, recipients, 
     4.1 --- a/src/pEpEngine.c	Wed Jan 24 16:06:50 2018 +0100
     4.2 +++ b/src/pEpEngine.c	Thu Jan 25 02:39:57 2018 +0100
     4.3 @@ -113,6 +113,27 @@
     4.4      "update person set id = ?1 " 
     4.5      "where id = ?2;";
     4.6  
     4.7 +static const char *sql_replace_main_user_fpr =  
     4.8 +    "update person "
     4.9 +    "   set main_key_id = ?1 "
    4.10 +    "   where id = ?2 ;";
    4.11 +
    4.12 +static const char *sql_get_main_user_fpr =  
    4.13 +    "select main_key_id from person"
    4.14 +    "   where id = ?1 ;";
    4.15 +
    4.16 +static const char *sql_refresh_userid_default_key =
    4.17 +    "update person "
    4.18 +    "   set main_key_id = "
    4.19 +    "       (select identity.main_key_id from identity "
    4.20 +    "           join trust on trust.user_id = identity.user_id "
    4.21 +    "               and trust.pgp_keypair_fpr = identity.main_key_id "
    4.22 +    "           join person on identity.user_id = identity.user_id "
    4.23 +    "       where identity.user_id = ?1 "
    4.24 +    "       order by trust.comm_type desc "
    4.25 +    "       limit 1) "
    4.26 +    "where id = ?1 ; ";
    4.27 +
    4.28  static const char *sql_get_device_group = 
    4.29      "select device_group from person "
    4.30      "where id = ?1;";
    4.31 @@ -175,7 +196,7 @@
    4.32  static const char *sql_mark_as_compromized = 
    4.33      "update trust not indexed set comm_type = 15"
    4.34      " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
    4.35 -
    4.36 +    
    4.37  static const char *sql_crashdump = 
    4.38      "select timestamp, title, entity, description, comment"
    4.39      " from log order by timestamp desc limit ?1 ;";
    4.40 @@ -823,6 +844,18 @@
    4.41              (int)strlen(sql_replace_userid), &_session->replace_userid, NULL);
    4.42      assert(int_result == SQLITE_OK);
    4.43  
    4.44 +    int_result = sqlite3_prepare_v2(_session->db, sql_replace_main_user_fpr,
    4.45 +            (int)strlen(sql_replace_main_user_fpr), &_session->replace_main_user_fpr, NULL);
    4.46 +    assert(int_result == SQLITE_OK);
    4.47 +
    4.48 +    int_result = sqlite3_prepare_v2(_session->db, sql_get_main_user_fpr,
    4.49 +            (int)strlen(sql_get_main_user_fpr), &_session->get_main_user_fpr, NULL);
    4.50 +    assert(int_result == SQLITE_OK);
    4.51 +
    4.52 +    int_result = sqlite3_prepare_v2(_session->db, sql_refresh_userid_default_key,
    4.53 +            (int)strlen(sql_refresh_userid_default_key), &_session->refresh_userid_default_key, NULL);
    4.54 +    assert(int_result == SQLITE_OK);
    4.55 +
    4.56      int_result = sqlite3_prepare_v2(_session->db, sql_replace_identities_fpr,
    4.57              (int)strlen(sql_replace_identities_fpr), 
    4.58              &_session->replace_identities_fpr, NULL);
    4.59 @@ -1113,6 +1146,12 @@
    4.60                  sqlite3_finalize(session->i18n_token);
    4.61              if (session->replace_userid)
    4.62                  sqlite3_finalize(session->replace_userid);
    4.63 +            if (session->replace_main_user_fpr)
    4.64 +                sqlite3_finalize(session->replace_main_user_fpr);                
    4.65 +            if (session->get_main_user_fpr)
    4.66 +                sqlite3_finalize(session->get_main_user_fpr);
    4.67 +            if (session->refresh_userid_default_key)
    4.68 +                sqlite3_finalize(session->refresh_userid_default_key);
    4.69              if (session->blacklist_add)
    4.70                  sqlite3_finalize(session->blacklist_add);
    4.71              if (session->blacklist_delete)
    4.72 @@ -1787,7 +1826,7 @@
    4.73      bool has_fpr = (identity->fpr && identity->fpr[0] != '\0');
    4.74      
    4.75      if (has_fpr) {    
    4.76 -        // blacklist check
    4.77 +        // blacklist check - FIXME: ENGINE-294 will remove
    4.78          status = blacklist_is_listed(session, identity->fpr, &listed);
    4.79          assert(status == PEP_STATUS_OK);
    4.80          if (status != PEP_STATUS_OK)
    4.81 @@ -2088,8 +2127,8 @@
    4.82      sqlite3_reset(session->unset_identity_flags);
    4.83      if (result != SQLITE_DONE)
    4.84          return PEP_CANNOT_SET_IDENTITY;
    4.85 -
    4.86 -    identity->flags &= ~flags;
    4.87 +        identity->flags &= ~flags;
    4.88 +
    4.89      return PEP_STATUS_OK;
    4.90  }
    4.91  
    4.92 @@ -2119,6 +2158,89 @@
    4.93      return PEP_STATUS_OK;
    4.94  }
    4.95  
    4.96 +PEP_STATUS refresh_userid_default_key(PEP_SESSION session, const char* user_id) {
    4.97 +    assert(session);
    4.98 +    assert(user_id);
    4.99 +    
   4.100 +    if (!session || !user_id)
   4.101 +        return PEP_ILLEGAL_VALUE;
   4.102 +
   4.103 +    int result;
   4.104 +
   4.105 +    sqlite3_reset(session->refresh_userid_default_key);
   4.106 +    sqlite3_bind_text(session->refresh_userid_default_key, 1, user_id, -1,
   4.107 +            SQLITE_STATIC);
   4.108 +    result = sqlite3_step(session->refresh_userid_default_key);
   4.109 +    sqlite3_reset(session->refresh_userid_default_key);
   4.110 +    if (result != SQLITE_DONE)
   4.111 +        return PEP_CANNOT_SET_PERSON;
   4.112 +
   4.113 +    return PEP_STATUS_OK;    
   4.114 +}
   4.115 +
   4.116 +PEP_STATUS replace_main_user_fpr(PEP_SESSION session, const char* user_id,
   4.117 +                                 const char* new_fpr) {
   4.118 +    assert(session);
   4.119 +    assert(user_id);
   4.120 +    assert(new_fpr);
   4.121 +    
   4.122 +    if (!session || !user_id || !new_fpr)
   4.123 +        return PEP_ILLEGAL_VALUE;
   4.124 +
   4.125 +    int result;
   4.126 +
   4.127 +    sqlite3_reset(session->replace_main_user_fpr);
   4.128 +    sqlite3_bind_text(session->replace_main_user_fpr, 1, new_fpr, -1,
   4.129 +            SQLITE_STATIC);
   4.130 +    sqlite3_bind_text(session->replace_main_user_fpr, 2, user_id, -1,
   4.131 +            SQLITE_STATIC);
   4.132 +    result = sqlite3_step(session->replace_main_user_fpr);
   4.133 +    sqlite3_reset(session->replace_main_user_fpr);
   4.134 +    if (result != SQLITE_DONE)
   4.135 +        return PEP_CANNOT_SET_PERSON;
   4.136 +
   4.137 +    return PEP_STATUS_OK;
   4.138 +}
   4.139 +
   4.140 +PEP_STATUS get_main_user_fpr(PEP_SESSION session, 
   4.141 +                             const char* user_id,
   4.142 +                             char** main_fpr)
   4.143 +{
   4.144 +    PEP_STATUS status = PEP_STATUS_OK;
   4.145 +    int result;
   4.146 +    
   4.147 +    assert(session);
   4.148 +    assert(user_id);
   4.149 +    assert(main_fpr);
   4.150 +    
   4.151 +    if (!(session && user_id && user_id[0] && main_fpr))
   4.152 +        return PEP_ILLEGAL_VALUE;
   4.153 +        
   4.154 +    *main_fpr = NULL;
   4.155 +    
   4.156 +    sqlite3_reset(session->get_main_user_fpr);
   4.157 +    sqlite3_bind_text(session->get_main_user_fpr, 1, user_id, -1,
   4.158 +                      SQLITE_STATIC);
   4.159 +    result = sqlite3_step(session->get_main_user_fpr);
   4.160 +    switch (result) {
   4.161 +    case SQLITE_ROW: {
   4.162 +        const char* _fpr = 
   4.163 +            (const char *) sqlite3_column_text(session->get_main_user_fpr, 0);
   4.164 +        if (_fpr)
   4.165 +            *main_fpr = strdup(_fpr);
   4.166 +        if (!(*main_fpr))
   4.167 +            status = PEP_OUT_OF_MEMORY;
   4.168 +        break;
   4.169 +    }
   4.170 +    default:
   4.171 +        status = PEP_CANNOT_FIND_PERSON;
   4.172 +    }
   4.173 +
   4.174 +    sqlite3_reset(session->get_main_user_fpr);
   4.175 +    return status;
   4.176 +}
   4.177 +
   4.178 +
   4.179  DYNAMIC_API PEP_STATUS mark_as_compromized(
   4.180          PEP_SESSION session,
   4.181          const char *fpr
   4.182 @@ -2149,6 +2271,36 @@
   4.183      free(p);
   4.184  }
   4.185  
   4.186 +PEP_STATUS set_trust(PEP_SESSION session, 
   4.187 +                     const char* user_id,
   4.188 +                     const char* fpr, 
   4.189 +                     PEP_comm_type comm_type) 
   4.190 +{
   4.191 +    assert(session);
   4.192 +    assert(user_id);
   4.193 +    assert(fpr);
   4.194 +    
   4.195 +    if (!session || !user_id || user_id[0] == '\0' || !fpr || fpr[0] == '\0')
   4.196 +        return PEP_ILLEGAL_VALUE;
   4.197 +        
   4.198 +    int result;
   4.199 +                
   4.200 +    sqlite3_reset(session->set_trust);
   4.201 +    sqlite3_bind_text(session->set_trust, 1, user_id, -1,
   4.202 +            SQLITE_STATIC);
   4.203 +    sqlite3_bind_text(session->set_trust, 2, fpr, -1,
   4.204 +            SQLITE_STATIC);
   4.205 +    sqlite3_bind_int(session->set_trust, 3, comm_type);
   4.206 +    result = sqlite3_step(session->set_trust);
   4.207 +    assert(result == SQLITE_DONE);
   4.208 +    sqlite3_reset(session->set_trust);
   4.209 +    if (result != SQLITE_DONE)
   4.210 +        return PEP_CANNOT_SET_TRUST;
   4.211 +
   4.212 +    return PEP_STATUS_OK;
   4.213 +}
   4.214 +
   4.215 +
   4.216  DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity)
   4.217  {
   4.218      PEP_STATUS status = PEP_STATUS_OK;
     5.1 --- a/src/pEpEngine.h	Wed Jan 24 16:06:50 2018 +0100
     5.2 +++ b/src/pEpEngine.h	Thu Jan 25 02:39:57 2018 +0100
     5.3 @@ -58,6 +58,7 @@
     5.4      PEP_CANNOT_SET_IDENTITY                         = 0x0383,
     5.5      PEP_CANNOT_SET_TRUST                            = 0x0384,
     5.6      PEP_KEY_BLACKLISTED                             = 0x0385,
     5.7 +    PEP_CANNOT_FIND_PERSON                          = 0x0386,
     5.8      
     5.9      PEP_CANNOT_FIND_ALIAS                           = 0x0391,
    5.10      PEP_CANNOT_SET_ALIAS                            = 0x0392,
    5.11 @@ -668,6 +669,7 @@
    5.12          const char* default_id,
    5.13          const char* alias_id);
    5.14  
    5.15 +
    5.16  // set_device_group() - update own person's device group
    5.17  //
    5.18  //    parameters:
    5.19 @@ -1217,7 +1219,16 @@
    5.20  PEP_STATUS remove_fpr_as_default(PEP_SESSION session, 
    5.21                                      const char* fpr);
    5.22                                
    5.23 +                                    
    5.24 +PEP_STATUS get_main_user_fpr(PEP_SESSION session, 
    5.25 +                             const char* user_id,
    5.26 +                             char** main_fpr);
    5.27 +
    5.28 +PEP_STATUS replace_main_user_fpr(PEP_SESSION session, const char* user_id,
    5.29 +                              const char* new_fpr);
    5.30      
    5.31 +PEP_STATUS refresh_userid_default_key(PEP_SESSION session, const char* user_id);
    5.32 +
    5.33  #ifdef __cplusplus
    5.34  }
    5.35  #endif
     6.1 --- a/src/pEp_internal.h	Wed Jan 24 16:06:50 2018 +0100
     6.2 +++ b/src/pEp_internal.h	Thu Jan 25 02:39:57 2018 +0100
     6.3 @@ -126,6 +126,9 @@
     6.4      sqlite3_stmt *get_identity_without_trust_check;
     6.5      sqlite3_stmt *get_identities_by_address;
     6.6      sqlite3_stmt *replace_identities_fpr;
     6.7 +    sqlite3_stmt *replace_main_user_fpr;
     6.8 +    sqlite3_stmt *get_main_user_fpr;
     6.9 +    sqlite3_stmt *refresh_userid_default_key;
    6.10      sqlite3_stmt *remove_fpr_as_default;
    6.11      sqlite3_stmt *set_person;
    6.12      sqlite3_stmt *set_device_group;
    6.13 @@ -387,6 +390,18 @@
    6.14      return retval;
    6.15  }
    6.16  
    6.17 +#ifndef EMPTYSTR
    6.18 +#define EMPTYSTR(STR) ((STR) == NULL || (STR)[0] == '\0')
    6.19 +#endif
    6.20 +
    6.21 +#ifndef _MIN
    6.22 +#define _MIN(A, B) ((B) > (A) ? (A) : (B))
    6.23 +#endif
    6.24 +#ifndef _MAX
    6.25 +#define _MAX(A, B) ((B) > (A) ? (B) : (A))
    6.26 +#endif
    6.27 +
    6.28 +
    6.29  // These are globals used in generating message IDs and should only be
    6.30  // computed once, as they're either really constants or OS-dependent
    6.31  
     7.1 --- a/test/test_util.cc	Wed Jan 24 16:06:50 2018 +0100
     7.2 +++ b/test/test_util.cc	Thu Jan 25 02:39:57 2018 +0100
     7.3 @@ -1,5 +1,6 @@
     7.4  #include "pEpEngine_test.h"
     7.5  #include "pEpEngine.h"
     7.6 +#include "pEp_internal.h"
     7.7  #include "message_api.h"
     7.8  #include <fstream>
     7.9  #include <sstream>
    7.10 @@ -30,6 +31,13 @@
    7.11      outfile.close();
    7.12  }
    7.13  
    7.14 +char* get_new_uuid() {
    7.15 +    char* new_uuid = (char*)calloc(37, 1);
    7.16 +    pEpUUID uuid;
    7.17 +    uuid_generate_random(uuid);
    7.18 +    uuid_unparse_upper(uuid, new_uuid);
    7.19 +    return new_uuid;
    7.20 +}
    7.21  
    7.22  const char* tl_status_string(PEP_STATUS status) {
    7.23      switch (status) {
     8.1 --- a/test/test_util.h	Wed Jan 24 16:06:50 2018 +0100
     8.2 +++ b/test/test_util.h	Thu Jan 25 02:39:57 2018 +0100
     8.3 @@ -18,3 +18,6 @@
     8.4  
     8.5  // Returns the string value of the input status enum value. 
     8.6  const char* tl_status_string(PEP_STATUS status);
     8.7 +
     8.8 +// Grabs a new uuid for your randomish string needs.
     8.9 +char* get_new_uuid();
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/test/trust_manipulation_test.cc	Thu Jan 25 02:39:57 2018 +0100
     9.3 @@ -0,0 +1,114 @@
     9.4 +// This file is under GNU General Public License 3.0
     9.5 +// see LICENSE.txt
     9.6 +
     9.7 +#include <stdlib.h>
     9.8 +#include <string.h>
     9.9 +#include <time.h>
    9.10 +#include "platform.h"
    9.11 +#include <iostream>
    9.12 +#include <fstream>
    9.13 +#include <assert.h>
    9.14 +#include "mime.h"
    9.15 +#include "message_api.h"
    9.16 +#include "test_util.h"
    9.17 +
    9.18 +using namespace std;
    9.19 +
    9.20 +int main() {
    9.21 +    cout << "\n*** trust manipulation test ***\n\n";
    9.22 +
    9.23 +    PEP_SESSION session;
    9.24 +
    9.25 +    char* user_id = get_new_uuid();
    9.26 +    
    9.27 +    cout << "calling init()\n";
    9.28 +    PEP_STATUS status = init(&session);   
    9.29 +    assert(status == PEP_STATUS_OK);
    9.30 +    assert(session);
    9.31 +    cout << "init() completed.\n";
    9.32 +
    9.33 +    cout << "creating id for : ";
    9.34 +    char *uniqname = strdup("AAAAtestuser@testdomain.org");
    9.35 +    srandom(time(NULL));
    9.36 +    for(int i=0; i < 4;i++)
    9.37 +        uniqname[i] += random() & 0xf;
    9.38 +    
    9.39 +    cout << uniqname << "\n";
    9.40 +    pEp_identity * user = new_identity(uniqname, NULL, user_id, "Test User");
    9.41 +    status = generate_keypair(session, user);
    9.42 +    assert(user->fpr);
    9.43 +
    9.44 +    char* keypair1 = strdup(user->fpr);
    9.45 +    cout << "generated fingerprint \n";
    9.46 +    cout << user->fpr << "\n";
    9.47 +
    9.48 +    cout << "Setting key 1 (" << user->fpr << ") as the default for the identity." << endl;
    9.49 +    // Put identity in the DB
    9.50 +    status = set_identity(session, user);
    9.51 +
    9.52 +    cout << "creating second keypair for : " << uniqname << endl;
    9.53 +    
    9.54 +    pEp_identity * user_again = new_identity(uniqname, NULL, user_id, "Test User");
    9.55 +    status = generate_keypair(session, user_again);
    9.56 +    assert(user_again->fpr);
    9.57 +
    9.58 +    char* keypair2 = strdup(user_again->fpr);
    9.59 +    cout << "generated fingerprint \n";
    9.60 +    cout << user_again->fpr << "\n";
    9.61 +
    9.62 +    assert(strcmp(user->fpr, user_again->fpr) != 0);
    9.63 +    update_identity(session, user);
    9.64 +    assert(strcmp(user->fpr, keypair1) == 0);
    9.65 +    cout << "Key 1 (" << user->fpr << ") is still the default for the identity after update_identity." << endl;
    9.66 +
    9.67 +    // First, trust the SECOND key; make sure it replaces as the default
    9.68 +    cout << "Set trust bit for key 2 (" << keypair2 << ") and ensure it replaces key 1 as the default." << endl;
    9.69 +    status = trust_personal_key(session, user_again);
    9.70 +    status = update_identity(session, user);
    9.71 +    assert(user->comm_type == PEP_ct_OpenPGP);
    9.72 +    assert(strcmp(user->fpr, keypair2) == 0);
    9.73 +    cout << "Key 2 (" << user->fpr << ") is now the default for the identity after update_identity, and its comm_type is PEP_ct_OpenPGP (trust bit set!)." << endl;
    9.74 +
    9.75 +    cout << "Now make key 2 not trusted (which also removes it as a default everywhere)." << endl;
    9.76 +    status = key_reset_trust(session, user);
    9.77 +    status = get_trust(session, user);
    9.78 +    assert(strcmp(user->fpr, keypair2) == 0);
    9.79 +    assert(user->comm_type == PEP_ct_OpenPGP_unconfirmed);
    9.80 +    cout << "Key 2 is untrusted in the DB." << endl;
    9.81 +
    9.82 +    cout << "Now let's mistrust key 2 in the DB." << endl;
    9.83 +    // Now let's mistrust the second key.
    9.84 +    status = key_mistrusted(session, user);
    9.85 +    status = get_trust(session, user);
    9.86 +    assert(strcmp(user->fpr, keypair2) == 0);
    9.87 +    assert(user->comm_type == PEP_ct_mistrusted);
    9.88 +    cout << "Hoorah, we now do not trust key 2. (We never liked key 2 anyway.)" << endl;
    9.89 +    cout << "Now we call update_identity to see what gifts it gives us (should be key 1 with key 1's initial trust.)" << endl;    
    9.90 +    status = update_identity(session, user);
    9.91 +    assert(strcmp(user->fpr, keypair1) == 0);
    9.92 +    assert(user->comm_type == PEP_ct_OpenPGP_unconfirmed);
    9.93 +    cout << "Yup, got key 1, and the trust status is PEP_ct_OpenPGP_unconfirmed." << endl;
    9.94 +    
    9.95 +    cout << "Let's mistrust key 1 too. It's been acting shifty lately." << endl;
    9.96 +    status = key_mistrusted(session, user);
    9.97 +    status = get_trust(session, user);
    9.98 +    assert(strcmp(user->fpr, keypair1) == 0);
    9.99 +    assert(user->comm_type == PEP_ct_mistrusted);
   9.100 +    cout << "Hoorah, we now do not trust key 1. (TRUST NO ONE)" << endl;
   9.101 +    cout << "Now we call update_identity to see what gifts it gives us (should be an empty key and a key not found comm_type.)" << endl;    
   9.102 +    status = update_identity(session, user);
   9.103 +    assert(user->fpr == NULL);
   9.104 +    assert(user->comm_type == PEP_ct_key_not_found);
   9.105 +    cout << "Yup, we trust no keys from " << uniqname << endl;
   9.106 +    
   9.107 +    cout << "TODO: Add cases where we have multiple user_ids addressing a single key, and multiple identities with that key + mistrust" << endl;
   9.108 +    cout << "Passed all of our exciting messing with the trust DB. Moving on..." << endl;
   9.109 + 
   9.110 +    free(user_id);
   9.111 +    free(keypair1);
   9.112 +    free(uniqname);
   9.113 +    free_identity(user);
   9.114 +    release(session);
   9.115 +    
   9.116 +    return 0;
   9.117 +}