src/keymanagement.c
author Edouard Tisserant <edouard@pep-project.org>
Thu, 21 Sep 2017 17:03:26 +0200
branchtest_diphoton
changeset 2089 174f5577c0aa
parent 1860 1975a3b9bc37
parent 1945 9503c962f746
child 2166 4c7f95dacc6a
child 2262 0437fb3b1875
permissions -rw-r--r--
Merged latest default in test_diphoton. Only one conflict about NOLOG. test_diphoton branches enforces logging, even if not debug build
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "platform.h"
     5 
     6 #include <string.h>
     7 #include <stdio.h>
     8 #include <stdlib.h>
     9 #include <assert.h>
    10 #include <ctype.h>
    11 
    12 #include "pEp_internal.h"
    13 #include "keymanagement.h"
    14 
    15 #include "sync_fsm.h"
    16 #include "blacklist.h"
    17 
    18 #ifndef EMPTYSTR
    19 #define EMPTYSTR(STR) ((STR) == NULL || (STR)[0] == '\0')
    20 #endif
    21 
    22 #define KEY_EXPIRE_DELTA (60 * 60 * 24 * 365)
    23 
    24 PEP_STATUS elect_pubkey(
    25         PEP_SESSION session, pEp_identity * identity
    26     )
    27 {
    28     PEP_STATUS status;
    29     stringlist_t *keylist = NULL;
    30     char *_fpr = "";
    31     identity->comm_type = PEP_ct_unknown;
    32 
    33     status = find_keys(session, identity->address, &keylist);
    34     assert(status != PEP_OUT_OF_MEMORY);
    35     if (status == PEP_OUT_OF_MEMORY)
    36         return PEP_OUT_OF_MEMORY;
    37 
    38     stringlist_t *_keylist;
    39     for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
    40         PEP_comm_type _comm_type_key;
    41 
    42         status = get_key_rating(session, _keylist->value, &_comm_type_key);
    43         assert(status != PEP_OUT_OF_MEMORY);
    44         if (status == PEP_OUT_OF_MEMORY) {
    45             free_stringlist(keylist);
    46             return PEP_OUT_OF_MEMORY;
    47         }
    48 
    49         if (_comm_type_key != PEP_ct_compromized &&
    50             _comm_type_key != PEP_ct_unknown)
    51         {
    52             if (identity->comm_type == PEP_ct_unknown ||
    53                 _comm_type_key > identity->comm_type)
    54             {
    55                 bool blacklisted;
    56                 status = blacklist_is_listed(session, _keylist->value, &blacklisted);
    57                 if (status == PEP_STATUS_OK && !blacklisted) {
    58                     identity->comm_type = _comm_type_key;
    59                     _fpr = _keylist->value;
    60                 }
    61             }
    62         }
    63     }
    64 
    65     
    66 //    if (_fpr) {
    67     free(identity->fpr);
    68 
    69     identity->fpr = strdup(_fpr);
    70     if (identity->fpr == NULL) {
    71         free_stringlist(keylist);
    72         return PEP_OUT_OF_MEMORY;
    73     }
    74 //    }
    75     free_stringlist(keylist);
    76     return PEP_STATUS_OK;
    77 }
    78 
    79 PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags);
    80 
    81 DYNAMIC_API PEP_STATUS update_identity(
    82         PEP_SESSION session, pEp_identity * identity
    83     )
    84 {
    85     pEp_identity *stored_identity = NULL;
    86     pEp_identity *temp_id = NULL;
    87     PEP_STATUS status;
    88 
    89     assert(session);
    90     assert(identity);
    91     assert(!EMPTYSTR(identity->address));
    92 
    93     if (!(session && identity && !EMPTYSTR(identity->address)))
    94         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
    95 
    96     if (_identity_me(identity)) {
    97         return _myself(session, identity, false, true);
    98     }
    99 
   100     int _no_user_id = EMPTYSTR(identity->user_id);
   101     int _did_elect_new_key = 0;
   102 
   103     if (_no_user_id)
   104     {
   105         status = get_identity(session, identity->address, PEP_OWN_USERID,
   106                 &stored_identity);
   107         if (status == PEP_STATUS_OK) {
   108             free_identity(stored_identity);
   109             return _myself(session, identity, false, true);
   110         }
   111 
   112         free(identity->user_id);
   113 
   114         identity->user_id = calloc(1, strlen(identity->address) + 6);
   115         if (!identity->user_id)
   116         {
   117             return PEP_OUT_OF_MEMORY;
   118         }
   119         snprintf(identity->user_id, strlen(identity->address) + 6,
   120                  "TOFU_%s", identity->address);
   121     }
   122  
   123     status = get_identity(session,
   124                           identity->address,
   125                           identity->user_id,
   126                           &stored_identity);
   127     
   128     assert(status != PEP_OUT_OF_MEMORY);
   129     if (status == PEP_OUT_OF_MEMORY)
   130         goto exit_free;
   131 
   132     temp_id = identity_dup(identity);
   133     
   134     /* We don't take given fpr. 
   135        In case there's no acceptable stored fpr, it will be elected. */
   136     free(temp_id->fpr);
   137     temp_id->fpr = NULL;
   138     temp_id->comm_type = PEP_ct_unknown;
   139             
   140     if (stored_identity) {
   141         
   142         bool dont_use_stored_fpr = true;
   143 
   144         /* if we have a stored_identity fpr */
   145         if (!EMPTYSTR(stored_identity->fpr)) {
   146             bool revoked = false;
   147             status = key_revoked(session, stored_identity->fpr, &revoked);
   148             
   149             if (status != PEP_STATUS_OK || revoked)
   150                 dont_use_stored_fpr = true;
   151                 
   152             if (revoked) {
   153                 // Do stuff
   154                 status = update_trust_for_fpr(session, stored_identity->fpr, PEP_ct_key_revoked);
   155                 // What to do on failure? FIXME
   156                 status = replace_identities_fpr(session, stored_identity->fpr, "");
   157             }
   158             else {    
   159                 status = blacklist_is_listed(session, stored_identity->fpr, &dont_use_stored_fpr);
   160                 if (status != PEP_STATUS_OK)
   161                     dont_use_stored_fpr = true; 
   162             }
   163         }
   164             
   165 
   166         if (!dont_use_stored_fpr) {
   167             /* Check stored comm_type */
   168             PEP_comm_type _comm_type_key;
   169             status = get_key_rating(session, stored_identity->fpr, &_comm_type_key);
   170             assert(status != PEP_OUT_OF_MEMORY);
   171             if (status == PEP_OUT_OF_MEMORY) {
   172                 goto exit_free;
   173             }
   174             if (status == PEP_KEY_NOT_FOUND){
   175                 /* stored key was deleted from keyring. any other candidate ?*/
   176                 status = elect_pubkey(session, temp_id);
   177                 if (status != PEP_STATUS_OK) {
   178                     goto exit_free;
   179                 } else {
   180                     _did_elect_new_key = 1;
   181                 }
   182             } else {
   183                 temp_id->fpr = strdup(stored_identity->fpr);
   184                 assert(temp_id->fpr);
   185                 if (temp_id->fpr == NULL) {
   186                     status = PEP_OUT_OF_MEMORY;
   187                     goto exit_free;
   188                 }
   189 
   190                 if (_comm_type_key < PEP_ct_unconfirmed_encryption) {
   191                     /* if key not good anymore, 
   192                        downgrade eventually trusted comm_type */
   193                     temp_id->comm_type = _comm_type_key;
   194                 } else {
   195                     /* otherwise take stored comm_type as-is except if 
   196                        is unknown or is expired (but key not expired anymore) */
   197                     temp_id->comm_type = stored_identity->comm_type;
   198                     if (temp_id->comm_type == PEP_ct_unknown ||
   199                         temp_id->comm_type == PEP_ct_key_expired) {
   200                         temp_id->comm_type = _comm_type_key;
   201                     }
   202                 }
   203             }
   204         }
   205         else {
   206             status = elect_pubkey(session, temp_id);
   207             if (status != PEP_STATUS_OK){
   208                 goto exit_free;
   209             } else {
   210                 _did_elect_new_key = 1;
   211             }
   212         }
   213         
   214         /* ok, from here on out, use temp_id */
   215         
   216         
   217         /* At this point, we either have a non-blacklisted fpr we can work */
   218         /* with, or we've got nada.                                        */
   219 
   220         if (EMPTYSTR(temp_id->fpr)) {
   221             /* nada : set comm_type accordingly */
   222             temp_id->comm_type = PEP_ct_key_not_found;
   223         }
   224         
   225         if (EMPTYSTR(temp_id->username)) {
   226             free(temp_id->username);
   227             temp_id->username = strdup(stored_identity->username);
   228             assert(temp_id->username);
   229             if (temp_id->username == NULL){
   230                 status = PEP_OUT_OF_MEMORY;
   231                 goto exit_free;
   232             }
   233         }
   234 
   235         if (temp_id->lang[0] == 0) {
   236             temp_id->lang[0] = stored_identity->lang[0];
   237             temp_id->lang[1] = stored_identity->lang[1];
   238             temp_id->lang[2] = 0;
   239         }
   240 
   241         temp_id->flags = stored_identity->flags;
   242     }
   243     else /* stored_identity == NULL */ {
   244         temp_id->flags = 0;
   245 
   246         /* We elect a pubkey */
   247         status = elect_pubkey(session, temp_id);
   248         if (status != PEP_STATUS_OK)
   249             goto exit_free;
   250         
   251         /* Work with the elected key */
   252         if (!EMPTYSTR(temp_id->fpr)) {
   253             
   254             PEP_comm_type _comm_type_key = temp_id->comm_type;
   255             
   256             _did_elect_new_key = 1;
   257 
   258             // We don't want to lose a previous trust entry!!!
   259             status = get_trust(session, temp_id);
   260 
   261             bool has_trust_status = (status == PEP_STATUS_OK);
   262 
   263             if (!has_trust_status)
   264                 temp_id->comm_type = _comm_type_key;
   265         }
   266     }
   267 
   268     if (temp_id->fpr == NULL) {
   269         temp_id->fpr = strdup("");
   270         if (temp_id->fpr == NULL) {
   271             status = PEP_OUT_OF_MEMORY;
   272             goto exit_free;
   273         }
   274     }
   275     
   276     
   277     status = PEP_STATUS_OK;
   278 
   279     if (temp_id->comm_type != PEP_ct_unknown && !EMPTYSTR(temp_id->user_id)) {
   280 
   281         if (EMPTYSTR(temp_id->username)) { // mitigate
   282             free(temp_id->username);
   283             temp_id->username = strdup("anonymous");
   284             assert(temp_id->username);
   285             if (temp_id->username == NULL){
   286                 status = PEP_OUT_OF_MEMORY;
   287                 goto exit_free;
   288             }
   289         }
   290 
   291         // Identity doesn't get stored if call was just about checking existing
   292         // user by address (i.e. no user id given but already stored)
   293         if (!(_no_user_id && stored_identity) || _did_elect_new_key)
   294         {
   295             status = set_identity(session, temp_id);
   296             assert(status == PEP_STATUS_OK);
   297             if (status != PEP_STATUS_OK) {
   298                 goto exit_free;
   299             }
   300         }
   301     }
   302 
   303     if (temp_id->comm_type != PEP_ct_compromized &&
   304             temp_id->comm_type < PEP_ct_strong_but_unconfirmed)
   305         if (session->examine_identity)
   306             session->examine_identity(temp_id, session->examine_management);
   307     
   308     /* ok, we got to the end. So we can assign the output identity */
   309     free(identity->address);
   310     identity->address = strdup(temp_id->address);
   311     free(identity->fpr);
   312     identity->fpr = strdup(temp_id->fpr);
   313     free(identity->user_id);
   314     identity->user_id = strdup(temp_id->user_id);
   315     free(identity->username);
   316     identity->username = strdup(temp_id->username ? temp_id->username : "anonymous");
   317     identity->comm_type = temp_id->comm_type;
   318     identity->lang[0] = temp_id->lang[0];
   319     identity->lang[1] = temp_id->lang[1];
   320     identity->lang[2] = 0;
   321     identity->flags = temp_id->flags;
   322 
   323 exit_free :
   324     free_identity(stored_identity);
   325     free_identity(temp_id);
   326     
   327     return ADD_TO_LOG(status);
   328 }
   329 
   330 PEP_STATUS elect_ownkey(
   331         PEP_SESSION session, pEp_identity * identity
   332     )
   333 {
   334     PEP_STATUS status;
   335     stringlist_t *keylist = NULL;
   336 
   337     free(identity->fpr);
   338     identity->fpr = NULL;
   339 
   340     status = find_private_keys(session, identity->address, &keylist);
   341     assert(status != PEP_OUT_OF_MEMORY);
   342     if (status == PEP_OUT_OF_MEMORY)
   343         return PEP_OUT_OF_MEMORY;
   344     
   345     if (keylist != NULL && keylist->value != NULL)
   346     {
   347         char *_fpr = NULL;
   348         identity->comm_type = PEP_ct_unknown;
   349 
   350         stringlist_t *_keylist;
   351         for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
   352             bool is_own = false;
   353             
   354             status = own_key_is_listed(session, _keylist->value, &is_own);
   355             assert(status == PEP_STATUS_OK);
   356             if (status != PEP_STATUS_OK) {
   357                 free_stringlist(keylist);
   358                 return status;
   359             }
   360             
   361             if (is_own)
   362             {
   363                 PEP_comm_type _comm_type_key;
   364                 
   365                 status = get_key_rating(session, _keylist->value, &_comm_type_key);
   366                 assert(status != PEP_OUT_OF_MEMORY);
   367                 if (status == PEP_OUT_OF_MEMORY) {
   368                     free_stringlist(keylist);
   369                     return PEP_OUT_OF_MEMORY;
   370                 }
   371                 
   372                 if (_comm_type_key != PEP_ct_compromized &&
   373                     _comm_type_key != PEP_ct_unknown)
   374                 {
   375                     if (identity->comm_type == PEP_ct_unknown ||
   376                         _comm_type_key > identity->comm_type)
   377                     {
   378                         identity->comm_type = _comm_type_key;
   379                         _fpr = _keylist->value;
   380                     }
   381                 }
   382             }
   383         }
   384         
   385         if (_fpr)
   386         {
   387             identity->fpr = strdup(_fpr);
   388             assert(identity->fpr);
   389             if (identity->fpr == NULL)
   390             {
   391                 free_stringlist(keylist);
   392                 return PEP_OUT_OF_MEMORY;
   393             }
   394         }
   395         free_stringlist(keylist);
   396     }
   397     return PEP_STATUS_OK;
   398 }
   399 
   400 PEP_STATUS _has_usable_priv_key(PEP_SESSION session, char* fpr,
   401                                 bool* is_usable) {
   402     
   403     bool dont_use_fpr = true;
   404     
   405     PEP_STATUS status = blacklist_is_listed(session, fpr, &dont_use_fpr);
   406     if (status == PEP_STATUS_OK && !dont_use_fpr) {
   407         // Make sure there is a *private* key associated with this fpr
   408         bool has_private = false;
   409         status = contains_priv_key(session, fpr, &has_private);
   410 
   411         if (status == PEP_STATUS_OK)
   412             dont_use_fpr = !has_private;
   413     }
   414     
   415     *is_usable = !dont_use_fpr;
   416     
   417     return ADD_TO_LOG(status);
   418 }
   419 
   420 PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags)
   421 {
   422     pEp_identity *stored_identity = NULL;
   423     PEP_STATUS status;
   424 
   425     assert(session);
   426     assert(identity);
   427     assert(!EMPTYSTR(identity->address));
   428 
   429     assert(EMPTYSTR(identity->user_id) ||
   430            strcmp(identity->user_id, PEP_OWN_USERID) == 0);
   431 
   432     if (!(session && identity && !EMPTYSTR(identity->address) &&
   433             (EMPTYSTR(identity->user_id) ||
   434             strcmp(identity->user_id, PEP_OWN_USERID) == 0)))
   435         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
   436 
   437     identity->comm_type = PEP_ct_pEp;
   438     if(ignore_flags)
   439         identity->flags = 0;
   440     else {
   441         // test_diphoton : dirty hack to prevent more than one sync enabled account
   442         identity_list *own_identities = NULL;
   443         if (_own_identities_retrieve(session, &own_identities, PEP_idf_not_for_sync) == PEP_STATUS_OK)
   444             // if at least one _other_ own address is sync enabled, set exclusion flag
   445             for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
   446                 pEp_identity *me = _i->ident;
   447                 if(me->address && strcmp(me->address, identity->address) != 0)
   448                 identity->flags |= PEP_idf_not_for_sync;
   449                 break;
   450             }
   451         free_identity_list(own_identities);
   452     }
   453     
   454     if (EMPTYSTR(identity->user_id))
   455     {
   456         free(identity->user_id);
   457         identity->user_id = strdup(PEP_OWN_USERID);
   458         assert(identity->user_id);
   459         if (identity->user_id == NULL)
   460             return PEP_OUT_OF_MEMORY;
   461     }
   462 
   463     if (EMPTYSTR(identity->username))
   464     {
   465         free(identity->username);
   466         identity->username = strdup("anonymous");
   467         assert(identity->username);
   468         if (identity->username == NULL)
   469             return PEP_OUT_OF_MEMORY;
   470     }
   471 
   472     DEBUG_LOG("myself", "debug", identity->address);
   473  
   474     status = get_identity(session,
   475                           identity->address,
   476                           identity->user_id,
   477                           &stored_identity);
   478     
   479     assert(status != PEP_OUT_OF_MEMORY);
   480     if (status == PEP_OUT_OF_MEMORY)
   481         return PEP_OUT_OF_MEMORY;
   482 
   483     bool dont_use_stored_fpr = true;
   484     bool dont_use_input_fpr = true;
   485         
   486     if (stored_identity)
   487     {
   488         if (EMPTYSTR(identity->fpr)) {
   489             
   490             bool has_private = false;
   491             
   492             status = _has_usable_priv_key(session, stored_identity->fpr, &has_private); 
   493             
   494             // N.B. has_private is never true if the returned status is not PEP_STATUS_OK
   495             if (has_private) {
   496                 identity->fpr = strdup(stored_identity->fpr);
   497                 assert(identity->fpr);
   498                 if (identity->fpr == NULL)
   499                 {
   500                     return PEP_OUT_OF_MEMORY;
   501                 }
   502                 dont_use_stored_fpr = false;
   503             }
   504         }
   505         
   506         identity->flags = (identity->flags & 255) | stored_identity->flags;
   507         free_identity(stored_identity);
   508     }
   509     
   510     if (dont_use_stored_fpr && !EMPTYSTR(identity->fpr))
   511     {
   512         // App must have a good reason to give fpr, such as explicit
   513         // import of private key, or similar.
   514 
   515         // Take given fpr as-is.
   516 
   517         // BUT:
   518         // First check to see if it's blacklisted or private part is missing?
   519         bool has_private = false;
   520         
   521         status = _has_usable_priv_key(session, identity->fpr, &has_private); 
   522         
   523         // N.B. has_private is never true if the returned status is not PEP_STATUS_OK
   524         if (has_private) {
   525             dont_use_input_fpr = false;
   526         }
   527     }
   528     
   529     // Ok, we failed to get keys either way, so let's elect one.
   530     if (dont_use_input_fpr && dont_use_stored_fpr)
   531     {
   532         status = elect_ownkey(session, identity);
   533         assert(status == PEP_STATUS_OK);
   534         if (status != PEP_STATUS_OK) {
   535             return ADD_TO_LOG(status);
   536         }
   537 
   538         bool has_private = false;
   539         if (identity->fpr) {
   540             // ok, we elected something.
   541             // elect_ownkey only returns private keys, so we don't check again.
   542             // Check to see if it's blacklisted
   543             bool listed;
   544             status = blacklist_is_listed(session, identity->fpr, &listed); 
   545 
   546             if (status == PEP_STATUS_OK)
   547                 has_private = !listed;
   548         }
   549         
   550         if (has_private) {
   551             dont_use_input_fpr = false;
   552         }
   553         else { // OK, we've tried everything. Time to generate new keys.
   554             free(identity->fpr); // It can stay in this state (unallocated) because we'll generate a new key 
   555             identity->fpr = NULL;
   556         }
   557     }
   558 
   559     bool revoked = false;
   560     char *r_fpr = NULL;
   561     if (!EMPTYSTR(identity->fpr))
   562     {
   563         status = key_revoked(session, identity->fpr, &revoked);
   564 
   565         if (status != PEP_STATUS_OK) 
   566         {
   567             return ADD_TO_LOG(status);
   568         }
   569     }
   570    
   571     bool new_key_generated = false;
   572 
   573     if (EMPTYSTR(identity->fpr) || revoked)
   574     {
   575         if(!do_keygen){
   576             return ADD_TO_LOG(PEP_GET_KEY_FAILED);
   577         }
   578 
   579         if(revoked)
   580         {
   581             r_fpr = identity->fpr;
   582             identity->fpr = NULL;
   583         }
   584         
   585         DEBUG_LOG("generating key pair", "debug", identity->address);
   586         status = generate_keypair(session, identity);
   587         assert(status != PEP_OUT_OF_MEMORY);
   588         if (status != PEP_STATUS_OK) {
   589             char buf[11];
   590             snprintf(buf, 11, "%d", status);
   591             DEBUG_LOG("generating key pair failed", "debug", buf);
   592             if(revoked && r_fpr)
   593                 free(r_fpr);
   594             return ADD_TO_LOG(status);
   595         }
   596 
   597         new_key_generated = true;
   598         
   599         if(revoked)
   600         {
   601             status = set_revoked(session, r_fpr,
   602                                  identity->fpr, time(NULL));
   603             free(r_fpr);
   604             if (status != PEP_STATUS_OK) {
   605                 return ADD_TO_LOG(status);
   606             }
   607         }
   608     }
   609     else
   610     {
   611         bool expired;
   612         status = key_expired(session, identity->fpr, 
   613                              time(NULL) + (7*24*3600), // In a week
   614                              &expired);
   615 
   616         assert(status == PEP_STATUS_OK);
   617         if (status != PEP_STATUS_OK) {
   618             return ADD_TO_LOG(status);
   619         }
   620 
   621         if (status == PEP_STATUS_OK && expired) {
   622             timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
   623             renew_key(session, identity->fpr, ts);
   624             free_timestamp(ts);
   625         }
   626     }
   627 
   628     if (!identity->username)
   629         identity->username = strdup("");
   630     
   631     status = set_identity(session, identity);
   632     assert(status == PEP_STATUS_OK);
   633     if (status != PEP_STATUS_OK) {
   634         return status;
   635     }
   636 
   637     if(new_key_generated)
   638     {
   639         // if a state machine for keysync is in place, inject notify
   640         status = inject_DeviceState_event(session, KeyGen, NULL, NULL);
   641         if (status == PEP_OUT_OF_MEMORY){
   642             return PEP_OUT_OF_MEMORY;
   643         }
   644     }
   645 
   646     return ADD_TO_LOG(PEP_STATUS_OK);
   647 }
   648 
   649 DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
   650 {
   651     return ADD_TO_LOG(_myself(session, identity, true, false));
   652 }
   653 
   654 DYNAMIC_API PEP_STATUS register_examine_function(
   655         PEP_SESSION session, 
   656         examine_identity_t examine_identity,
   657         void *management
   658     )
   659 {
   660     assert(session);
   661     if (!session)
   662         return PEP_ILLEGAL_VALUE;
   663 
   664     session->examine_management = management;
   665     session->examine_identity = examine_identity;
   666 
   667     return PEP_STATUS_OK;
   668 }
   669 
   670 DYNAMIC_API PEP_STATUS do_keymanagement(
   671         retrieve_next_identity_t retrieve_next_identity,
   672         void *management
   673     )
   674 {
   675     PEP_SESSION session;
   676     pEp_identity *identity;
   677     PEP_STATUS status;
   678 
   679     assert(retrieve_next_identity);
   680     assert(management);
   681 
   682     if (!retrieve_next_identity || !management)
   683         return PEP_ILLEGAL_VALUE;
   684 
   685     status = init(&session);
   686     assert(status == PEP_STATUS_OK);
   687     if (status != PEP_STATUS_OK)
   688         return status;
   689 
   690     log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
   691 
   692     while ((identity = retrieve_next_identity(management))) 
   693     {
   694         assert(identity->address);
   695         if(identity->address)
   696         {
   697             DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
   698 
   699             if (_identity_me(identity)) {
   700                 status = myself(session, identity);
   701             } else {
   702                 status = recv_key(session, identity->address);
   703             }
   704 
   705             assert(status != PEP_OUT_OF_MEMORY);
   706             if(status == PEP_OUT_OF_MEMORY)
   707                 return PEP_OUT_OF_MEMORY;
   708         }
   709         free_identity(identity);
   710     }
   711 
   712     log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
   713 
   714     release(session);
   715     return PEP_STATUS_OK;
   716 }
   717 
   718 DYNAMIC_API PEP_STATUS key_mistrusted(
   719         PEP_SESSION session,
   720         pEp_identity *ident
   721     )
   722 {
   723     PEP_STATUS status = PEP_STATUS_OK;
   724 
   725     assert(session);
   726     assert(ident);
   727     assert(!EMPTYSTR(ident->fpr));
   728 
   729     if (!(session && ident && ident->fpr))
   730         return PEP_ILLEGAL_VALUE;
   731 
   732     if (_identity_me(ident))
   733     {
   734         revoke_key(session, ident->fpr, NULL);
   735         myself(session, ident);
   736     }
   737     else
   738     {
   739         status = mark_as_compromized(session, ident->fpr);
   740     }
   741 
   742     return status;
   743 }
   744 
   745 DYNAMIC_API PEP_STATUS key_reset_trust(
   746         PEP_SESSION session,
   747         pEp_identity *ident
   748     )
   749 {
   750     PEP_STATUS status = PEP_STATUS_OK;
   751 
   752     assert(session);
   753     assert(ident);
   754     assert(!_identity_me(ident));
   755     assert(!EMPTYSTR(ident->fpr));
   756     assert(!EMPTYSTR(ident->address));
   757     assert(!EMPTYSTR(ident->user_id));
   758 
   759     if (!(session && ident && !_identity_me(ident) && ident->fpr && ident->address &&
   760             ident->user_id))
   761         return PEP_ILLEGAL_VALUE;
   762 
   763     status = update_identity(session, ident);
   764     if (status != PEP_STATUS_OK)
   765         return status;
   766 
   767     if (ident->comm_type == PEP_ct_mistrusted)
   768         ident->comm_type = PEP_ct_unknown;
   769     else
   770         ident->comm_type &= ~PEP_ct_confirmed;
   771 
   772     status = set_identity(session, ident);
   773     if (status != PEP_STATUS_OK)
   774         return status;
   775 
   776     if (ident->comm_type == PEP_ct_unknown)
   777         status = update_identity(session, ident);
   778     return status;
   779 }
   780 
   781 DYNAMIC_API PEP_STATUS trust_personal_key(
   782         PEP_SESSION session,
   783         pEp_identity *ident
   784     )
   785 {
   786     PEP_STATUS status = PEP_STATUS_OK;
   787 
   788     assert(session);
   789     assert(ident);
   790     assert(!EMPTYSTR(ident->address));
   791     assert(!EMPTYSTR(ident->user_id));
   792     assert(!EMPTYSTR(ident->fpr));
   793 
   794     if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
   795             EMPTYSTR(ident->fpr))
   796         return PEP_ILLEGAL_VALUE;
   797 
   798     status = update_identity(session, ident);
   799     if (status != PEP_STATUS_OK)
   800         return status;
   801 
   802     if (ident->comm_type > PEP_ct_strong_but_unconfirmed) {
   803         ident->comm_type |= PEP_ct_confirmed;
   804         status = set_identity(session, ident);
   805     }
   806     else {
   807         // MISSING: S/MIME has to be handled depending on trusted CAs
   808         status = PEP_CANNOT_SET_TRUST;
   809     }
   810 
   811     return status;
   812 }
   813 
   814 DYNAMIC_API PEP_STATUS own_key_is_listed(
   815         PEP_SESSION session,
   816         const char *fpr,
   817         bool *listed
   818     )
   819 {
   820     PEP_STATUS status = PEP_STATUS_OK;
   821     int count;
   822     
   823     assert(session && fpr && fpr[0] && listed);
   824     
   825     if (!(session && fpr && fpr[0] && listed))
   826         return PEP_ILLEGAL_VALUE;
   827     
   828     *listed = false;
   829     
   830     sqlite3_reset(session->own_key_is_listed);
   831     sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1, SQLITE_STATIC);
   832     
   833     int result;
   834     
   835     result = sqlite3_step(session->own_key_is_listed);
   836     switch (result) {
   837         case SQLITE_ROW:
   838             count = sqlite3_column_int(session->own_key_is_listed, 0);
   839             *listed = count > 0;
   840             status = PEP_STATUS_OK;
   841             break;
   842             
   843         default:
   844             status = PEP_UNKNOWN_ERROR;
   845     }
   846     
   847     sqlite3_reset(session->own_key_is_listed);
   848     return status;
   849 }
   850 
   851 PEP_STATUS _own_identities_retrieve(
   852         PEP_SESSION session,
   853         identity_list **own_identities,
   854         identity_flags_t excluded_flags
   855       )
   856 {
   857     PEP_STATUS status = PEP_STATUS_OK;
   858     
   859     assert(session && own_identities);
   860     if (!(session && own_identities))
   861         return PEP_ILLEGAL_VALUE;
   862     
   863     *own_identities = NULL;
   864     identity_list *_own_identities = new_identity_list(NULL);
   865     if (_own_identities == NULL)
   866         goto enomem;
   867     
   868     sqlite3_reset(session->own_identities_retrieve);
   869     
   870     int result;
   871     // address, fpr, username, user_id, comm_type, lang, flags
   872     const char *address = NULL;
   873     const char *fpr = NULL;
   874     const char *username = NULL;
   875     const char *user_id = NULL;
   876     PEP_comm_type comm_type = PEP_ct_unknown;
   877     const char *lang = NULL;
   878     unsigned int flags = 0;
   879     
   880     identity_list *_bl = _own_identities;
   881     do {
   882         sqlite3_bind_int(session->own_identities_retrieve, 1, excluded_flags);
   883         result = sqlite3_step(session->own_identities_retrieve);
   884         switch (result) {
   885             case SQLITE_ROW:
   886                 address = (const char *)
   887                     sqlite3_column_text(session->own_identities_retrieve, 0);
   888                 fpr = (const char *)
   889                     sqlite3_column_text(session->own_identities_retrieve, 1);
   890                 user_id = PEP_OWN_USERID;
   891                 username = (const char *)
   892                     sqlite3_column_text(session->own_identities_retrieve, 2);
   893                 comm_type = PEP_ct_pEp;
   894                 lang = (const char *)
   895                     sqlite3_column_text(session->own_identities_retrieve, 3);
   896                 flags = (unsigned int)
   897                     sqlite3_column_int(session->own_identities_retrieve, 4);
   898 
   899                 pEp_identity *ident = new_identity(address, fpr, user_id, username);
   900                 if (!ident)
   901                     goto enomem;
   902                 ident->comm_type = comm_type;
   903                 if (lang && lang[0]) {
   904                     ident->lang[0] = lang[0];
   905                     ident->lang[1] = lang[1];
   906                     ident->lang[2] = 0;
   907                 }
   908                 ident->flags = flags;
   909 
   910                 _bl = identity_list_add(_bl, ident);
   911                 if (_bl == NULL) {
   912                     free_identity(ident);
   913                     goto enomem;
   914                 }
   915                 
   916                 break;
   917                 
   918             case SQLITE_DONE:
   919                 break;
   920                 
   921             default:
   922                 status = PEP_UNKNOWN_ERROR;
   923                 result = SQLITE_DONE;
   924         }
   925     } while (result != SQLITE_DONE);
   926     
   927     sqlite3_reset(session->own_identities_retrieve);
   928     if (status == PEP_STATUS_OK)
   929         *own_identities = _own_identities;
   930     else
   931         free_identity_list(_own_identities);
   932     
   933     goto the_end;
   934     
   935 enomem:
   936     free_identity_list(_own_identities);
   937     status = PEP_OUT_OF_MEMORY;
   938     
   939 the_end:
   940     return status;
   941 }
   942 
   943 DYNAMIC_API PEP_STATUS own_identities_retrieve(
   944         PEP_SESSION session,
   945         identity_list **own_identities
   946       )
   947 {
   948     return _own_identities_retrieve(session, own_identities, 0);
   949 }
   950 
   951 PEP_STATUS _own_keys_retrieve(
   952         PEP_SESSION session,
   953         stringlist_t **keylist,
   954         identity_flags_t excluded_flags
   955       )
   956 {
   957     PEP_STATUS status = PEP_STATUS_OK;
   958     
   959     assert(session && keylist);
   960     if (!(session && keylist))
   961         return PEP_ILLEGAL_VALUE;
   962     
   963     *keylist = NULL;
   964     stringlist_t *_keylist = NULL;
   965     
   966     sqlite3_reset(session->own_keys_retrieve);
   967     
   968     int result;
   969     char *fpr = NULL;
   970     
   971     stringlist_t *_bl = _keylist;
   972     do {
   973         sqlite3_bind_int(session->own_keys_retrieve, 1, excluded_flags);
   974         result = sqlite3_step(session->own_keys_retrieve);
   975         switch (result) {
   976             case SQLITE_ROW:
   977                 fpr = strdup((const char *) sqlite3_column_text(session->own_keys_retrieve, 0));
   978                 if(fpr == NULL)
   979                     goto enomem;
   980 
   981                 _bl = stringlist_add(_bl, fpr);
   982                 if (_bl == NULL) {
   983                     free(fpr);
   984                     goto enomem;
   985                 }
   986                 if (_keylist == NULL)
   987                     _keylist = _bl;
   988                 
   989                 break;
   990                 
   991             case SQLITE_DONE:
   992                 break;
   993                 
   994             default:
   995                 status = PEP_UNKNOWN_ERROR;
   996                 result = SQLITE_DONE;
   997         }
   998     } while (result != SQLITE_DONE);
   999     
  1000     sqlite3_reset(session->own_keys_retrieve);
  1001     if (status == PEP_STATUS_OK)
  1002         *keylist = _keylist;
  1003     else
  1004         free_stringlist(_keylist);
  1005     
  1006     goto the_end;
  1007     
  1008 enomem:
  1009     free_stringlist(_keylist);
  1010     status = PEP_OUT_OF_MEMORY;
  1011     
  1012 the_end:
  1013     return status;
  1014 }
  1015 
  1016 DYNAMIC_API PEP_STATUS own_keys_retrieve(PEP_SESSION session, stringlist_t **keylist)
  1017 {
  1018     return _own_keys_retrieve(session, keylist, 0);
  1019 }
  1020 
  1021 // FIXME: should it be be used when sync receive old keys ? (ENGINE-145)
  1022 DYNAMIC_API PEP_STATUS set_own_key(
  1023        PEP_SESSION session,
  1024        const char *address,
  1025        const char *fpr
  1026     )
  1027 {
  1028     PEP_STATUS status = PEP_STATUS_OK;
  1029     
  1030     assert(session &&
  1031            address &&
  1032            fpr && fpr[0]
  1033           );
  1034     
  1035     if (!(session &&
  1036           address &&
  1037           fpr && fpr[0]
  1038          ))
  1039         return PEP_ILLEGAL_VALUE;
  1040     
  1041     sqlite3_reset(session->set_own_key);
  1042     sqlite3_bind_text(session->set_own_key, 1, address, -1, SQLITE_STATIC);
  1043     sqlite3_bind_text(session->set_own_key, 2, fpr, -1, SQLITE_STATIC);
  1044 
  1045     int result;
  1046     
  1047     result = sqlite3_step(session->set_own_key);
  1048     switch (result) {
  1049         case SQLITE_DONE:
  1050             status = PEP_STATUS_OK;
  1051             break;
  1052             
  1053         default:
  1054             status = PEP_UNKNOWN_ERROR;
  1055     }
  1056     
  1057     sqlite3_reset(session->set_own_key);
  1058     return status;
  1059 }
  1060 
  1061 PEP_STATUS contains_priv_key(PEP_SESSION session, const char *fpr,
  1062                              bool *has_private) {
  1063 
  1064     assert(session);
  1065     assert(fpr);
  1066     assert(has_private);
  1067     
  1068     if (!(session && fpr && has_private))
  1069         return PEP_ILLEGAL_VALUE;
  1070 
  1071     return session->cryptotech[PEP_crypt_OpenPGP].contains_priv_key(session, fpr, has_private);
  1072 }