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