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