This is Work in Progress branch for async key management. async_key_management
authorEdouard Tisserant
Mon, 25 Apr 2016 14:53:45 +0200
branchasync_key_management
changeset 539c8a4c7b86064
parent 528 587f602bf045
child 541 484833434fed
This is Work in Progress branch for async key management.
- All DB operation altering identity, person, trust, pgp_keypair tables
are now serialized in key management thread.
- myself() returns immediately.
- Database is updated asynchronously, by key management thread.
- update_identity() and mysel() returned identity reflects input confronted
to informations immediately available in pEpEngine. Changes to DB are
applied later.
- confront_identity() is resposnible to selectively modify given identity
according to content of DB and keyrings but without changing pEp state.
It detects if confrontation resulted in some changes deserving to be
examined. It is called by update_identity() and myself() before queueing
identity to be examined by key management thread.
- Key management itself calls confront_identity() in order to detect and
mitigate concurrent conflicting operation on same identity.
- ensure_own_key() is also called by key management to deal with cases
where own identity key is inexistant, revoked or expired.
- examine_identity() as well as retrieve_next_identity() got their signature
updated, and adapters have to update. Those callbacks are now also used to
signal keymanagement activity to the app, thus avoiding app writer to poll
identity or message colors when waiting for long operation to complete
(i.e. key gen)
- Updated some SQL :
- Now address and user_id ar together primary key of identity.
- Use of still unused pgp_keypair.created column to mark own key pair
- Added sql_get_pgp_keypair_created
- Ensured consistant storage and comparing of fingerprints (spaces, case)
- Added sql_get_best_user as a (questionable) fallback for app
developper that would still not give identity.user_id after already having
already created a person for that identity/address.
- Changed mark_as_compromized into a more generic set_fpr_trust, with
comm_type given as a parameter, not anymore hard-coded in SQL statement.
- Added test to detect revoked key in pgp_netpgp.c + various minor fixes.
- Renamed key_compromized() to key_mistrusted()
src/cryptotech.c
src/cryptotech.h
src/keymanagement.c
src/keymanagement.h
src/message_api.c
src/pEpEngine.c
src/pEpEngine.h
src/pEp_internal.h
src/pgp_netpgp.c
src/pgp_netpgp.h
     1.1 --- a/src/cryptotech.c	Wed Apr 06 17:00:54 2016 +0200
     1.2 +++ b/src/cryptotech.c	Mon Apr 25 14:53:45 2016 +0200
     1.3 @@ -45,6 +45,7 @@
     1.4          cryptotech[PEP_crypt_OpenPGP].renew_key = pgp_renew_key;
     1.5          cryptotech[PEP_crypt_OpenPGP].revoke_key = pgp_revoke_key;
     1.6          cryptotech[PEP_crypt_OpenPGP].key_expired = pgp_key_expired;
     1.7 +        cryptotech[PEP_crypt_OpenPGP].key_revoked = pgp_key_revoked;
     1.8  #ifdef PGP_BINARY_PATH
     1.9          cryptotech[PEP_crypt_OpenPGP].binary_path = PGP_BINARY_PATH;
    1.10  #endif
     2.1 --- a/src/cryptotech.h	Wed Apr 06 17:00:54 2016 +0200
     2.2 +++ b/src/cryptotech.h	Mon Apr 25 14:53:45 2016 +0200
     2.3 @@ -63,6 +63,9 @@
     2.4  typedef PEP_STATUS (*key_expired_t)(PEP_SESSION session, const char *fpr,
     2.5          bool *expired);
     2.6  
     2.7 +typedef PEP_STATUS (*key_revoked_t)(PEP_SESSION session, const char *fpr,
     2.8 +                                    bool *revoked);
     2.9 +
    2.10  typedef PEP_STATUS (*binary_path_t)(const char **path);
    2.11  
    2.12  typedef struct _PEP_cryptotech_t {
    2.13 @@ -84,6 +87,7 @@
    2.14      renew_key_t renew_key;
    2.15      revoke_key_t revoke_key;
    2.16      key_expired_t key_expired;
    2.17 +    key_revoked_t key_revoked;
    2.18      binary_path_t binary_path;
    2.19  } PEP_cryptotech_t;
    2.20  
     3.1 --- a/src/keymanagement.c	Wed Apr 06 17:00:54 2016 +0200
     3.2 +++ b/src/keymanagement.c	Mon Apr 25 14:53:45 2016 +0200
     3.3 @@ -15,6 +15,13 @@
     3.4  
     3.5  #define KEY_EXPIRE_DELTA (60 * 60 * 24 * 365)
     3.6  
     3.7 +#ifndef MIN
     3.8 +#define MIN(A, B) ((B) > (A) ? (A) : (B))
     3.9 +#endif
    3.10 +#ifndef MAX
    3.11 +#define MAX(A, B) ((B) > (A) ? (B) : (A))
    3.12 +#endif
    3.13 +
    3.14  // Space tolerant and case insensitive fingerprint string compare
    3.15  static int _same_fpr(
    3.16          const char* fpra,
    3.17 @@ -42,265 +49,851 @@
    3.18      return ai == fpras && bi == fprbs;
    3.19  }
    3.20  
    3.21 -DYNAMIC_API PEP_STATUS update_identity(
    3.22 -        PEP_SESSION session, pEp_identity * identity
    3.23 +#ifndef NDEBUG
    3.24 +
    3.25 +static void _debug_log_identity_address_fpr(PEP_SESSION session,
    3.26 +                                            const char* title,
    3.27 +                                            const char* entity,
    3.28 +                                            pEp_identity *identity)
    3.29 +{
    3.30 +    size_t dbgmsg_size = identity->address_size + identity->fpr_size + 4;
    3.31 +    char* dbgmsg = calloc(1, dbgmsg_size);
    3.32 +    if (dbgmsg)
    3.33 +    {
    3.34 +        snprintf(dbgmsg, dbgmsg_size, "%s (%s)",
    3.35 +                 identity->address,identity->fpr);
    3.36 +        DEBUG_LOG(title, entity, dbgmsg);
    3.37 +    }
    3.38 +}
    3.39 +
    3.40 +#define DEBUG_LOG_IDENTITY(TITLE, ENTITY, IDENTITY) \
    3.41 +    _debug_log_identity_address_fpr(session, (TITLE), (ENTITY), (IDENTITY));
    3.42 +
    3.43 +#else
    3.44 +
    3.45 +#define DEBUG_LOG_IDENTITY(TITLE, ENTITY, IDENTITY)
    3.46 +
    3.47 +#endif
    3.48 +
    3.49 +
    3.50 +static bool _apply_comm_type(PEP_comm_type *dst, PEP_comm_type target_comm_type)
    3.51 +{
    3.52 +    switch(target_comm_type)
    3.53 +    {
    3.54 +        
    3.55 +        case PEP_ct_unknown:
    3.56 +            return false;
    3.57 +            
    3.58 +        case PEP_ct_no_encryption:
    3.59 +        case PEP_ct_unconfirmed_encryption:
    3.60 +        case PEP_ct_to_be_checked:
    3.61 +        case PEP_ct_strong_but_unconfirmed:
    3.62 +        case PEP_ct_unconfirmed_enc_anon:
    3.63 +            
    3.64 +            // ignore generic types
    3.65 +            return false;
    3.66 +            
    3.67 +        case PEP_ct_confirmed:
    3.68 +        case PEP_ct_confirmed_encryption:
    3.69 +            
    3.70 +            // case of trust_personal_key
    3.71 +            // applies only to unconfirmed encryption
    3.72 +            if (*dst > PEP_ct_unconfirmed_encryption)
    3.73 +            {
    3.74 +                *dst |= PEP_ct_confirmed;
    3.75 +                return true;
    3.76 +            }
    3.77 +            return false;
    3.78 +            
    3.79 +        case PEP_ct_to_be_checked_confirmed:
    3.80 +        case PEP_ct_strong_encryption:
    3.81 +        case PEP_ct_confirmed_enc_anon:
    3.82 +            
    3.83 +            // ignore other generic comm_types
    3.84 +            return false;
    3.85 +            
    3.86 +        case PEP_ct_pEp:
    3.87 +            
    3.88 +            // case of own identity
    3.89 +            if (*dst > PEP_ct_unconfirmed_encryption)
    3.90 +            {
    3.91 +                *dst = PEP_ct_pEp;
    3.92 +                return true;
    3.93 +            }
    3.94 +            return false;
    3.95 +            
    3.96 +        default:
    3.97 +            
    3.98 +            if ((target_comm_type & ~(*dst)) == PEP_ct_confirmed)
    3.99 +            {
   3.100 +                // Again case of trust_personal_key
   3.101 +                // but at second confrontation
   3.102 +                *dst = target_comm_type;
   3.103 +                return true;
   3.104 +            }
   3.105 +            return false;
   3.106 +    }
   3.107 +}
   3.108 +
   3.109 +// confront_identity() - confront identity to what pEpEngine already knows.
   3.110 +//
   3.111 +//  parameters:
   3.112 +//      session (in)                session handle
   3.113 +//		identity (inout)            pointer to pEp_identity structure
   3.114 +//		target_comm_type (in)       comm_type to be applied to identity
   3.115 +//      outstanding_changes (OUT)   identity contains changes to be stored
   3.116 +//
   3.117 +//  This function modifies the given identity struct; the struct remains in
   3.118 +//  the ownership of the caller.
   3.119 +//
   3.120 +//  If identity->user_id is not provided, then a default user_id is created,
   3.121 +//  based on address.
   3.122 +//
   3.123 +//  When wanted_com_type is given, it is applied to identity if not in
   3.124 +//  contradiction with current state.
   3.125 +//
   3.126 +//  identity->me is taken in account, and may be reset if not applicable.
   3.127 +//  Key's ownership (status of being created by pEp) can be forced by
   3.128 +//  setting target_comm_type to PEP_ct_pEp, and providing target fpr.
   3.129 +//
   3.130 +//  Identity is not stored in database. This is caller's responsibility
   3.131 +//  to store identities with outstanding_changes.
   3.132 +//  Calling confront_identity doesn't modify pEpEngine's internal state,
   3.133 +//  and is not blocking.
   3.134 +//
   3.135 +//  Caller MUST NOT store modified identity if either :
   3.136 +//    - outstanding_changes is false
   3.137 +//    - identity->comm_type is PEP_ct_unknown
   3.138 +//    - returned value different from PEP_STATUS_OK
   3.139 +//
   3.140 +//  Caller SHOULD store modified identity if both :
   3.141 +//    - outstanding_changes is true
   3.142 +//    - identity->comm_type is greater PEP_ct_unknown
   3.143 +//    - returned value is PEP_STATUS_OK
   3.144 +//
   3.145 +//  Confront_identity behavior should be consistent across successive
   3.146 +//  calls on the same identity, provided that :
   3.147 +//         - initial call did set outstanding_changes to true,
   3.148 +//         - engine state is unchanged between calls.
   3.149 +//
   3.150 +
   3.151 +static PEP_STATUS confront_identity(
   3.152 +        PEP_SESSION session,
   3.153 +        pEp_identity * identity,
   3.154 +        PEP_comm_type target_comm_type,
   3.155 +        bool *outstanding_changes
   3.156      )
   3.157  {
   3.158 -    pEp_identity *stored_identity;
   3.159 +    pEp_identity *stored_identity = NULL;
   3.160      PEP_STATUS status;
   3.161 +    int _no_fpr = EMPTYSTR(identity->fpr);
   3.162 +    int _no_user_id = EMPTYSTR(identity->user_id);
   3.163 +
   3.164 +    if (_no_user_id)
   3.165 +    {
   3.166 +        if (identity->me)
   3.167 +        {
   3.168 +            // App MUST provide unique user_id
   3.169 +            // for each local account
   3.170 +            return PEP_ILLEGAL_VALUE;
   3.171 +        }
   3.172 +        
   3.173 +        free(identity->user_id);
   3.174  
   3.175 -    assert(session);
   3.176 -    assert(identity);
   3.177 -    assert(!EMPTYSTR(identity->address));
   3.178 +        status = get_best_user(session,
   3.179 +                              identity->address,
   3.180 +                              &identity->user_id);
   3.181  
   3.182 -    if (!(session && identity && !EMPTYSTR(identity->address)))
   3.183 -        return PEP_ILLEGAL_VALUE;
   3.184 -
   3.185 -    status = get_identity(session, identity->address, &stored_identity);
   3.186 +        // Default user_id, aka Virtual user_id
   3.187 +        if (status == PEP_CANNOT_FIND_IDENTITY)
   3.188 +        {
   3.189 +            identity->user_id = calloc(1, identity->address_size + 5);
   3.190 +            snprintf(identity->user_id, identity->address_size + 5,
   3.191 +                     "TOFU_%s", identity->address);
   3.192 +        }
   3.193 +        else if (status != PEP_STATUS_OK)
   3.194 +        {
   3.195 +            return status;
   3.196 +        }
   3.197 +    }
   3.198 +    
   3.199 +    status = get_identity(session,
   3.200 +                          identity->address,
   3.201 +                          identity->user_id,
   3.202 +                          &stored_identity);
   3.203 +    
   3.204      assert(status != PEP_OUT_OF_MEMORY);
   3.205      if (status == PEP_OUT_OF_MEMORY)
   3.206          return PEP_OUT_OF_MEMORY;
   3.207 -
   3.208 -    if (stored_identity) {
   3.209 -        PEP_comm_type _comm_type_key;
   3.210 -        status = get_key_rating(session, stored_identity->fpr, &_comm_type_key);
   3.211 +    
   3.212 +    *outstanding_changes = false;
   3.213 +    
   3.214 +    if (stored_identity)
   3.215 +    {
   3.216 +        PEP_comm_type _stored_comm_type_key;
   3.217 +        status = get_key_rating(session,
   3.218 +                                stored_identity->fpr,
   3.219 +                                &_stored_comm_type_key);
   3.220 +        
   3.221          assert(status != PEP_OUT_OF_MEMORY);
   3.222          if (status == PEP_OUT_OF_MEMORY)
   3.223 +        {
   3.224 +            free_identity(stored_identity);
   3.225              return PEP_OUT_OF_MEMORY;
   3.226 -
   3.227 -        if (EMPTYSTR(identity->user_id)) {
   3.228 -            free(identity->user_id);
   3.229 -            identity->user_id = strndup(stored_identity->user_id, stored_identity->user_id_size);
   3.230 -            assert(identity->user_id);
   3.231 -            if (identity->user_id == NULL)
   3.232 -                return PEP_OUT_OF_MEMORY;
   3.233 -            identity->user_id_size = stored_identity->user_id_size;
   3.234 -        }
   3.235 -
   3.236 -        if (EMPTYSTR(identity->username)) {
   3.237 -            free(identity->username);
   3.238 -            identity->username = strndup(stored_identity->username, stored_identity->username_size);
   3.239 -            assert(identity->username);
   3.240 -            if (identity->username == NULL)
   3.241 -                return PEP_OUT_OF_MEMORY;
   3.242 -            identity->username_size = stored_identity->username_size;
   3.243          }
   3.244  
   3.245 -        if (EMPTYSTR(identity->fpr)) {
   3.246 -            identity->fpr = strndup(stored_identity->fpr, stored_identity->fpr_size);
   3.247 -            assert(identity->fpr);
   3.248 -            if (identity->fpr == NULL)
   3.249 +        if (EMPTYSTR(identity->username) &&
   3.250 +            !EMPTYSTR(stored_identity->username))
   3.251 +        {
   3.252 +            free(identity->username);
   3.253 +            identity->username = strndup(stored_identity->username,
   3.254 +                                         stored_identity->username_size);
   3.255 +            assert(identity->username);
   3.256 +            if (identity->username == NULL)
   3.257 +            {
   3.258 +                free_identity(stored_identity);
   3.259                  return PEP_OUT_OF_MEMORY;
   3.260 -            identity->fpr_size = stored_identity->fpr_size;
   3.261 -            if (_comm_type_key < PEP_ct_unconfirmed_encryption) {
   3.262 -                identity->comm_type = _comm_type_key;
   3.263              }
   3.264 -            else {
   3.265 -                identity->comm_type = stored_identity->comm_type;
   3.266 -            }
   3.267 +            identity->username_size = stored_identity->username_size;
   3.268          }
   3.269 -        else /* !EMPTYSTR(identity->fpr) */ {
   3.270 -            if (_same_fpr(identity->fpr,
   3.271 -                          identity->fpr_size,
   3.272 -                          stored_identity->fpr,
   3.273 -                          stored_identity->fpr_size)) {
   3.274 -                if (_comm_type_key < PEP_ct_unconfirmed_encryption) {
   3.275 -                    identity->comm_type = _comm_type_key;
   3.276 -                }else{
   3.277 -                    identity->comm_type = stored_identity->comm_type;
   3.278 -                    if (identity->comm_type == PEP_ct_unknown) {
   3.279 -                        identity->comm_type = _comm_type_key;
   3.280 -                    }
   3.281 -                }
   3.282 -            } else {
   3.283 -                status = get_trust(session, identity);
   3.284 -                assert(status != PEP_OUT_OF_MEMORY);
   3.285 -                if (status == PEP_OUT_OF_MEMORY)
   3.286 -                    return PEP_OUT_OF_MEMORY;
   3.287 -                if (identity->comm_type < stored_identity->comm_type)
   3.288 -                    identity->comm_type = PEP_ct_unknown;
   3.289 +        else
   3.290 +        {
   3.291 +            // See what username is given, if not the same as stored.
   3.292 +            if (!EMPTYSTR(identity->username) &&
   3.293 +                (EMPTYSTR(stored_identity->username) ||
   3.294 +                 stored_identity->username_size != identity->username_size ||
   3.295 +                 strncmp(stored_identity->username,
   3.296 +                         identity->username,
   3.297 +                         identity->username_size) != 0))
   3.298 +            {
   3.299 +                // If no user ID was given, this is just information
   3.300 +                *outstanding_changes = !_no_user_id;
   3.301              }
   3.302          }
   3.303  
   3.304 -        if (identity->lang[0] == 0) {
   3.305 +        // Fpr is not given or is equivalent to stored
   3.306 +        if (_no_fpr ||
   3.307 +            _same_fpr(identity->fpr,
   3.308 +                      identity->fpr_size,
   3.309 +                      stored_identity->fpr,
   3.310 +                      stored_identity->fpr_size))
   3.311 +        {
   3.312 +            
   3.313 +            if (_stored_comm_type_key < PEP_ct_unconfirmed_encryption)
   3.314 +            {
   3.315 +                // Id key's rating bad, smash ident's comm_type
   3.316 +                identity->comm_type = _stored_comm_type_key;
   3.317 + 
   3.318 +                // Lose ownership if stored identity is not our own
   3.319 +                identity->me &= stored_identity->me;
   3.320 +            }
   3.321 +            else
   3.322 +            {
   3.323 +                if (_no_fpr ||
   3.324 +                    target_comm_type == PEP_ct_unknown ||
   3.325 +                    stored_identity->comm_type < PEP_ct_unconfirmed_encryption)
   3.326 +                {
   3.327 +                    // Take stored comm_type as-is when no fpr given,
   3.328 +                    // or if bad comm_type or when no target given
   3.329 +                    identity->comm_type = stored_identity->comm_type;
   3.330 +                    
   3.331 +                    // Lose ownership if stored identity is not our own
   3.332 +                    identity->me &= stored_identity->me;
   3.333 +                }
   3.334 +                else
   3.335 +                {
   3.336 +                    // XXX return value -> outstanding_changes
   3.337 +                    // Otherwise, accept wanted comm_type
   3.338 +                    _apply_comm_type(&identity->comm_type, target_comm_type);
   3.339 +                }
   3.340 +                
   3.341 +                if (identity->comm_type == PEP_ct_unknown)
   3.342 +                {
   3.343 +                    // If still unset at that point, take key's comm_type
   3.344 +                    identity->comm_type = _stored_comm_type_key;
   3.345 +                    
   3.346 +                    // If no user ID was given, this is just information
   3.347 +                    *outstanding_changes = !_no_user_id;
   3.348 +                }
   3.349 +            }
   3.350 +            
   3.351 +            if(_no_fpr)
   3.352 +            {
   3.353 +                // Copy fpr only in case it wasn't given
   3.354 +                free(identity->fpr);
   3.355 +                identity->fpr = strndup(stored_identity->fpr,
   3.356 +                                        stored_identity->fpr_size);
   3.357 +                assert(identity->fpr);
   3.358 +                if (identity->fpr == NULL)
   3.359 +                {
   3.360 +                    free_identity(stored_identity);
   3.361 +                    return PEP_OUT_OF_MEMORY;
   3.362 +                }
   3.363 +                identity->fpr_size = stored_identity->fpr_size;
   3.364 +            }
   3.365 +        }
   3.366 +        
   3.367 +        // Fpr given but different from stored
   3.368 +        else if (!_no_fpr &&
   3.369 +                 !_same_fpr(identity->fpr,
   3.370 +                            identity->fpr_size,
   3.371 +                            stored_identity->fpr,
   3.372 +                            stored_identity->fpr_size))
   3.373 +        {
   3.374 +            
   3.375 +            // This case can happen when re-confronting queued identity,
   3.376 +            // after execution of other conflicting operations on same identity
   3.377 +            // that would have been queued earlier.
   3.378 +            // Confrontation should result in selecting the most appropriate key
   3.379 +            
   3.380 +            PEP_comm_type _given_key_comm_type;
   3.381 +            status = get_key_rating(session,
   3.382 +                                    stored_identity->fpr,
   3.383 +                                    &_given_key_comm_type);
   3.384 +            assert(status != PEP_OUT_OF_MEMORY);
   3.385 +            if (status != PEP_STATUS_OK)
   3.386 +            {
   3.387 +                free_identity(stored_identity);
   3.388 +                return status;
   3.389 +            }
   3.390 +            
   3.391 +            // Ensure that given fpr match a key with corresponding address
   3.392 +            // TODO : make a dedicated crypto call for that purpose
   3.393 +
   3.394 +            stringlist_t *keylist = NULL;
   3.395 +            stringlist_t *_keylist;
   3.396 +            
   3.397 +            status = find_keys(session, identity->address, &keylist);
   3.398 +            assert(status != PEP_OUT_OF_MEMORY);
   3.399 +            if (status == PEP_OUT_OF_MEMORY)
   3.400 +            {
   3.401 +                free_identity(stored_identity);
   3.402 +                return PEP_OUT_OF_MEMORY;
   3.403 +            }
   3.404 +
   3.405 +            for (_keylist = keylist;
   3.406 +                 _keylist && _keylist->value;
   3.407 +                 _keylist = _keylist->next)
   3.408 +            {
   3.409 +                if (_same_fpr(identity->fpr,
   3.410 +                              identity->fpr_size,
   3.411 +                              _keylist->value,
   3.412 +                              strlen(_keylist->value)))
   3.413 +                {
   3.414 +                    break;
   3.415 +                }
   3.416 +            }
   3.417 +
   3.418 +            assert(_keylist != NULL);
   3.419 +            if (_keylist == NULL)
   3.420 +            {
   3.421 +                free_stringlist(keylist);
   3.422 +                free_identity(stored_identity);
   3.423 +                return PEP_KEY_HAS_AMBIG_NAME;
   3.424 +            }
   3.425 +
   3.426 +            free_stringlist(keylist);
   3.427 +
   3.428 +            PEP_comm_type _least_comm_type = PEP_ct_unknown;
   3.429 +            
   3.430 +            status = least_trust(session, identity->fpr, &_least_comm_type);
   3.431 +            if (status != PEP_STATUS_OK &&
   3.432 +                status != PEP_CANNOT_FIND_IDENTITY)
   3.433 +            {
   3.434 +                free_identity(stored_identity);
   3.435 +                return status;
   3.436 +            }
   3.437 +            
   3.438 +            if (
   3.439 +                // Bad key ?
   3.440 +                _given_key_comm_type < PEP_ct_unconfirmed_encryption ||
   3.441 +                
   3.442 +                // no target and proposed key comm_type weaker than pre-existing
   3.443 +                (target_comm_type == PEP_ct_unknown &&
   3.444 +                 _given_key_comm_type <= stored_identity->comm_type) ||
   3.445 +                
   3.446 +                // key is already known, and has bad press
   3.447 +                (_least_comm_type != PEP_ct_unknown &&
   3.448 +                 _least_comm_type < PEP_ct_unconfirmed_encryption) ||
   3.449 +                
   3.450 +                // target comm_type given but lower than pre-existing
   3.451 +                (target_comm_type != PEP_ct_unknown &&
   3.452 +                 target_comm_type < stored_identity->comm_type) ||
   3.453 +                
   3.454 +                // wanted comm_type greater than available trust
   3.455 +                // (key reset trust needed)
   3.456 +                (_least_comm_type != PEP_ct_unknown &&
   3.457 +                 target_comm_type != PEP_ct_unknown &&
   3.458 +                 target_comm_type > _least_comm_type))
   3.459 +            {
   3.460 +                // ignore.
   3.461 +                identity->comm_type = PEP_ct_unknown;
   3.462 +            }
   3.463 +            else
   3.464 +            {
   3.465 +                bool _ct_updated = false;
   3.466 +                if(target_comm_type != PEP_ct_unknown)
   3.467 +                {
   3.468 +                    _ct_updated = _apply_comm_type(&identity->comm_type,
   3.469 +                                                   target_comm_type);
   3.470 +                }
   3.471 +                else
   3.472 +                {
   3.473 +                    identity->comm_type = _given_key_comm_type;
   3.474 +                    _ct_updated = true;
   3.475 +                }
   3.476 +
   3.477 +                if (identity->me)
   3.478 +                {
   3.479 +                    int created = 0;
   3.480 +
   3.481 +                    status = get_pgp_keypair_created(session,
   3.482 +                                                     identity->fpr,
   3.483 +                                                     &created);
   3.484 +                    
   3.485 +                    assert(status == PEP_STATUS_OK);
   3.486 +                    if (status != PEP_STATUS_OK)
   3.487 +                    {
   3.488 +                        free_identity(stored_identity);
   3.489 +                        return status;
   3.490 +                    }
   3.491 +                    
   3.492 +                    // ownership preserved only if new keypair really our own
   3.493 +                    if (created)
   3.494 +                    {
   3.495 +                        // If no user ID was given, this is just information
   3.496 +                        *outstanding_changes = !_no_user_id && _ct_updated;
   3.497 +                    }
   3.498 +                    else
   3.499 +                    {
   3.500 +                        identity->me = false;
   3.501 +                    }
   3.502 +                }
   3.503 +                else
   3.504 +                {
   3.505 +                    // If no user ID was given, this is just information
   3.506 +                    *outstanding_changes = !_no_user_id && _ct_updated;
   3.507 +                }
   3.508 +            }
   3.509 +        }
   3.510 +
   3.511 +        if (identity->lang[0] == 0)
   3.512 +        {
   3.513              identity->lang[0] = stored_identity->lang[0];
   3.514              identity->lang[1] = stored_identity->lang[1];
   3.515              identity->lang[2] = 0;
   3.516          }
   3.517 +        
   3.518 +        free_identity(stored_identity);
   3.519      }
   3.520 -    else /* stored_identity == NULL */ {
   3.521 -        if (!EMPTYSTR(identity->fpr)) {
   3.522 -            PEP_comm_type _comm_type_key;
   3.523 +    else /* stored_identity == NULL */
   3.524 +    {
   3.525 +        stringlist_t *keylist;
   3.526 +        identity->comm_type = PEP_ct_unknown;
   3.527 +        
   3.528 +        status = find_keys(session, identity->address, &keylist);
   3.529 +        assert(status != PEP_OUT_OF_MEMORY);
   3.530 +        if (status == PEP_OUT_OF_MEMORY)
   3.531 +            return PEP_OUT_OF_MEMORY;
   3.532 +        
   3.533 +        stringlist_t *_keylist;
   3.534  
   3.535 -            status = get_key_rating(session, identity->fpr, &_comm_type_key);
   3.536 -            assert(status != PEP_OUT_OF_MEMORY);
   3.537 -            if (status == PEP_OUT_OF_MEMORY)
   3.538 -                return PEP_OUT_OF_MEMORY;
   3.539 +        if (!_no_fpr)
   3.540 +        {
   3.541 +            // Find pgp key matching both address and given fpr
   3.542 +            for (_keylist = keylist;
   3.543 +                 _keylist && _keylist->value;
   3.544 +                 _keylist = _keylist->next)
   3.545 +            {
   3.546 +                if (_same_fpr(identity->fpr,
   3.547 +                              identity->fpr_size,
   3.548 +                              _keylist->value,
   3.549 +                              strlen(_keylist->value)))
   3.550 +                {
   3.551 +                    if (identity->me)
   3.552 +                    {
   3.553 +                        // New own identity is accepted if
   3.554 +                        // key is already known as own
   3.555 +                        int created = 0;
   3.556 +                        status = get_pgp_keypair_created(session,
   3.557 +                                                         identity->fpr,
   3.558 +                                                         &created);
   3.559 +                        
   3.560 +                        assert(status == PEP_STATUS_OK);
   3.561 +                        if (status != PEP_STATUS_OK)
   3.562 +                        {
   3.563 +                            free_stringlist(keylist);
   3.564 +                            return status;
   3.565 +                        }
   3.566 +                        
   3.567 +                        // Or, when a key wasn't created, it is possible to
   3.568 +                        // force it if target_com_type is PEP_ct_pEp
   3.569  
   3.570 -            identity->comm_type = _comm_type_key;
   3.571 -        }
   3.572 -        else /* EMPTYSTR(identity->fpr) */ {
   3.573 -            PEP_STATUS status;
   3.574 -            stringlist_t *keylist;
   3.575 -            char *_fpr = NULL;
   3.576 -            identity->comm_type = PEP_ct_unknown;
   3.577 +                        if (created ||
   3.578 +                            (!created && target_comm_type == PEP_ct_pEp))
   3.579 +                        {
   3.580 +                            break;
   3.581 +                        }
   3.582 +                        else
   3.583 +                        {
   3.584 +                            free_stringlist(keylist);
   3.585 +                            return PEP_KEY_NOT_FOUND;
   3.586 +                        }
   3.587 +                    }
   3.588 +                    else
   3.589 +                    {
   3.590 +                        break;
   3.591 +                    }
   3.592 +                }
   3.593 +            }
   3.594 +            
   3.595 +            assert(_keylist != NULL);
   3.596 +            if (_keylist == NULL)
   3.597 +            {
   3.598 +                free_stringlist(keylist);
   3.599 +                return PEP_KEY_HAS_AMBIG_NAME;
   3.600 +            }
   3.601 +            
   3.602 +            PEP_comm_type _least_comm_type = PEP_ct_unknown;
   3.603  
   3.604 -            status = find_keys(session, identity->address, &keylist);
   3.605 -            assert(status != PEP_OUT_OF_MEMORY);
   3.606 -            if (status == PEP_OUT_OF_MEMORY)
   3.607 -                return PEP_OUT_OF_MEMORY;
   3.608 -
   3.609 -            stringlist_t *_keylist;
   3.610 -            for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
   3.611 +            status = least_trust(session, identity->fpr, &_least_comm_type);
   3.612 +            if (status != PEP_STATUS_OK &&
   3.613 +                status != PEP_CANNOT_FIND_IDENTITY)
   3.614 +            {
   3.615 +                free_stringlist(keylist);
   3.616 +                return status;
   3.617 +            }
   3.618 +            
   3.619 +            if(_least_comm_type == PEP_ct_unknown ||
   3.620 +               _least_comm_type >= PEP_ct_unconfirmed_encryption)
   3.621 +            {
   3.622                  PEP_comm_type _comm_type_key;
   3.623 -
   3.624 -                status = get_key_rating(session, _keylist->value, &_comm_type_key);
   3.625 +                
   3.626 +                status = get_key_rating(session,
   3.627 +                                        identity->fpr,
   3.628 +                                        &_comm_type_key);
   3.629 +                
   3.630                  assert(status != PEP_OUT_OF_MEMORY);
   3.631 -                if (status == PEP_OUT_OF_MEMORY) {
   3.632 +                if (status == PEP_OUT_OF_MEMORY)
   3.633 +                {
   3.634                      free_stringlist(keylist);
   3.635                      return PEP_OUT_OF_MEMORY;
   3.636                  }
   3.637  
   3.638 -                if (identity->comm_type == PEP_ct_unknown) {
   3.639 -                    if (_comm_type_key != PEP_ct_compromized && _comm_type_key != PEP_ct_unknown) {
   3.640 -                        identity->comm_type = _comm_type_key;
   3.641 -                        _fpr = _keylist->value;
   3.642 -                    }
   3.643 +                identity->comm_type = _comm_type_key;
   3.644 +                
   3.645 +                *outstanding_changes = true;
   3.646 +            }
   3.647 +            else
   3.648 +            {
   3.649 +                identity->comm_type = _least_comm_type;
   3.650 +            }
   3.651 +        }
   3.652 +        else /* _no_fpr */
   3.653 +        {
   3.654 +            char *_fpr = NULL;
   3.655 +            bool _elected_outstanding = false;
   3.656 +            PEP_comm_type _elected_comm_type = PEP_ct_unknown;
   3.657 +
   3.658 +            free(identity->fpr);
   3.659 +            identity->fpr = NULL;
   3.660 +            
   3.661 +            // Loop over address matching keylist to elect the best key
   3.662 +            for (_keylist = keylist;
   3.663 +                 _keylist && _keylist->value;
   3.664 +                 _keylist = _keylist->next)
   3.665 +            {
   3.666 +                PEP_comm_type _candidate_comm_type = PEP_ct_unknown;
   3.667 +
   3.668 +                status = least_trust(session,
   3.669 +                                     identity->fpr,
   3.670 +                                     &_candidate_comm_type);
   3.671 +                
   3.672 +                if (status != PEP_STATUS_OK &&
   3.673 +                    status != PEP_CANNOT_FIND_IDENTITY)
   3.674 +                {
   3.675 +                    free_stringlist(keylist);
   3.676 +                    return status;
   3.677                  }
   3.678 -                else {
   3.679 -                    if (_comm_type_key != PEP_ct_compromized && _comm_type_key != PEP_ct_unknown) {
   3.680 -                        if (_comm_type_key > identity->comm_type) {
   3.681 -                            identity->comm_type = _comm_type_key;
   3.682 -                            _fpr = _keylist->value;
   3.683 +                
   3.684 +                // Include unknown keys, exclude key with known problems
   3.685 +                if(_candidate_comm_type == PEP_ct_unknown ||
   3.686 +                   _candidate_comm_type >= PEP_ct_unconfirmed_encryption)
   3.687 +                {
   3.688 +                    status = get_key_rating(session,
   3.689 +                                            _keylist->value,
   3.690 +                                            &_candidate_comm_type);
   3.691 +                    
   3.692 +                    assert(status != PEP_OUT_OF_MEMORY);
   3.693 +                    if (status == PEP_OUT_OF_MEMORY)
   3.694 +                    {
   3.695 +                        free_stringlist(keylist);
   3.696 +                        return PEP_OUT_OF_MEMORY;
   3.697 +                    }
   3.698 +                    
   3.699 +                    // Filter-out keys that are not created if we are searchin
   3.700 +                    // for a key for own identity.
   3.701 +                    if (identity->me)
   3.702 +                    {
   3.703 +                        int created = 0;
   3.704 +                        status = get_pgp_keypair_created(session,
   3.705 +                                                         _keylist->value,
   3.706 +                                                         &created);
   3.707 +                        
   3.708 +                        assert(status == PEP_STATUS_OK);
   3.709 +                        if (status != PEP_STATUS_OK)
   3.710 +                        {
   3.711 +                            free_stringlist(keylist);
   3.712 +                            return status;
   3.713 +                        }
   3.714 +                        
   3.715 +                        if (!created)
   3.716 +                        {
   3.717 +                            break;
   3.718                          }
   3.719                      }
   3.720                  }
   3.721 +
   3.722 +                // Elect if the best.
   3.723 +                if (_candidate_comm_type > identity->comm_type)
   3.724 +                {
   3.725 +                    _elected_comm_type = _candidate_comm_type;
   3.726 +                    _fpr = _keylist->value;
   3.727 +
   3.728 +                    _elected_outstanding =
   3.729 +                        _candidate_comm_type >= PEP_ct_unconfirmed_encryption;
   3.730 +                }
   3.731              }
   3.732  
   3.733 -            if (_fpr) {
   3.734 -                free(identity->fpr);
   3.735 -
   3.736 +            if (_fpr && _elected_comm_type >= target_comm_type)
   3.737 +            {
   3.738                  identity->fpr = strdup(_fpr);
   3.739                  if (identity->fpr == NULL) {
   3.740                      free_stringlist(keylist);
   3.741                      return PEP_OUT_OF_MEMORY;
   3.742                  }
   3.743                  identity->fpr_size = strlen(identity->fpr);
   3.744 +                
   3.745 +                identity->comm_type = _elected_comm_type;
   3.746 +                
   3.747 +                *outstanding_changes = _elected_outstanding;
   3.748 +            }
   3.749 +            else
   3.750 +            {
   3.751 +                // No satisfying key found, need a new one.
   3.752 +                
   3.753 +                // In that case comm_type is set to target,
   3.754 +                // but fpr is left empty.
   3.755 +                identity->comm_type = _elected_comm_type;
   3.756              }
   3.757              free_stringlist(keylist);
   3.758          }
   3.759      }
   3.760  
   3.761 -    status = PEP_STATUS_OK;
   3.762 +    return PEP_STATUS_OK;
   3.763 +}
   3.764 +
   3.765 +DYNAMIC_API PEP_STATUS update_identity(
   3.766 +        PEP_SESSION session, pEp_identity * identity
   3.767 +    )
   3.768 +{
   3.769 +    PEP_STATUS status;
   3.770 +    bool outstanding_changes = false;
   3.771 +
   3.772 +    assert(session);
   3.773 +    assert(identity);
   3.774 +    assert(!EMPTYSTR(identity->address));
   3.775 +    assert(!identity->me);
   3.776 +
   3.777 +    if (!(session &&
   3.778 +          identity &&
   3.779 +          !EMPTYSTR(identity->address) &&
   3.780 +          !identity->me))
   3.781 +    {
   3.782 +        return PEP_ILLEGAL_VALUE;
   3.783 +    }
   3.784  
   3.785 -    if (identity->comm_type != PEP_ct_unknown && !EMPTYSTR(identity->user_id)) {
   3.786 -        assert(!EMPTYSTR(identity->username)); // this should not happen
   3.787 +    status = confront_identity(session,
   3.788 +                               identity,
   3.789 +                               PEP_ct_unknown, // comm_type is read_only
   3.790 +                               &outstanding_changes);
   3.791 +        
   3.792 +    assert(status != PEP_STATUS_OK);
   3.793 +    if (status != PEP_STATUS_OK)
   3.794 +        return status;
   3.795 +    
   3.796 +    if (identity->comm_type != PEP_ct_unknown &&
   3.797 +        outstanding_changes)
   3.798 +    {
   3.799 +        assert(session->examine_identity);
   3.800 +        if (session->examine_identity)
   3.801 +        {
   3.802 +            // This causes identity to be re-confronted and stored
   3.803 +            // asynchronously, by keymanagement thread.
   3.804 +            
   3.805 +            if (session->examine_identity(identity,
   3.806 +                                          session->examine_management))
   3.807 +            {
   3.808 +                return PEP_OUT_OF_MEMORY;
   3.809 +            }
   3.810 +        }
   3.811 +        else
   3.812 +        {
   3.813 +            // FIXME : having no keymanagement thread
   3.814 +            // shouldn't be allowed. Should return an error.
   3.815 +            
   3.816 +            status = set_identity(session, identity);
   3.817 +            assert(status == PEP_STATUS_OK);
   3.818 +            if (status != PEP_STATUS_OK) {
   3.819 +                return status;
   3.820 +            }
   3.821 +        }
   3.822 +    }
   3.823  
   3.824 -        if (EMPTYSTR(identity->username)) { // mitigate
   3.825 -            free(identity->username);
   3.826 -            identity->username = strdup("anonymous");
   3.827 -            if (identity->username == NULL)
   3.828 +    if (identity->comm_type != PEP_ct_compromized &&
   3.829 +        identity->comm_type < PEP_ct_strong_but_unconfirmed)
   3.830 +    {
   3.831 +        if (session->examine_identity)
   3.832 +        {
   3.833 +            // Pass only address to keymanagement thread
   3.834 +            // to trigger keyserver request
   3.835 +            pEp_identity *tmp_identity = new_identity(identity->address,
   3.836 +                                                      NULL, NULL, NULL);
   3.837 +            if (session->examine_identity(tmp_identity,
   3.838 +                                          session->examine_management))
   3.839 +            {
   3.840                  return PEP_OUT_OF_MEMORY;
   3.841 -            identity->username_size = 9;
   3.842 +            }
   3.843 +            free_identity(tmp_identity);
   3.844          }
   3.845 +    }
   3.846  
   3.847 -        status = set_identity(session, identity);
   3.848 +    return PEP_STATUS_OK;
   3.849 +}
   3.850 +
   3.851 +// This is meant to be called only from key management thread
   3.852 +// no concurrency is allowed here.
   3.853 +static PEP_STATUS ensure_own_key(PEP_SESSION session, pEp_identity * identity)
   3.854 +{
   3.855 +    PEP_STATUS status;
   3.856 +    bool revoked = false;
   3.857 +    
   3.858 +    assert(session);
   3.859 +    assert(identity);
   3.860 +    assert(!EMPTYSTR(identity->address));
   3.861 +    assert(!EMPTYSTR(identity->user_id));
   3.862 +    assert(identity->me);
   3.863 +    
   3.864 +    DEBUG_LOG("update_own_key", "debug", identity->address);
   3.865 +    
   3.866 +    if (!(session && identity &&
   3.867 +          identity->address &&
   3.868 +          identity->user_id &&
   3.869 +          identity->me))
   3.870 +    {
   3.871 +        return PEP_ILLEGAL_VALUE;
   3.872 +    }
   3.873 +    
   3.874 +    if (!EMPTYSTR(identity->fpr))
   3.875 +    {
   3.876 +        status = key_revoked(session, identity->fpr, &revoked);
   3.877 +        assert(status == PEP_STATUS_OK);
   3.878 +        if (status != PEP_STATUS_OK)
   3.879 +        {
   3.880 +            return status;
   3.881 +        }
   3.882 +    }
   3.883 +
   3.884 +    if (EMPTYSTR(identity->fpr) || revoked)
   3.885 +    {
   3.886 +        DEBUG_LOG("generating key pair", "debug", identity->address);
   3.887 +        
   3.888 +        free(identity->fpr);
   3.889 +        identity->fpr = NULL;
   3.890 +        
   3.891 +        status = generate_keypair(session, identity);
   3.892 +        assert(status != PEP_OUT_OF_MEMORY);
   3.893 +        if (status != PEP_STATUS_OK)
   3.894 +        {
   3.895 +            char buf[11];
   3.896 +            snprintf(buf, 11, "%d", status);
   3.897 +            DEBUG_LOG("generating key pair failed", "debug", buf);
   3.898 +            return status;
   3.899 +        }
   3.900 +        
   3.901 +        assert(!EMPTYSTR(identity->fpr));
   3.902 +        if (EMPTYSTR(identity->fpr))
   3.903 +        {
   3.904 +            return PEP_UNKNOWN_ERROR;
   3.905 +        }
   3.906 +    }
   3.907 +    else
   3.908 +    {
   3.909 +        bool expired;
   3.910 +        status = key_expired(session, identity->fpr, &expired);
   3.911          assert(status == PEP_STATUS_OK);
   3.912          if (status != PEP_STATUS_OK) {
   3.913              return status;
   3.914          }
   3.915 +        
   3.916 +        if (status == PEP_STATUS_OK && expired) {
   3.917 +            timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
   3.918 +            renew_key(session, identity->fpr, ts);
   3.919 +            free_timestamp(ts);
   3.920 +        }
   3.921      }
   3.922 -
   3.923 -    if (identity->comm_type != PEP_ct_compromized &&
   3.924 -            identity->comm_type < PEP_ct_strong_but_unconfirmed)
   3.925 -        if (session->examine_identity)
   3.926 -            session->examine_identity(identity, session->examine_management);
   3.927 -
   3.928 -    return status;
   3.929 +    
   3.930 +    return PEP_STATUS_OK;
   3.931  }
   3.932  
   3.933  DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
   3.934  {
   3.935      PEP_STATUS status;
   3.936 -    stringlist_t *keylist = NULL;
   3.937 +    bool outstanding_changes = false;
   3.938  
   3.939      assert(session);
   3.940      assert(identity);
   3.941 -    assert(identity->address);
   3.942 -    assert(identity->username);
   3.943 -    assert(identity->user_id);
   3.944 +    assert(!EMPTYSTR(identity->address));
   3.945 +    assert(!EMPTYSTR(identity->user_id));
   3.946  
   3.947 -    if (!(session && identity && identity->address && identity->username &&
   3.948 -                identity->user_id))
   3.949 +    if (!(session &&
   3.950 +          identity &&
   3.951 +          identity->address &&
   3.952 +          identity->user_id))
   3.953 +    {
   3.954          return PEP_ILLEGAL_VALUE;
   3.955 +    }
   3.956  
   3.957 -    identity->comm_type = PEP_ct_pEp;
   3.958      identity->me = true;
   3.959  
   3.960      DEBUG_LOG("myself", "debug", identity->address);
   3.961 -
   3.962 -    status = find_keys(session, identity->address, &keylist);
   3.963 -    assert(status != PEP_OUT_OF_MEMORY);
   3.964 -    if (status == PEP_OUT_OF_MEMORY)
   3.965 -        return PEP_OUT_OF_MEMORY;
   3.966 -
   3.967 -    if (keylist == NULL || keylist->value == NULL) {
   3.968 -        DEBUG_LOG("generating key pair", "debug", identity->address);
   3.969 -        status = generate_keypair(session, identity);
   3.970 -        assert(status != PEP_OUT_OF_MEMORY);
   3.971 -        if (status != PEP_STATUS_OK) {
   3.972 -            char buf[11];
   3.973 -            snprintf(buf, 11, "%d", status);
   3.974 -            DEBUG_LOG("generating key pair failed", "debug", buf);
   3.975 -            return status;
   3.976 +    
   3.977 +    status = confront_identity(session,
   3.978 +                               identity,
   3.979 +                               PEP_ct_pEp,
   3.980 +                               &outstanding_changes);
   3.981 +    
   3.982 +    assert(status != PEP_STATUS_OK);
   3.983 +    if (status != PEP_STATUS_OK)
   3.984 +        return status;
   3.985 +    
   3.986 +    if (identity->me &&
   3.987 +        identity->comm_type != PEP_ct_unknown)
   3.988 +    {
   3.989 +        if(outstanding_changes)
   3.990 +        {
   3.991 +            assert(session->examine_identity);
   3.992 +            if (session->examine_identity)
   3.993 +            {
   3.994 +                session->examine_identity(identity,
   3.995 +                                          session->examine_management);
   3.996 +            }
   3.997          }
   3.998 -
   3.999 -        status = find_keys(session, identity->address, &keylist);
  3.1000 -        assert(status != PEP_OUT_OF_MEMORY);
  3.1001 -        if (status == PEP_OUT_OF_MEMORY)
  3.1002 -            return PEP_OUT_OF_MEMORY;
  3.1003 -
  3.1004 -        assert(keylist && keylist->value);
  3.1005 -        if (keylist == NULL || keylist->value == NULL) {
  3.1006 -            return PEP_UNKNOWN_ERROR;
  3.1007 -        }
  3.1008 +        return PEP_STATUS_OK;
  3.1009      }
  3.1010 -    else {
  3.1011 -        bool expired;
  3.1012 -        status = key_expired(session, keylist->value, &expired);
  3.1013 -        assert(status == PEP_STATUS_OK);
  3.1014 -        if (status != PEP_STATUS_OK) {
  3.1015 -            goto free_keylist;
  3.1016 -        }
  3.1017 -
  3.1018 -        if (status == PEP_STATUS_OK && expired) {
  3.1019 -            timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
  3.1020 -            renew_key(session, keylist->value, ts);
  3.1021 -            free_timestamp(ts);
  3.1022 -        }
  3.1023 -    }
  3.1024 -
  3.1025 -    if (identity->fpr)
  3.1026 -        free(identity->fpr);
  3.1027 -    identity->fpr = strdup(keylist->value);
  3.1028 -    assert(identity->fpr);
  3.1029 -    if (identity->fpr == NULL){
  3.1030 -        status = PEP_OUT_OF_MEMORY;
  3.1031 -        goto free_keylist;
  3.1032 -    }
  3.1033 -    identity->fpr_size = strlen(identity->fpr);
  3.1034 -
  3.1035 -    status = set_identity(session, identity);
  3.1036 -    assert(status == PEP_STATUS_OK);
  3.1037 -    if (status != PEP_STATUS_OK) {
  3.1038 -        goto free_keylist;
  3.1039 -    }
  3.1040 -
  3.1041 -    return PEP_STATUS_OK;
  3.1042 -
  3.1043 -free_keylist:
  3.1044 -    free_stringlist(keylist);
  3.1045 -    return status;
  3.1046 +    
  3.1047 +    // FIXME : find better return value when identity ownership is refused
  3.1048 +    return PEP_KEY_NOT_FOUND;
  3.1049  }
  3.1050  
  3.1051  DYNAMIC_API PEP_STATUS register_examine_function(
  3.1052 @@ -326,7 +919,9 @@
  3.1053  {
  3.1054      PEP_SESSION session;
  3.1055      pEp_identity *identity;
  3.1056 +    pEp_identity *processed_identity = NULL;
  3.1057      PEP_STATUS status;
  3.1058 +    bool allow_keyserver_lookup = false;
  3.1059  
  3.1060      assert(retrieve_next_identity);
  3.1061      assert(management);
  3.1062 @@ -341,51 +936,280 @@
  3.1063  
  3.1064      log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
  3.1065  
  3.1066 -    while ((identity = retrieve_next_identity(management))) 
  3.1067 +    while ((identity = retrieve_next_identity(processed_identity,
  3.1068 +                                              management,
  3.1069 +                                              &allow_keyserver_lookup)))
  3.1070      {
  3.1071 -        assert(identity->address);
  3.1072 -        if(identity->address)
  3.1073 +        DEBUG_LOG("do_keymanagement", "retrieve_next_identity", NULL);
  3.1074 +        bool outstanding_changes = false;
  3.1075 +
  3.1076 +        if(processed_identity)
  3.1077 +        {
  3.1078 +            free_identity(processed_identity);
  3.1079 +            processed_identity = NULL;
  3.1080 +        }
  3.1081 +        
  3.1082 +        if (!EMPTYSTR(identity->address) &&
  3.1083 +            identity->me &&
  3.1084 +            !EMPTYSTR(identity->fpr) &&
  3.1085 +            identity->comm_type == PEP_ct_mistrusted &&
  3.1086 +            !EMPTYSTR(identity->user_id))
  3.1087 +        {
  3.1088 +            DEBUG_LOG("do_keymanagement", "revoking", identity->fpr);
  3.1089 +
  3.1090 +            // Case of own key to be revoked
  3.1091 +            status = revoke_key(session, identity->fpr, NULL);
  3.1092 +            
  3.1093 +            if (status == PEP_STATUS_OK)
  3.1094 +            {
  3.1095 +                // This changes the identity to match next if statement
  3.1096 +                identity->comm_type = PEP_ct_pEp;
  3.1097 +            }
  3.1098 +        }
  3.1099 +        
  3.1100 +        if (!EMPTYSTR(identity->address) &&
  3.1101 +            identity->me &&
  3.1102 +            identity->comm_type == PEP_ct_pEp &&
  3.1103 +            !EMPTYSTR(identity->user_id))
  3.1104 +        {
  3.1105 +            // Own identity issued by a call to Myself()
  3.1106 +            // or above revoked identity
  3.1107 +            
  3.1108 +            DEBUG_LOG("do_keymanagement", "confront_identity (me)",
  3.1109 +                      identity->address);
  3.1110 +            
  3.1111 +            status = confront_identity(session,
  3.1112 +                                       identity,
  3.1113 +                                       PEP_ct_pEp,
  3.1114 +                                       &outstanding_changes);
  3.1115 +            
  3.1116 +            if(status == PEP_STATUS_OK &&
  3.1117 +               identity->comm_type != PEP_ct_unknown &&
  3.1118 +               outstanding_changes)
  3.1119 +            {
  3.1120 +                
  3.1121 +                // TODO : move key-gen op to a different thread
  3.1122 +                //        keygen would then re-enqueue identity once
  3.1123 +                //        key would have been generated.
  3.1124 +                //        This would avoid blocking key management while
  3.1125 +                //        generating key.
  3.1126 +                
  3.1127 +                DEBUG_LOG("do_keymanagement", "ensure_own_key",
  3.1128 +                          identity->address);
  3.1129 +                
  3.1130 +                status = ensure_own_key(session, identity);
  3.1131 +                if(status == PEP_STATUS_OK &&
  3.1132 +                   identity->me)
  3.1133 +                {
  3.1134 +                    identity->comm_type = PEP_ct_pEp;
  3.1135 +
  3.1136 +                    DEBUG_LOG_IDENTITY("do_keymanagement",
  3.1137 +                                       "set_identity",
  3.1138 +                                       identity);
  3.1139 +                    
  3.1140 +                    status = set_identity(session, identity);
  3.1141 +                }
  3.1142 +            }
  3.1143 +        }
  3.1144 +        else if (!EMPTYSTR(identity->address) &&
  3.1145 +                 !identity->me &&
  3.1146 +                 !EMPTYSTR(identity->fpr) &&
  3.1147 +                 identity->comm_type != PEP_ct_unknown &&
  3.1148 +                 !EMPTYSTR(identity->user_id))
  3.1149          {
  3.1150 -            DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
  3.1151 +
  3.1152 +            // Identity with some outstanding changes. Could come from
  3.1153 +            //  update_identity or trust_personal_key
  3.1154 +            
  3.1155 +            DEBUG_LOG("do_keymanagement", "confront_identity",
  3.1156 +                      identity->address);
  3.1157 +            
  3.1158 +            status = confront_identity(session,
  3.1159 +                                       identity,
  3.1160 +                                       PEP_ct_unknown,
  3.1161 +                                       &outstanding_changes);
  3.1162 +
  3.1163 +            if(status == PEP_STATUS_OK &&
  3.1164 +               identity->comm_type != PEP_ct_unknown &&
  3.1165 +               outstanding_changes)
  3.1166 +            {
  3.1167 +                DEBUG_LOG_IDENTITY("do_keymanagement", "set_identity",
  3.1168 +                                   identity);
  3.1169 +                
  3.1170 +                status = set_identity(session, identity);
  3.1171 +            }
  3.1172 +        }
  3.1173 +        else if (EMPTYSTR(identity->address) &&
  3.1174 +                 !identity->me &&
  3.1175 +                 !EMPTYSTR(identity->fpr) &&
  3.1176 +                 EMPTYSTR(identity->user_id) &&
  3.1177 +                 EMPTYSTR(identity->username))
  3.1178 +        {
  3.1179 +            // Order to force or reset trust.
  3.1180 +            // For key_reset_trust and key_mistrusted
  3.1181 +            
  3.1182 +            DEBUG_LOG("do_keymanagement", "(un)forcing trust",
  3.1183 +                      identity->fpr);
  3.1184 +            
  3.1185 +
  3.1186 +            if (identity->comm_type == PEP_ct_mistrusted)
  3.1187 +            {
  3.1188 +                
  3.1189 +                // Mistrust Key
  3.1190 +                
  3.1191 +                DEBUG_LOG("do_keymanagement", "set_fpr_trust PEP_ct_mistrusted",
  3.1192 +                          identity->fpr);
  3.1193  
  3.1194 -            if (identity->me) {
  3.1195 -                status = myself(session, identity);
  3.1196 -            } else {
  3.1197 +                // XXX : shall we refuse to refuse to
  3.1198 +                //       set mistrust on created identities ?
  3.1199 +                
  3.1200 +                // Apply mistrust
  3.1201 +                status = set_fpr_trust(session,
  3.1202 +                                       identity->fpr,
  3.1203 +                                       PEP_ct_mistrusted);
  3.1204 +            }
  3.1205 +            else if (identity->comm_type == PEP_ct_unknown)
  3.1206 +            {
  3.1207 +                // Reset trust
  3.1208 +                
  3.1209 +                PEP_comm_type _least_comm_type = PEP_ct_unknown;
  3.1210 +                
  3.1211 +                status = least_trust(session, identity->fpr, &_least_comm_type);
  3.1212 +                
  3.1213 +                if (status == PEP_STATUS_OK ||
  3.1214 +                    status == PEP_CANNOT_FIND_IDENTITY)
  3.1215 +                {
  3.1216 +                    // refuse to reset compromized key
  3.1217 +                    if(_least_comm_type != PEP_ct_compromized)
  3.1218 +                    {
  3.1219 +                        // Reset trust for an fpr consist in setting
  3.1220 +                        // original key comm_type as new trust
  3.1221 +                        
  3.1222 +                        PEP_comm_type _comm_type_key;
  3.1223 +                        
  3.1224 +                        DEBUG_LOG("do_keymanagement",
  3.1225 +                                  "get_key_rating",
  3.1226 +                                  identity->fpr);
  3.1227 +                        
  3.1228 +                        status = get_key_rating(session,
  3.1229 +                                                identity->fpr,
  3.1230 +                                                &_comm_type_key);
  3.1231 +                        
  3.1232 +                        // XXX : shall we reset to PEP_ct_pEp for
  3.1233 +                        //       created identities ?
  3.1234 +                        
  3.1235 +                        if (status == PEP_STATUS_OK)
  3.1236 +                        {
  3.1237 +                            DEBUG_LOG("do_keymanagement",
  3.1238 +                                      "set_fpr_trust (key's comm_type)",
  3.1239 +                                      identity->fpr);
  3.1240 +                            
  3.1241 +                            // Apply key's comm_type as trust
  3.1242 +                            status = set_fpr_trust(session,
  3.1243 +                                                   identity->fpr,
  3.1244 +                                                   _comm_type_key);
  3.1245 +                        }
  3.1246 +                    }
  3.1247 +                }
  3.1248 +            }
  3.1249 +            else
  3.1250 +            {
  3.1251 +                DEBUG_LOG("do_keymanagement",
  3.1252 +                          "BUG : trying to force trust with "
  3.1253 +                           "inappropriate value !",
  3.1254 +                          NULL);
  3.1255 +                
  3.1256 +                assert(true);
  3.1257 +            }
  3.1258 +        }
  3.1259 +        else if (!EMPTYSTR(identity->address) &&
  3.1260 +                 !EMPTYSTR(identity->fpr) &&
  3.1261 +                 identity->comm_type == PEP_ct_unknown &&
  3.1262 +                 EMPTYSTR(identity->user_id) &&
  3.1263 +                 EMPTYSTR(identity->username))
  3.1264 +        {
  3.1265 +            // Key server lookup
  3.1266 +            
  3.1267 +            if (allow_keyserver_lookup)
  3.1268 +            {
  3.1269 +                DEBUG_LOG("do_keymanagement", "recv_key",
  3.1270 +                          identity->address);
  3.1271 +
  3.1272 +                // Key server requests only has address set.
  3.1273                  status = recv_key(session, identity->address);
  3.1274              }
  3.1275 +        }
  3.1276  
  3.1277 -            assert(status != PEP_OUT_OF_MEMORY);
  3.1278 -            if(status == PEP_OUT_OF_MEMORY)
  3.1279 -                return PEP_OUT_OF_MEMORY;
  3.1280 -        }
  3.1281 -        free_identity(identity);
  3.1282 +        assert(status != PEP_OUT_OF_MEMORY);
  3.1283 +        if(status == PEP_OUT_OF_MEMORY)
  3.1284 +            return PEP_OUT_OF_MEMORY;
  3.1285 +
  3.1286 +        processed_identity = identity;
  3.1287 +        allow_keyserver_lookup = false;
  3.1288      }
  3.1289  
  3.1290 +    if(processed_identity)
  3.1291 +    {
  3.1292 +        free_identity(processed_identity);
  3.1293 +        processed_identity = NULL;
  3.1294 +    }
  3.1295 +    
  3.1296      log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
  3.1297  
  3.1298      release(session);
  3.1299      return PEP_STATUS_OK;
  3.1300  }
  3.1301  
  3.1302 -DYNAMIC_API PEP_STATUS key_compromized(
  3.1303 +static PEP_STATUS _key_force_trust_async(
  3.1304 +       PEP_SESSION session,
  3.1305 +       pEp_identity *ident,
  3.1306 +       PEP_comm_type order
  3.1307 +   )
  3.1308 +{
  3.1309 +    PEP_STATUS status = PEP_STATUS_OK;
  3.1310 +    
  3.1311 +    assert(session);
  3.1312 +    assert(ident);
  3.1313 +    assert(!EMPTYSTR(ident->fpr));
  3.1314 +    
  3.1315 +    if (!(session && ident && ident->fpr))
  3.1316 +    {
  3.1317 +        return PEP_ILLEGAL_VALUE;
  3.1318 +    }
  3.1319 +    
  3.1320 +    if (session->examine_identity)
  3.1321 +    {
  3.1322 +        // Pass only fpr
  3.1323 +        pEp_identity *tmp_identity = new_identity(NULL, ident->fpr,
  3.1324 +                                                  NULL, NULL);
  3.1325 +        
  3.1326 +        // Management thread forces according to given order.
  3.1327 +        tmp_identity->comm_type = order;
  3.1328 +        
  3.1329 +        if (session->examine_identity(tmp_identity,
  3.1330 +                                      session->examine_management))
  3.1331 +        {
  3.1332 +            return PEP_OUT_OF_MEMORY;
  3.1333 +        }
  3.1334 +        free_identity(tmp_identity);
  3.1335 +    }
  3.1336 +    else
  3.1337 +    {
  3.1338 +        return PEP_NO_MANAGEMENT_THREAD;
  3.1339 +    }
  3.1340 +    
  3.1341 +    return status;
  3.1342 +}
  3.1343 +
  3.1344 +
  3.1345 +
  3.1346 +
  3.1347 +DYNAMIC_API PEP_STATUS key_mistrusted(
  3.1348          PEP_SESSION session,
  3.1349          pEp_identity *ident
  3.1350      )
  3.1351  {
  3.1352 -    PEP_STATUS status = PEP_STATUS_OK;
  3.1353 -
  3.1354 -    assert(session);
  3.1355 -    assert(ident);
  3.1356 -    assert(!EMPTYSTR(ident->fpr));
  3.1357 -
  3.1358 -    if (!(session && ident && ident->fpr))
  3.1359 -        return PEP_ILLEGAL_VALUE;
  3.1360 -
  3.1361 -    if (ident->me)
  3.1362 -        revoke_key(session, ident->fpr, NULL);
  3.1363 -    status = mark_as_compromized(session, ident->fpr);
  3.1364 -
  3.1365 -    return status;
  3.1366 +    return _key_force_trust_async(session, ident, PEP_ct_mistrusted);
  3.1367  }
  3.1368  
  3.1369  DYNAMIC_API PEP_STATUS key_reset_trust(
  3.1370 @@ -393,35 +1217,7 @@
  3.1371          pEp_identity *ident
  3.1372      )
  3.1373  {
  3.1374 -    PEP_STATUS status = PEP_STATUS_OK;
  3.1375 -
  3.1376 -    assert(session);
  3.1377 -    assert(ident);
  3.1378 -    assert(!ident->me);
  3.1379 -    assert(!EMPTYSTR(ident->fpr));
  3.1380 -    assert(!EMPTYSTR(ident->address));
  3.1381 -    assert(!EMPTYSTR(ident->user_id));
  3.1382 -
  3.1383 -    if (!(session && ident && !ident->me && ident->fpr && ident->address &&
  3.1384 -            ident->user_id))
  3.1385 -        return PEP_ILLEGAL_VALUE;
  3.1386 -
  3.1387 -    status = update_identity(session, ident);
  3.1388 -    if (status != PEP_STATUS_OK)
  3.1389 -        return status;
  3.1390 -
  3.1391 -    if (ident->comm_type == PEP_ct_mistrusted)
  3.1392 -        ident->comm_type = PEP_ct_unknown;
  3.1393 -    else
  3.1394 -        ident->comm_type &= ~PEP_ct_confirmed;
  3.1395 -
  3.1396 -    status = set_identity(session, ident);
  3.1397 -    if (status != PEP_STATUS_OK)
  3.1398 -        return status;
  3.1399 -
  3.1400 -    if (ident->comm_type == PEP_ct_unknown)
  3.1401 -        status = update_identity(session, ident);
  3.1402 -    return status;
  3.1403 +    return _key_force_trust_async(session, ident, PEP_ct_mistrusted);
  3.1404  }
  3.1405  
  3.1406  DYNAMIC_API PEP_STATUS trust_personal_key(
  3.1407 @@ -430,6 +1226,7 @@
  3.1408      )
  3.1409  {
  3.1410      PEP_STATUS status = PEP_STATUS_OK;
  3.1411 +    bool outstanding_changes = false;
  3.1412  
  3.1413      assert(session);
  3.1414      assert(ident);
  3.1415 @@ -438,17 +1235,48 @@
  3.1416      assert(!EMPTYSTR(ident->fpr));
  3.1417      assert(!ident->me);
  3.1418  
  3.1419 -    if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
  3.1420 -            EMPTYSTR(ident->fpr) || ident->me)
  3.1421 +    if (!(session &&
  3.1422 +          ident &&
  3.1423 +          !EMPTYSTR(ident->address) &&
  3.1424 +          !EMPTYSTR(ident->user_id) &&
  3.1425 +          !EMPTYSTR(ident->fpr) &&
  3.1426 +          !ident->me))
  3.1427 +    {
  3.1428          return PEP_ILLEGAL_VALUE;
  3.1429 +    }
  3.1430  
  3.1431 -    status = update_identity(session, ident);
  3.1432 +    status = confront_identity(session,
  3.1433 +                               ident,
  3.1434 +                               PEP_ct_confirmed,
  3.1435 +                               &outstanding_changes);
  3.1436 +    
  3.1437      if (status != PEP_STATUS_OK)
  3.1438          return status;
  3.1439  
  3.1440 -    if (ident->comm_type > PEP_ct_strong_but_unconfirmed) {
  3.1441 +    if (ident->comm_type > PEP_ct_strong_but_unconfirmed &&
  3.1442 +        outstanding_changes)
  3.1443 +    {
  3.1444          ident->comm_type |= PEP_ct_confirmed;
  3.1445 -        status = set_identity(session, ident);
  3.1446 +        
  3.1447 +        if (session->examine_identity)
  3.1448 +        {
  3.1449 +            if (session->examine_identity(ident,
  3.1450 +                                          session->examine_management))
  3.1451 +            {
  3.1452 +                return PEP_OUT_OF_MEMORY;
  3.1453 +            }
  3.1454 +        }
  3.1455 +        else
  3.1456 +        {
  3.1457 +            // FIXME : having no keymanagement thread
  3.1458 +            // shouldn't be allowed.
  3.1459 +            
  3.1460 +            status = set_identity(session, ident);
  3.1461 +            assert(status == PEP_STATUS_OK);
  3.1462 +            if (status != PEP_STATUS_OK) {
  3.1463 +                return status;
  3.1464 +            }
  3.1465 +        }
  3.1466      }
  3.1467      else {
  3.1468          // MISSING: S/MIME has to be handled depending on trusted CAs
     4.1 --- a/src/keymanagement.h	Wed Apr 06 17:00:54 2016 +0200
     4.2 +++ b/src/keymanagement.h	Mon Apr 25 14:53:45 2016 +0200
     4.3 @@ -47,7 +47,13 @@
     4.4  // retrieve_next_identity() - callback being called by do_keymanagement()
     4.5  //
     4.6  //  parameters:
     4.7 -//      management (in)     data structure to deliver (implementation defined)
     4.8 +//      management (in)               data structure to deliver
     4.9 +//                                    (implementation defined)
    4.10 +//      processed_identity (in)       identity previously processed
    4.11 +//                                    by management
    4.12 +//      allow_keyserver_lookup (out)  allow management to lookup for
    4.13 +//                                    missing key on keyserver
    4.14 +//                                    (applies only on returned identity)
    4.15  //
    4.16  //  return value:
    4.17  //      identity to check or NULL to terminate do_keymanagement()
    4.18 @@ -59,8 +65,13 @@
    4.19  //      this callback has to block until an identity or NULL can be returned
    4.20  //      an implementation is not provided by this library; instead it has to be
    4.21  //      implemented by the user of this library
    4.22 +//      memory ownership of indentity remains to pEpEngine
    4.23  
    4.24 -typedef pEp_identity *(*retrieve_next_identity_t)(void *management);
    4.25 +typedef pEp_identity *(*retrieve_next_identity_t)(
    4.26 +        pEp_identity * processed_identity,
    4.27 +        void *management,
    4.28 +        bool *allow_keyserver_lookup
    4.29 +    );
    4.30  
    4.31  
    4.32  // examine_identity() - callback for appending to queue
    4.33 @@ -113,13 +124,13 @@
    4.34      );
    4.35  
    4.36  
    4.37 -// key_compromized() - mark key as being compromized
    4.38 +// key_mistrusted() - mark key as being compromized
    4.39  //
    4.40  //  parameters:
    4.41  //      session (in)        session to use
    4.42  //      ident (in)          person and key which was compromized
    4.43  
    4.44 -DYNAMIC_API PEP_STATUS key_compromized(
    4.45 +DYNAMIC_API PEP_STATUS key_mistrusted(
    4.46          PEP_SESSION session,
    4.47          pEp_identity *ident
    4.48      );
    4.49 @@ -140,7 +151,7 @@
    4.50      );
    4.51  
    4.52  
    4.53 -// key_reset_trust() - undo trust_personal_key and key_compromized() for keys
    4.54 +// key_reset_trust() - undo trust_personal_key and key_mistrusted() for keys
    4.55  //                     we don't own
    4.56  //
    4.57  //  parameters:
     5.1 --- a/src/message_api.c	Wed Apr 06 17:00:54 2016 +0200
     5.2 +++ b/src/message_api.c	Mon Apr 25 14:53:45 2016 +0200
     5.3 @@ -809,25 +809,18 @@
     5.4      pEp_identity *ident
     5.5      )
     5.6  {
     5.7 -    PEP_STATUS status = update_identity(session, ident);
     5.8 -
     5.9      if (max_comm_type == PEP_ct_compromized)
    5.10          return PEP_ct_compromized;
    5.11      
    5.12      if (max_comm_type == PEP_ct_mistrusted)
    5.13          return PEP_ct_mistrusted;
    5.14  
    5.15 -    if (status == PEP_STATUS_OK) {
    5.16 -        if (ident->comm_type == PEP_ct_compromized)
    5.17 -            return PEP_ct_compromized;
    5.18 -        else if (ident->comm_type == PEP_ct_mistrusted)
    5.19 -            return PEP_ct_mistrusted;
    5.20 -        else
    5.21 -            return MIN(max_comm_type, ident->comm_type);
    5.22 -    }
    5.23 -    else {
    5.24 -        return PEP_ct_unknown;
    5.25 -    }
    5.26 +    if (ident->comm_type == PEP_ct_compromized)
    5.27 +        return PEP_ct_compromized;
    5.28 +    else if (ident->comm_type == PEP_ct_mistrusted)
    5.29 +        return PEP_ct_mistrusted;
    5.30 +    else
    5.31 +        return MIN(max_comm_type, ident->comm_type);
    5.32  }
    5.33  
    5.34  void import_attached_keys(PEP_SESSION session, const message *msg)
     6.1 --- a/src/pEpEngine.c	Wed Apr 06 17:00:54 2016 +0200
     6.2 +++ b/src/pEpEngine.c	Mon Apr 25 14:53:45 2016 +0200
     6.3 @@ -13,13 +13,15 @@
     6.4  	static const char *sql_log;
     6.5  	static const char *sql_trustword;
     6.6  	static const char *sql_get_identity;
     6.7 +    static const char *sql_get_best_user;
     6.8  	static const char *sql_set_person;
     6.9  	static const char *sql_set_pgp_keypair;
    6.10 +    static const char *sql_get_pgp_keypair_created;
    6.11  	static const char *sql_set_identity;
    6.12  	static const char *sql_set_trust;
    6.13      static const char *sql_get_trust;
    6.14      static const char *sql_least_trust;
    6.15 -    static const char *sql_mark_as_compromized;
    6.16 +    static const char *sql_set_fpr_trust;
    6.17      static const char *sql_crashdump;
    6.18      static const char *sql_languagelist;
    6.19      static const char *sql_i18n_token;
    6.20 @@ -127,12 +129,9 @@
    6.21                  "   expires integer,\n"
    6.22                  "   comment text\n"
    6.23                  ");\n"
    6.24 -                "create index if not exists pgp_keypair_expires on pgp_keypair (\n"
    6.25 -                "   expires\n"
    6.26 -                ");\n"
    6.27                  "create table if not exists person (\n"
    6.28                  "   id text primary key,\n"
    6.29 -                "   username text not null,\n"
    6.30 +                "   username text,\n"
    6.31                  "   main_key_id text\n"
    6.32                  "       references pgp_keypair (fpr)\n"
    6.33                  "       on delete set null,\n"
    6.34 @@ -140,14 +139,15 @@
    6.35                  "   comment text\n"
    6.36                  ");\n"
    6.37                  "create table if not exists identity (\n"
    6.38 -                "   address text primary key,\n"
    6.39 +                "   address text,\n"
    6.40                  "   user_id text\n"
    6.41                  "       references person (id)\n"
    6.42                  "       on delete cascade,\n"
    6.43                  "   main_key_id text\n"
    6.44                  "       references pgp_keypair (fpr)\n"
    6.45                  "       on delete set null,\n"
    6.46 -                "   comment text\n"
    6.47 +                "   comment text,\n"
    6.48 +                "   primary key (address, user_id)\n"
    6.49                  ");\n"
    6.50                  "create table if not exists trust (\n"
    6.51                  "   user_id text not null\n"
    6.52 @@ -186,36 +186,64 @@
    6.53          sql_log = "insert into log (title, entity, description, comment)"
    6.54                    "values (?1, ?2, ?3, ?4);";
    6.55  
    6.56 -        sql_get_identity =	"select fpr, identity.user_id, username, comm_type, lang"
    6.57 +        sql_get_identity =	"select fpr, username, comm_type, lang, pgp_keypair.created"
    6.58                              "   from identity"
    6.59                              "   join person on id = identity.user_id"
    6.60                              "   join pgp_keypair on fpr = identity.main_key_id"
    6.61                              "   join trust on id = trust.user_id"
    6.62                              "       and pgp_keypair_fpr = identity.main_key_id"
    6.63 -                            "   where address = ?1 ;";
    6.64 +                            "   where address = ?1 and identity.user_id = ?2;";
    6.65 +
    6.66 +        sql_get_best_user = "select identity.user_id"
    6.67 +                            "   from identity"
    6.68 +                            "   join trust on trust.user_id = identity.user_id"
    6.69 +                            "       and pgp_keypair_fpr = identity.main_key_id"
    6.70 +                            "   where address = ?1"
    6.71 +                            "   order by comm_type DESC, identity.rowid DESC"
    6.72 +                            "   limit 1;";
    6.73  
    6.74          sql_trustword = "select id, word from wordlist where lang = lower(?1) "
    6.75                         "and id = ?2 ;";
    6.76  
    6.77 -        sql_set_person = "insert or replace into person (id, username, lang) "
    6.78 -                         "values (?1, ?2, ?3) ;";
    6.79 +        // "replace" cannot be used here because of "on delete" triggers
    6.80 +        // First try to update, then try to insert.
    6.81 +        // Update is first to avoid firing unnecessary triggers.
    6.82 +        sql_set_person = "update or ignore person"
    6.83 +                         "    set username = ?2,"
    6.84 +                         "        lang = ?3"
    6.85 +                         "    where id = ?1;\n"
    6.86 +                         "insert or ignore into person (id, username, lang)"
    6.87 +                         "    values (?1, ?2, ?3);";
    6.88  
    6.89 -        sql_set_pgp_keypair = "insert or replace into pgp_keypair (fpr) "
    6.90 -                              "values (?1) ;";
    6.91 +        // Use pgp_keypair.created to mark keys created by pEp (i.e. own keys)
    6.92 +        // Once set, "created" cannot be reset.
    6.93 +        //
    6.94 +        // "replace" cannot be used here because of "on delete" triggers
    6.95 +        sql_set_pgp_keypair = "update or ignore pgp_keypair"
    6.96 +                              "    set created = case created"
    6.97 +                              "                    when 0 then ?2"
    6.98 +                              "                    else created"
    6.99 +                              "                  end"
   6.100 +                              "    where fpr = upper(replace(?1,' ','')) ;\n"
   6.101 +                              "insert or ignore into pgp_keypair (fpr, created)"
   6.102 +                              "    values (upper(replace(?1,' ','')), ?2) ;";
   6.103 +        
   6.104 +        sql_get_pgp_keypair_created = "select created from pgp_keypair"
   6.105 +                                      "    where fpr = upper(replace(?1,' ',''));";
   6.106  
   6.107          sql_set_identity = "insert or replace into identity (address, main_key_id, "
   6.108 -                           "user_id) values (?1, ?2, ?3) ;";
   6.109 +                           "user_id) values (?1, upper(replace(?2,' ','')), ?3) ;";
   6.110  
   6.111          sql_set_trust = "insert or replace into trust (user_id, pgp_keypair_fpr, comm_type) "
   6.112 -                        "values (?1, ?2, ?3) ;";
   6.113 +                        "values (?1, upper(replace(?2,' ','')), ?3) ;";
   6.114  
   6.115 -        sql_get_trust = "select user_id, comm_type from trust where user_id = ?1 "
   6.116 -                        "and pgp_keypair_fpr = ?2 ;";
   6.117 +        sql_get_trust = "select comm_type from trust where user_id = ?1 "
   6.118 +                        "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;";
   6.119  
   6.120 -        sql_least_trust = "select min(comm_type) from trust where pgp_keypair_fpr = ?1 ;";
   6.121 +        sql_least_trust = "select min(comm_type) from trust where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   6.122  
   6.123 -        sql_mark_as_compromized = "update trust not indexed set comm_type = 15"
   6.124 -                                  " where pgp_keypair_fpr = ?1 ;";
   6.125 +        sql_set_fpr_trust = "update trust not indexed set comm_type = ?2"
   6.126 +                                  " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   6.127  
   6.128          sql_crashdump = "select timestamp, title, entity, description, comment"
   6.129                          " from log order by timestamp desc limit ?1 ;";
   6.130 @@ -226,13 +254,13 @@
   6.131  
   6.132          // blacklist
   6.133  
   6.134 -        sql_blacklist_add = "insert or replace into blacklist_keys (fpr) values (?1) ;"
   6.135 -                            "delete from identity where main_key_id = ?1 ;"
   6.136 -                            "delete from pgp_keypair where fpr = ?1 ;";
   6.137 +        sql_blacklist_add = "insert or replace into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;"
   6.138 +                            "delete from identity where main_key_id = upper(replace(?1,' ','')) ;"
   6.139 +                            "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;";
   6.140  
   6.141 -        sql_blacklist_delete = "delete from blacklist_keys where fpr = ?1 ;";
   6.142 +        sql_blacklist_delete = "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   6.143  
   6.144 -        sql_blacklist_is_listed = "select count(*) from blacklist_keys where fpr = ?1 ;";
   6.145 +        sql_blacklist_is_listed = "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   6.146  
   6.147          sql_blacklist_retrieve = "select * from blacklist_keys ;";
   6.148      }
   6.149 @@ -248,6 +276,10 @@
   6.150      int_result = sqlite3_prepare_v2(_session->db, sql_get_identity,
   6.151              (int)strlen(sql_get_identity), &_session->get_identity, NULL);
   6.152  	assert(int_result == SQLITE_OK);
   6.153 +    
   6.154 +    int_result = sqlite3_prepare_v2(_session->db, sql_get_best_user,
   6.155 +            (int)strlen(sql_get_best_user), &_session->get_best_user, NULL);
   6.156 +    assert(int_result == SQLITE_OK);
   6.157  
   6.158      int_result = sqlite3_prepare_v2(_session->db, sql_set_person,
   6.159              (int)strlen(sql_set_person), &_session->set_person, NULL);
   6.160 @@ -257,6 +289,11 @@
   6.161              (int)strlen(sql_set_pgp_keypair), &_session->set_pgp_keypair, NULL);
   6.162  	assert(int_result == SQLITE_OK);
   6.163  
   6.164 +    int_result = sqlite3_prepare_v2(_session->db, sql_get_pgp_keypair_created,
   6.165 +            (int)strlen(sql_get_pgp_keypair_created), &_session->get_pgp_keypair_created, NULL);
   6.166 +    const char *plop = sqlite3_errmsg(_session->db);
   6.167 +	assert(int_result == SQLITE_OK);
   6.168 +
   6.169      int_result = sqlite3_prepare_v2(_session->db, sql_set_identity,
   6.170              (int)strlen(sql_set_identity), &_session->set_identity, NULL);
   6.171  	assert(int_result == SQLITE_OK);
   6.172 @@ -273,8 +310,8 @@
   6.173              (int)strlen(sql_least_trust), &_session->least_trust, NULL);
   6.174      assert(int_result == SQLITE_OK);
   6.175  
   6.176 -    int_result = sqlite3_prepare_v2(_session->db, sql_mark_as_compromized,
   6.177 -            (int)strlen(sql_mark_as_compromized), &_session->mark_compromized, NULL);
   6.178 +    int_result = sqlite3_prepare_v2(_session->db, sql_set_fpr_trust,
   6.179 +            (int)strlen(sql_set_fpr_trust), &_session->mark_compromized, NULL);
   6.180      assert(int_result == SQLITE_OK);
   6.181  
   6.182      int_result = sqlite3_prepare_v2(_session->db, sql_crashdump,
   6.183 @@ -360,10 +397,14 @@
   6.184                  sqlite3_finalize(session->trustword);
   6.185              if (session->get_identity)
   6.186                  sqlite3_finalize(session->get_identity);
   6.187 +            if (session->get_best_user)
   6.188 +                sqlite3_finalize(session->get_best_user);
   6.189              if (session->set_person)
   6.190                  sqlite3_finalize(session->set_person);
   6.191              if (session->set_pgp_keypair)
   6.192                  sqlite3_finalize(session->set_pgp_keypair);
   6.193 +            if (session->get_pgp_keypair_created)
   6.194 +                sqlite3_finalize(session->get_pgp_keypair_created);
   6.195              if (session->set_identity)
   6.196                  sqlite3_finalize(session->set_identity);
   6.197              if (session->set_trust)
   6.198 @@ -670,8 +711,23 @@
   6.199      }
   6.200  }
   6.201  
   6.202 +static void _set_identity_lang(pEp_identity *identity, 	const char *lang)
   6.203 +{
   6.204 +    if (lang && lang[0]) {
   6.205 +        assert(lang[0] >= 'a' && lang[0] <= 'z');
   6.206 +        assert(lang[1] >= 'a' && lang[1] <= 'z');
   6.207 +        assert(lang[2] == 0);
   6.208 +        // FIXME : assert without if
   6.209 +        identity->lang[0] = lang[0];
   6.210 +        identity->lang[1] = lang[1];
   6.211 +        identity->lang[2] = 0;
   6.212 +    }
   6.213 +}
   6.214 +
   6.215  DYNAMIC_API PEP_STATUS get_identity(
   6.216 -        PEP_SESSION session, const char *address,
   6.217 +        PEP_SESSION session,
   6.218 +        const char *address,
   6.219 +        const char *user_id,
   6.220          pEp_identity **identity
   6.221      )
   6.222  {
   6.223 @@ -689,6 +745,7 @@
   6.224  
   6.225      sqlite3_reset(session->get_identity);
   6.226      sqlite3_bind_text(session->get_identity, 1, address, -1, SQLITE_STATIC);
   6.227 +    sqlite3_bind_text(session->get_identity, 2, user_id, -1, SQLITE_STATIC);
   6.228  
   6.229      result = sqlite3_step(session->get_identity);
   6.230  	switch (result) {
   6.231 @@ -696,23 +753,17 @@
   6.232          _identity = new_identity(
   6.233                  address,
   6.234                  (const char *) sqlite3_column_text(session->get_identity, 0),
   6.235 -                (const char *) sqlite3_column_text(session->get_identity, 1),
   6.236 -                (const char *) sqlite3_column_text(session->get_identity, 2)
   6.237 +                user_id,
   6.238 +                (const char *) sqlite3_column_text(session->get_identity, 1)
   6.239                  );
   6.240          assert(_identity);
   6.241          if (_identity == NULL)
   6.242              return PEP_OUT_OF_MEMORY;
   6.243  
   6.244 -        _identity->comm_type = (PEP_comm_type) sqlite3_column_int(session->get_identity, 3);
   6.245 -        _lang = (const char *) sqlite3_column_text(session->get_identity, 4);
   6.246 -        if (_lang && _lang[0]) {
   6.247 -			assert(_lang[0] >= 'a' && _lang[0] <= 'z');
   6.248 -			assert(_lang[1] >= 'a' && _lang[1] <= 'z');
   6.249 -			assert(_lang[2] == 0);
   6.250 -			_identity->lang[0] = _lang[0];
   6.251 -			_identity->lang[1] = _lang[1];
   6.252 -            _identity->lang[2] = 0;
   6.253 -		}
   6.254 +        _identity->comm_type = (PEP_comm_type) sqlite3_column_int(session->get_identity, 2);
   6.255 +        _lang = (const char *) sqlite3_column_text(session->get_identity, 3);
   6.256 +        _set_identity_lang(_identity,_lang);
   6.257 +        _identity->me = (PEP_comm_type) sqlite3_column_int(session->get_identity, 4);
   6.258  		*identity = _identity;
   6.259  		break;
   6.260  	default:
   6.261 @@ -724,6 +775,41 @@
   6.262  	return status;
   6.263  }
   6.264  
   6.265 +DYNAMIC_API PEP_STATUS get_best_user(
   6.266 +       PEP_SESSION session,
   6.267 +       const char *address,
   6.268 +       char **user_id
   6.269 +    )
   6.270 +{
   6.271 +    PEP_STATUS status = PEP_STATUS_OK;
   6.272 +    int result;
   6.273 +    
   6.274 +    assert(session);
   6.275 +    assert(address);
   6.276 +    assert(user_id);
   6.277 +    
   6.278 +    *user_id = NULL;
   6.279 +    
   6.280 +    if (!(session && address && user_id))
   6.281 +        return PEP_ILLEGAL_VALUE;
   6.282 +    
   6.283 +    sqlite3_reset(session->get_best_user);
   6.284 +    sqlite3_bind_text(session->get_best_user, 1, address, -1, SQLITE_STATIC);
   6.285 +    
   6.286 +    result = sqlite3_step(session->get_best_user);
   6.287 +    switch (result) {
   6.288 +        case SQLITE_ROW: {
   6.289 +            *user_id = strdup((const char *)sqlite3_column_text(session->get_identity, 0));
   6.290 +            break;
   6.291 +        }
   6.292 +        default:
   6.293 +            status = PEP_CANNOT_FIND_IDENTITY;
   6.294 +    }
   6.295 +    
   6.296 +    sqlite3_reset(session->get_best_user);
   6.297 +    return status;
   6.298 +}
   6.299 +
   6.300  DYNAMIC_API PEP_STATUS set_identity(
   6.301          PEP_SESSION session, const pEp_identity *identity
   6.302      )
   6.303 @@ -735,10 +821,9 @@
   6.304  	assert(identity->address);
   6.305  	assert(identity->fpr);
   6.306  	assert(identity->user_id);
   6.307 -	assert(identity->username);
   6.308  
   6.309      if (!(session && identity && identity->address && identity->fpr &&
   6.310 -                identity->user_id && identity->username))
   6.311 +                identity->user_id))
   6.312          return PEP_ILLEGAL_VALUE;
   6.313  
   6.314      bool listed;
   6.315 @@ -755,9 +840,18 @@
   6.316  	sqlite3_reset(session->set_person);
   6.317      sqlite3_bind_text(session->set_person, 1, identity->user_id, -1,
   6.318              SQLITE_STATIC);
   6.319 -    sqlite3_bind_text(session->set_person, 2, identity->username, -1,
   6.320 -            SQLITE_STATIC);
   6.321 -	if (identity->lang[0])
   6.322 +
   6.323 +    if(!identity->username || identity->username[0]==0)
   6.324 +    {
   6.325 +        sqlite3_bind_null(session->set_person, 2);
   6.326 +    }
   6.327 +    else
   6.328 +    {
   6.329 +        sqlite3_bind_text(session->set_person, 2, identity->username, -1,
   6.330 +                          SQLITE_STATIC);
   6.331 +    }
   6.332 +
   6.333 +    if (identity->lang[0])
   6.334          sqlite3_bind_text(session->set_person, 3, identity->lang, 1,
   6.335                  SQLITE_STATIC);
   6.336  	else
   6.337 @@ -772,6 +866,7 @@
   6.338  	sqlite3_reset(session->set_pgp_keypair);
   6.339      sqlite3_bind_text(session->set_pgp_keypair, 1, identity->fpr, -1,
   6.340              SQLITE_STATIC);
   6.341 +    sqlite3_bind_int(session->set_pgp_keypair, 2, identity->me);
   6.342  	result = sqlite3_step(session->set_pgp_keypair);
   6.343  	sqlite3_reset(session->set_pgp_keypair);
   6.344  	if (result != SQLITE_DONE) {
   6.345 @@ -813,9 +908,11 @@
   6.346  		return PEP_COMMIT_FAILED;
   6.347  }
   6.348  
   6.349 -DYNAMIC_API PEP_STATUS mark_as_compromized(
   6.350 +DYNAMIC_API PEP_STATUS set_fpr_trust(
   6.351          PEP_SESSION session,
   6.352 -        const char *fpr
   6.353 +        const char *fpr,
   6.354 +        PEP_comm_type trust
   6.355 +                                     
   6.356      )
   6.357  {
   6.358  	int result;
   6.359 @@ -829,6 +926,8 @@
   6.360  	sqlite3_reset(session->mark_compromized);
   6.361      sqlite3_bind_text(session->mark_compromized, 1, fpr, -1,
   6.362              SQLITE_STATIC);
   6.363 +    sqlite3_bind_int(session->set_trust, 2, trust);
   6.364 +
   6.365      result = sqlite3_step(session->mark_compromized);
   6.366  	sqlite3_reset(session->mark_compromized);
   6.367  
   6.368 @@ -868,16 +967,7 @@
   6.369      result = sqlite3_step(session->get_trust);
   6.370      switch (result) {
   6.371      case SQLITE_ROW: {
   6.372 -        const char * user_id = (const char *) sqlite3_column_text(session->get_trust, 0);
   6.373 -        int comm_type = (PEP_comm_type) sqlite3_column_int(session->get_trust, 1);
   6.374 -
   6.375 -        if (strcmp(user_id, identity->user_id) != 0) {
   6.376 -            free(identity->user_id);
   6.377 -            identity->user_id = strdup(user_id);
   6.378 -            assert(identity->user_id);
   6.379 -            if (identity->user_id == NULL)
   6.380 -                return PEP_OUT_OF_MEMORY;
   6.381 -        }
   6.382 +        int comm_type = (PEP_comm_type) sqlite3_column_int(session->get_trust, 0);
   6.383          identity->comm_type = comm_type;
   6.384          break;
   6.385      }
   6.386 @@ -926,6 +1016,45 @@
   6.387      return status;
   6.388  }
   6.389  
   6.390 +
   6.391 +DYNAMIC_API PEP_STATUS get_pgp_keypair_created(
   6.392 +        PEP_SESSION session,
   6.393 +        const char *fpr,
   6.394 +        int *created
   6.395 +    )
   6.396 +{
   6.397 +    PEP_STATUS status = PEP_STATUS_OK;
   6.398 +    int result;
   6.399 +
   6.400 +    assert(session);
   6.401 +    assert(fpr);
   6.402 +    assert(created);
   6.403 +
   6.404 +    *created = PEP_ct_unknown;
   6.405 +
   6.406 +    if (!(session && fpr && created))
   6.407 +        return PEP_ILLEGAL_VALUE;
   6.408 +
   6.409 +    sqlite3_reset(session->get_pgp_keypair_created);
   6.410 +    sqlite3_bind_text(session->get_pgp_keypair_created, 1, fpr, -1, SQLITE_STATIC);
   6.411 +
   6.412 +    result = sqlite3_step(session->get_pgp_keypair_created);
   6.413 +    switch (result) {
   6.414 +        case SQLITE_ROW: {
   6.415 +            *created = sqlite3_column_int(session->get_pgp_keypair_created, 0);
   6.416 +            break;
   6.417 +        }
   6.418 +        default:
   6.419 +            status = PEP_CANNOT_FIND_IDENTITY;
   6.420 +    }
   6.421 +
   6.422 +    sqlite3_reset(session->get_pgp_keypair_created);
   6.423 +    return status;
   6.424 +}
   6.425 +
   6.426 +
   6.427 +
   6.428 +
   6.429  DYNAMIC_API PEP_STATUS decrypt_and_verify(
   6.430      PEP_SESSION session, const char *ctext, size_t csize,
   6.431      char **ptext, size_t *psize, stringlist_t **keylist
   6.432 @@ -1134,6 +1263,23 @@
   6.433              expired);
   6.434  }
   6.435  
   6.436 +DYNAMIC_API PEP_STATUS key_revoked(
   6.437 +        PEP_SESSION session,
   6.438 +        const char *fpr,
   6.439 +        bool *revoked
   6.440 +    )
   6.441 +{
   6.442 +    assert(session);
   6.443 +    assert(fpr);
   6.444 +    assert(revoked);
   6.445 +    
   6.446 +    if (!(session && fpr && revoked))
   6.447 +        return PEP_ILLEGAL_VALUE;
   6.448 +    
   6.449 +    return session->cryptotech[PEP_crypt_OpenPGP].key_revoked(session, fpr,
   6.450 +            revoked);
   6.451 +}
   6.452 +
   6.453  static void _clean_log_value(char *text)
   6.454  {
   6.455      if (text) {
     7.1 --- a/src/pEpEngine.h	Wed Apr 06 17:00:54 2016 +0200
     7.2 +++ b/src/pEpEngine.h	Mon Apr 25 14:53:45 2016 +0200
     7.3 @@ -27,54 +27,55 @@
     7.4  typedef enum {
     7.5  	PEP_STATUS_OK									= 0,
     7.6  
     7.7 -	PEP_INIT_CANNOT_LOAD_GPGME						= 0x0110,
     7.8 -	PEP_INIT_GPGME_INIT_FAILED						= 0x0111,
     7.9 -	PEP_INIT_NO_GPG_HOME							= 0x0112,
    7.10 -	PEP_INIT_NETPGP_INIT_FAILED						= 0x0113,
    7.11 +	PEP_INIT_CANNOT_LOAD_GPGME                      = 0x0110,
    7.12 +	PEP_INIT_GPGME_INIT_FAILED                      = 0x0111,
    7.13 +	PEP_INIT_NO_GPG_HOME                            = 0x0112,
    7.14 +	PEP_INIT_NETPGP_INIT_FAILED                     = 0x0113,
    7.15  
    7.16 -	PEP_INIT_SQLITE3_WITHOUT_MUTEX					= 0x0120,
    7.17 -	PEP_INIT_CANNOT_OPEN_DB							= 0x0121,
    7.18 -	PEP_INIT_CANNOT_OPEN_SYSTEM_DB					= 0x0122,
    7.19 +	PEP_INIT_SQLITE3_WITHOUT_MUTEX                  = 0x0120,
    7.20 +	PEP_INIT_CANNOT_OPEN_DB                         = 0x0121,
    7.21 +	PEP_INIT_CANNOT_OPEN_SYSTEM_DB                  = 0x0122,
    7.22  	
    7.23 -	PEP_KEY_NOT_FOUND						        = 0x0201,
    7.24 -	PEP_KEY_HAS_AMBIG_NAME					        = 0x0202,
    7.25 -	PEP_GET_KEY_FAILED						        = 0x0203,
    7.26 +	PEP_KEY_NOT_FOUND                               = 0x0201,
    7.27 +	PEP_KEY_HAS_AMBIG_NAME                          = 0x0202,
    7.28 +	PEP_GET_KEY_FAILED                              = 0x0203,
    7.29  	
    7.30 -	PEP_CANNOT_FIND_IDENTITY						= 0x0301,
    7.31 -	PEP_CANNOT_SET_PERSON							= 0x0381,
    7.32 -	PEP_CANNOT_SET_PGP_KEYPAIR						= 0x0382,
    7.33 -	PEP_CANNOT_SET_IDENTITY							= 0x0383,
    7.34 +	PEP_CANNOT_FIND_IDENTITY                        = 0x0301,
    7.35 +	PEP_CANNOT_SET_PERSON                           = 0x0381,
    7.36 +	PEP_CANNOT_SET_PGP_KEYPAIR                      = 0x0382,
    7.37 +	PEP_CANNOT_SET_IDENTITY                         = 0x0383,
    7.38      PEP_CANNOT_SET_TRUST                            = 0x0384,
    7.39      PEP_KEY_BLACKLISTED                             = 0x0385,
    7.40  	
    7.41 -	PEP_UNENCRYPTED									= 0x0400,
    7.42 -	PEP_VERIFIED									= 0x0401,
    7.43 -	PEP_DECRYPTED									= 0x0402,
    7.44 -	PEP_DECRYPTED_AND_VERIFIED						= 0x0403,
    7.45 -	PEP_DECRYPT_WRONG_FORMAT						= 0x0404,
    7.46 -	PEP_DECRYPT_NO_KEY								= 0x0405,
    7.47 -	PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH			= 0x0406,
    7.48 +	PEP_UNENCRYPTED                                 = 0x0400,
    7.49 +	PEP_VERIFIED                                    = 0x0401,
    7.50 +	PEP_DECRYPTED                                   = 0x0402,
    7.51 +	PEP_DECRYPTED_AND_VERIFIED                      = 0x0403,
    7.52 +	PEP_DECRYPT_WRONG_FORMAT                        = 0x0404,
    7.53 +	PEP_DECRYPT_NO_KEY                              = 0x0405,
    7.54 +	PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH            = 0x0406,
    7.55      PEP_VERIFY_NO_KEY                               = 0x0407,
    7.56      PEP_VERIFIED_AND_TRUSTED                        = 0x0408,
    7.57 -	PEP_CANNOT_DECRYPT_UNKNOWN						= 0x04ff,
    7.58 +	PEP_CANNOT_DECRYPT_UNKNOWN                      = 0x04ff,
    7.59  
    7.60 -	PEP_TRUSTWORD_NOT_FOUND							= 0x0501,
    7.61 +	PEP_TRUSTWORD_NOT_FOUND                         = 0x0501,
    7.62  
    7.63      PEP_CANNOT_CREATE_KEY                           = 0x0601,
    7.64      PEP_CANNOT_SEND_KEY                             = 0x0602,
    7.65  
    7.66      PEP_PHRASE_NOT_FOUND                            = 0x0701,
    7.67  
    7.68 -	PEP_COMMIT_FAILED								= 0xff01,
    7.69 +	PEP_COMMIT_FAILED                               = 0xff01,
    7.70  
    7.71 +    PEP_NO_MANAGEMENT_THREAD                        = -6,
    7.72      PEP_CANNOT_CREATE_TEMP_FILE                     = -5,
    7.73      PEP_ILLEGAL_VALUE                               = -4,
    7.74      PEP_BUFFER_TOO_SMALL                            = -3,
    7.75 -	PEP_OUT_OF_MEMORY								= -2,
    7.76 -	PEP_UNKNOWN_ERROR								= -1
    7.77 +	PEP_OUT_OF_MEMORY                               = -2,
    7.78 +	PEP_UNKNOWN_ERROR                               = -1
    7.79  } PEP_STATUS;
    7.80  
    7.81 -
    7.82 +    
    7.83  // INIT_STATUS init() - initialize pEpEngine for a thread
    7.84  //
    7.85  //  parameters:
    7.86 @@ -443,10 +444,32 @@
    7.87  //		more
    7.88  
    7.89  DYNAMIC_API PEP_STATUS get_identity(
    7.90 -        PEP_SESSION session, const char *address,
    7.91 +        PEP_SESSION session,
    7.92 +        const char *address,
    7.93 +        const char *user_id,
    7.94          pEp_identity **identity
    7.95      );
    7.96 -
    7.97 +    
    7.98 +// get_best_user() - get best user_id candidate for a given address
    7.99 +//
   7.100 +//	parameters:
   7.101 +//		session (in)		session handle
   7.102 +//		address (in)		C string with communication address, UTF-8 encoded
   7.103 +//		user_id (out)		pointer to user_id string
   7.104 +//
   7.105 +//	caveat:
   7.106 +//	    the address string is being copied; the original string remains in the
   7.107 +//	    ownership of the caller
   7.108 +//		the resulting user_id string goes to the ownership of the
   7.109 +//		caller and has to be freed with free() when not in use any
   7.110 +//		more
   7.111 +    
   7.112 +DYNAMIC_API PEP_STATUS get_best_user(
   7.113 +        PEP_SESSION session,
   7.114 +        const char *address,
   7.115 +        char **user_id
   7.116 +    );
   7.117 +    
   7.118  
   7.119  // set_identity() - set identity information
   7.120  //
   7.121 @@ -472,15 +495,16 @@
   7.122      );
   7.123  
   7.124  
   7.125 -// mark_as_compromized() - mark key in trust db as compromized
   7.126 +// set_fpr_trust() - mark key in trust db as compromized
   7.127  //
   7.128  //	parameters:
   7.129  //		session (in)		session handle
   7.130  //		fpr (in)            fingerprint of key to mark
   7.131  
   7.132 -DYNAMIC_API PEP_STATUS mark_as_compromized(
   7.133 +DYNAMIC_API PEP_STATUS set_fpr_trust(
   7.134          PEP_SESSION session,
   7.135 -        const char *fpr
   7.136 +        const char *fpr,
   7.137 +        PEP_comm_type trust
   7.138      );
   7.139  
   7.140  
   7.141 @@ -584,7 +608,6 @@
   7.142  //	    the ownerships of keylist isgoing to the caller
   7.143  //	    the caller must use free_stringlist() to free it
   7.144  
   7.145 -
   7.146  DYNAMIC_API PEP_STATUS find_keys(
   7.147          PEP_SESSION session, const char *pattern, stringlist_t **keylist
   7.148      );
   7.149 @@ -645,6 +668,24 @@
   7.150      );
   7.151  
   7.152  
   7.153 +// get_pgp_keypair_created() - get the created flag for a key in the database
   7.154 +//
   7.155 +//  parameters:
   7.156 +//      session (in)            session handle
   7.157 +//      fpr (in)                fingerprint of key to check
   7.158 +//      created (out)           created flag as result (out)
   7.159 +//
   7.160 +//  a key with created flag non-null has either been generated by pEp, or
   7.161 +//  might have been imported, but then explicitely trusted as own key, as
   7.162 +//  if it would have been created
   7.163 +    
   7.164 +DYNAMIC_API PEP_STATUS get_pgp_keypair_created(
   7.165 +        PEP_SESSION session,
   7.166 +        const char *fpr,
   7.167 +        int *created
   7.168 +    );
   7.169 +    
   7.170 +    
   7.171  // get_key_rating() - get the rating a bare key has
   7.172  //
   7.173  //  parameters:
   7.174 @@ -661,6 +702,7 @@
   7.175          PEP_comm_type *comm_type
   7.176      );
   7.177  
   7.178 +    
   7.179  
   7.180  // renew_key() - renew an expired key
   7.181  //
   7.182 @@ -688,7 +730,7 @@
   7.183  //  caveat:
   7.184  //      reason text must not include empty lines
   7.185  //      this function is meant for internal use only; better use
   7.186 -//      key_compromized() of keymanagement API
   7.187 +//      key_mistrusted() of keymanagement API
   7.188  
   7.189  DYNAMIC_API PEP_STATUS revoke_key(
   7.190          PEP_SESSION session,
   7.191 @@ -711,6 +753,20 @@
   7.192      );
   7.193  
   7.194  
   7.195 +// key_revoked() - flags if a key is already revoked
   7.196 +//
   7.197 +//  parameters:
   7.198 +//      session (in)            session handle
   7.199 +//      fpr (in)                ID of key to check as UTF-8 string
   7.200 +//      revoked (out)           flag if key revoked
   7.201 +
   7.202 +DYNAMIC_API PEP_STATUS key_revoked(
   7.203 +        PEP_SESSION session,
   7.204 +        const char *fpr,
   7.205 +        bool *revoked
   7.206 +    );
   7.207 +    
   7.208 +    
   7.209  // get_crashdump_log() - get the last log messages out
   7.210  //
   7.211  //  parameters:
     8.1 --- a/src/pEp_internal.h	Wed Apr 06 17:00:54 2016 +0200
     8.2 +++ b/src/pEp_internal.h	Mon Apr 25 14:53:45 2016 +0200
     8.3 @@ -88,8 +88,10 @@
     8.4      sqlite3_stmt *log;
     8.5      sqlite3_stmt *trustword;
     8.6      sqlite3_stmt *get_identity;
     8.7 +    sqlite3_stmt *get_best_user;
     8.8      sqlite3_stmt *set_person;
     8.9      sqlite3_stmt *set_pgp_keypair;
    8.10 +    sqlite3_stmt *get_pgp_keypair_created;
    8.11      sqlite3_stmt *set_identity;
    8.12      sqlite3_stmt *set_trust;
    8.13      sqlite3_stmt *get_trust;
     9.1 --- a/src/pgp_netpgp.c	Wed Apr 06 17:00:54 2016 +0200
     9.2 +++ b/src/pgp_netpgp.c	Mon Apr 25 14:53:45 2016 +0200
     9.3 @@ -168,7 +168,7 @@
     9.4      PEP_STATUS status = PEP_STATUS_OK;
     9.5  
     9.6      assert(session);
     9.7 -    if(!session) return PEP_UNKNOWN_ERROR;
     9.8 +    if(!session) return PEP_ILLEGAL_VALUE;
     9.9  
    9.10      if (in_first) {
    9.11          if((status = init_netpgp()) != PEP_STATUS_OK)
    9.12 @@ -210,32 +210,6 @@
    9.13      return armoured;
    9.14  }
    9.15  
    9.16 -/* write key ID bytes read from hex string 
    9.17 - * tolerates no space, only hexes */
    9.18 -static unsigned str_to_id(uint8_t *keyid, const char *str)
    9.19 -{
    9.20 -    int i, n;
    9.21 -    for (i = 0; i < PGP_KEY_ID_SIZE ; i++) {
    9.22 -        uint8_t b = 0;
    9.23 -        for (n = 0; n < 2; n++) {
    9.24 -            char c = str[i * 2 + n];
    9.25 -            uint8_t q;
    9.26 -            if(c >= '0' &&  c <= '9'){
    9.27 -                q = (c - '0');
    9.28 -            }else if(c >= 'a' &&  c <= 'f'){
    9.29 -                q = (c - 'a' + 0xA);
    9.30 -            }else if(c >= 'A' &&  c <= 'F'){
    9.31 -                q = (c - 'A' + 0xA);
    9.32 -            }else{
    9.33 -                return 0;
    9.34 -            }
    9.35 -            b |= q << (4 * (1 - n));
    9.36 -        }
    9.37 -        keyid[i] = b;
    9.38 -    }
    9.39 -    return 1;
    9.40 -}
    9.41 -
    9.42  /* write key fingerprint hexdump as a string */
    9.43  static unsigned
    9.44  fpr_to_str (char **str, const uint8_t *fpr, size_t length)
    9.45 @@ -391,7 +365,7 @@
    9.46      assert(keylist);
    9.47  
    9.48      if(!session || !ctext || !csize || !ptext || !psize || !keylist) 
    9.49 -        return PEP_UNKNOWN_ERROR;
    9.50 +        return PEP_ILLEGAL_VALUE;
    9.51  
    9.52      if(pthread_mutex_lock(&netpgp_mutex)){
    9.53          return PEP_UNKNOWN_ERROR;
    9.54 @@ -491,7 +465,7 @@
    9.55      assert(keylist);
    9.56  
    9.57      if(!session || !text || !size || !signature || !sig_size || !keylist) 
    9.58 -        return PEP_UNKNOWN_ERROR;
    9.59 +        return PEP_ILLEGAL_VALUE;
    9.60  
    9.61      if(pthread_mutex_lock(&netpgp_mutex)){
    9.62          return PEP_UNKNOWN_ERROR;
    9.63 @@ -584,7 +558,7 @@
    9.64      assert(csize);
    9.65  
    9.66      if(!session || !ptext || !psize || !ctext || !csize || !keylist) 
    9.67 -        return PEP_UNKNOWN_ERROR;
    9.68 +        return PEP_ILLEGAL_VALUE;
    9.69  
    9.70      if(pthread_mutex_lock(&netpgp_mutex)){
    9.71          return PEP_UNKNOWN_ERROR;
    9.72 @@ -732,7 +706,7 @@
    9.73  
    9.74      if(!session || !identity || 
    9.75         !identity->address || identity->fpr || !identity->username)
    9.76 -        return PEP_UNKNOWN_ERROR;
    9.77 +        return PEP_ILLEGAL_VALUE;
    9.78  
    9.79      if(pthread_mutex_lock(&netpgp_mutex)){
    9.80          return PEP_UNKNOWN_ERROR;
    9.81 @@ -839,7 +813,7 @@
    9.82      assert(fprstr);
    9.83  
    9.84      if (!session || !fprstr)
    9.85 -        return PEP_UNKNOWN_ERROR;
    9.86 +        return PEP_ILLEGAL_VALUE;
    9.87  
    9.88      if(pthread_mutex_lock(&netpgp_mutex)){
    9.89          return PEP_UNKNOWN_ERROR;
    9.90 @@ -893,7 +867,7 @@
    9.91      assert(key_data);
    9.92  
    9.93      if(!session || !key_data) 
    9.94 -        return PEP_UNKNOWN_ERROR;
    9.95 +        return PEP_ILLEGAL_VALUE;
    9.96  
    9.97      if(pthread_mutex_lock(&netpgp_mutex)){
    9.98          return PEP_UNKNOWN_ERROR;
    9.99 @@ -941,7 +915,7 @@
   9.100  	pgp_setup_memory_write(&output, &mem, 128);
   9.101  
   9.102      if (mem == NULL || output == NULL) {
   9.103 -        return PEP_OUT_OF_MEMORY;
   9.104 +        return PEP_ILLEGAL_VALUE;
   9.105      }
   9.106  
   9.107      if (!pgp_write_xfer_key(output, key, 1)) {
   9.108 @@ -989,7 +963,7 @@
   9.109      assert(size);
   9.110  
   9.111      if (!session || !fprstr || !key_data || !size)
   9.112 -        return PEP_UNKNOWN_ERROR;
   9.113 +        return PEP_ILLEGAL_VALUE;
   9.114  
   9.115      if(pthread_mutex_lock(&netpgp_mutex)){
   9.116          return PEP_UNKNOWN_ERROR;
   9.117 @@ -1070,7 +1044,7 @@
   9.118      assert(pattern);
   9.119  
   9.120      if (!session || !pattern )
   9.121 -        return PEP_UNKNOWN_ERROR;
   9.122 +        return PEP_ILLEGAL_VALUE;
   9.123  
   9.124      if(pthread_mutex_lock(&session->ctx.curl_mutex)){
   9.125          return PEP_UNKNOWN_ERROR;
   9.126 @@ -1217,9 +1191,12 @@
   9.127      assert(keylist);
   9.128  
   9.129      if (!session || !pattern || !keylist )
   9.130 -        return PEP_UNKNOWN_ERROR;
   9.131 +    {
   9.132 +        return PEP_ILLEGAL_VALUE;
   9.133 +    }
   9.134  
   9.135 -    if(pthread_mutex_lock(&netpgp_mutex)){
   9.136 +    if (pthread_mutex_lock(&netpgp_mutex))
   9.137 +    {
   9.138          return PEP_UNKNOWN_ERROR;
   9.139      }
   9.140  
   9.141 @@ -1314,7 +1291,7 @@
   9.142      assert(pattern);
   9.143  
   9.144      if (!session || !pattern )
   9.145 -        return PEP_UNKNOWN_ERROR;
   9.146 +        return PEP_ILLEGAL_VALUE;
   9.147  
   9.148      encoded_keys = new_stringlist(NULL);
   9.149      assert(encoded_keys);
   9.150 @@ -1399,7 +1376,7 @@
   9.151      assert(comm_type);
   9.152  
   9.153      if (!session || !fprstr || !comm_type )
   9.154 -        return PEP_UNKNOWN_ERROR;
   9.155 +        return PEP_ILLEGAL_VALUE;
   9.156  
   9.157      *comm_type = PEP_ct_unknown;
   9.158  
   9.159 @@ -1472,7 +1449,7 @@
   9.160      assert(fprstr);
   9.161  
   9.162      if (!session || !fprstr )
   9.163 -        return PEP_UNKNOWN_ERROR;
   9.164 +        return PEP_ILLEGAL_VALUE;
   9.165  
   9.166      if(ts)
   9.167      {
   9.168 @@ -1619,7 +1596,7 @@
   9.169  
   9.170  PEP_STATUS pgp_key_expired(
   9.171          PEP_SESSION session,
   9.172 -        const char *keyidstr,
   9.173 +        const char *fprstr,
   9.174          bool *expired
   9.175      )
   9.176  {
   9.177 @@ -1627,12 +1604,16 @@
   9.178      PEP_comm_type comm_type;
   9.179  
   9.180      assert(session);
   9.181 -    assert(keyidstr);
   9.182 +    assert(fprstr);
   9.183      assert(expired);
   9.184  
   9.185 +    if (!session || !fprstr || !expired)
   9.186 +        return PEP_UNKNOWN_ERROR;
   9.187 +
   9.188 +
   9.189      *expired = false;
   9.190  
   9.191 -    status = pgp_get_key_rating(session, keyidstr, &comm_type);
   9.192 +    status = pgp_get_key_rating(session, fprstr, &comm_type);
   9.193  
   9.194      if (status != PEP_STATUS_OK)
   9.195          return status;
   9.196 @@ -1644,3 +1625,29 @@
   9.197      return PEP_STATUS_OK;
   9.198  }
   9.199  
   9.200 +PEP_STATUS pgp_key_revoked(
   9.201 +        PEP_SESSION session,
   9.202 +        const char *fprstr,
   9.203 +        bool *revoked
   9.204 +    )
   9.205 +{
   9.206 +    PEP_STATUS status = PEP_STATUS_OK;
   9.207 +    PEP_comm_type comm_type;
   9.208 +    
   9.209 +    assert(session);
   9.210 +    assert(fprstr);
   9.211 +    assert(revoked);
   9.212 +    
   9.213 +    *revoked = false;
   9.214 +    
   9.215 +    status = pgp_get_key_rating(session, fprstr, &comm_type);
   9.216 +    
   9.217 +    if (status != PEP_STATUS_OK)
   9.218 +        return status;
   9.219 +    
   9.220 +    if (comm_type == PEP_ct_key_revoked){
   9.221 +        *revoked = true;
   9.222 +    }
   9.223 +    
   9.224 +    return PEP_STATUS_OK;
   9.225 +}
    10.1 --- a/src/pgp_netpgp.h	Wed Apr 06 17:00:54 2016 +0200
    10.2 +++ b/src/pgp_netpgp.h	Mon Apr 25 14:53:45 2016 +0200
    10.3 @@ -64,3 +64,8 @@
    10.4          bool *expired
    10.5      );
    10.6  
    10.7 +PEP_STATUS pgp_key_revoked(
    10.8 +        PEP_SESSION session,
    10.9 +        const char *fpr,
   10.10 +        bool *revoked
   10.11 +    );