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