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