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