src/keymanagement.c
author Krista Bennett <krista@pep-project.org>
Wed, 17 Jan 2018 12:23:44 +0100
branchENGINE-289
changeset 2401 f5aa974726e1
parent 2399 09faff2e1f54
child 2404 ba45f3303e5f
permissions -rw-r--r--
ENGINE-289: added tests for myself() default user_id aliases, fixed consts in signature, fixed blacklist test issue
     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         
   787         status = set_userid_alias(session, default_own_id, identity->user_id);
   788         // Do we want this to be fatal? For now, we'll do it...
   789         if (status != PEP_STATUS_OK)
   790             goto pep_free;
   791             
   792         free(identity->user_id);
   793         identity->user_id = strdup(default_own_id);
   794         if (identity->user_id == NULL) {
   795             status = PEP_OUT_OF_MEMORY;
   796             goto pep_free;
   797         }
   798     }
   799 
   800     // NOTE: IF WE DON'T YET HAVE AN OWN_ID, WE IGNORE REFERENCES TO THIS ADDRESS IN THE
   801     // DB (WHICH MAY HAVE BEEN SET BEFORE MYSELF WAS CALLED BY RECEIVING AN EMAIL FROM
   802     // THIS ADDRESS), AS IT IS NOT AN OWN_IDENTITY AND HAS NO INFORMATION WE NEED OR WHAT TO
   803     // SET FOR MYSELF
   804     
   805     // Ok, so now, set up the own_identity:
   806     identity->comm_type = PEP_ct_pEp;
   807     identity->me = true;
   808     if(ignore_flags)
   809         identity->flags = 0;
   810     
   811     // Let's see if we have an identity record in the DB for 
   812     // this user_id + address
   813     DEBUG_LOG("myself", "debug", identity->address);
   814  
   815     status = get_identity(session,
   816                           identity->address,
   817                           identity->user_id,
   818                           &stored_identity);
   819 
   820     assert(status != PEP_OUT_OF_MEMORY);
   821     if (status == PEP_OUT_OF_MEMORY)
   822         return PEP_OUT_OF_MEMORY;
   823 
   824     // Set usernames - priority is input username > stored name > "Anonymous"
   825     // If there's an input username, we always patch the username with that
   826     // input.
   827     if (EMPTYSTR(identity->username)) {
   828         bool stored_uname = (stored_identity && stored_identity->username);
   829         char* uname = (stored_uname ? "Anonymous" : stored_identity->username);
   830         free(identity->username);
   831         identity->username = strdup(uname);
   832         if (identity->username == NULL)
   833             return PEP_OUT_OF_MEMORY;
   834     }
   835 
   836     bool valid_key_found = false;
   837     
   838     // Now deal with keys.
   839     // Different from update_identity(), the input fpr here
   840     // MATTERS. 
   841     // If the input fpr is invalid, we return, giving the reason why.
   842     if (identity->fpr) {
   843         status = validate_fpr(session, identity);
   844     
   845         if (status != PEP_STATUS_OK || 
   846             identity->comm_type < PEP_ct_strong_but_unconfirmed) {
   847             if (identity->comm_type != PEP_ct_key_expired)
   848                 goto pep_free;
   849             // Otherwise, it was expired and key renewal failed
   850             // and we take the stored one or do keygen. 
   851         } 
   852         else
   853             valid_key_found = true;
   854     }    
   855     
   856     // Ok, if there wasn't a valid input fpr, check stored identity
   857     if (!valid_key_found && stored_identity && 
   858         (!identity->fpr || strcmp(stored_identity->fpr, identity->fpr) != 0)) {
   859         
   860         // Fall back / retrieve
   861         status = validate_fpr(session, stored_identity);
   862         if (status == PEP_STATUS_OK && 
   863             stored_identity->comm_type >= PEP_ct_strong_but_unconfirmed) {
   864           
   865             free(identity->fpr);
   866             identity->fpr = strdup(stored_identity->fpr);
   867             valid_key_found = true;            
   868         }
   869         else {
   870             bool revoked = false;
   871             if (!EMPTYSTR(stored_identity->fpr)) {
   872                 status = key_revoked(session, stored_identity->fpr, &revoked);
   873                 if (revoked)
   874                     revoked_fpr = strdup(stored_identity->fpr);
   875             }        
   876         }
   877     }
   878     
   879     // Nothing left to do but generate a key
   880     if (!valid_key_found) {
   881         if (!do_keygen)
   882             status = PEP_GET_KEY_FAILED;
   883         else {
   884             DEBUG_LOG("Generating key pair", "debug", identity->address);
   885 
   886             free(identity->fpr);
   887             identity->fpr = NULL;
   888             status = generate_keypair(session, identity);
   889             assert(status != PEP_OUT_OF_MEMORY);
   890 
   891             if (status != PEP_STATUS_OK) {
   892                 char buf[11];
   893                 snprintf(buf, 11, "%d", status); // uh, this is kludgey. FIXME
   894                 DEBUG_LOG("Generating key pair failed", "debug", buf);
   895             }        
   896             else {
   897                 valid_key_found = true;
   898                 if (revoked_fpr) {
   899                     status = set_revoked(session, revoked_fpr,
   900                                          stored_identity->fpr, time(NULL));
   901                 }
   902             }
   903         }
   904     }
   905 
   906     if (valid_key_found) {
   907         identity->comm_type = PEP_ct_pEp;
   908         status = PEP_STATUS_OK;
   909     }
   910     else {
   911         free(identity->fpr);
   912         identity->fpr = NULL;
   913         identity->comm_type = PEP_ct_unknown;
   914     }
   915     
   916     status = set_identity(session, identity);
   917 
   918 pep_free:    
   919     free(default_own_id);
   920     free(revoked_fpr);                     
   921     free_identity(stored_identity);
   922     return ADD_TO_LOG(status);
   923 }
   924 
   925 DYNAMIC_API PEP_STATUS initialise_own_identities(PEP_SESSION session,
   926                                                  identity_list* my_idents) {
   927     PEP_STATUS status = PEP_STATUS_OK;
   928     if (!session)
   929         return PEP_ILLEGAL_VALUE;
   930         
   931     char* stored_own_userid = NULL;
   932     get_default_own_userid(session, &stored_own_userid);
   933     
   934     identity_list* ident_curr = my_idents;
   935     while (ident_curr) {
   936         pEp_identity* ident = ident_curr->ident;
   937         if (!ident)
   938             return PEP_ILLEGAL_VALUE;
   939             
   940         if (stored_own_userid) {
   941             if (!ident->user_id) 
   942                 ident->user_id = strdup(stored_own_userid);
   943             else if (strcmp(stored_own_userid, ident->user_id) != 0)
   944                 return PEP_ILLEGAL_VALUE;
   945         }
   946         else if (!ident->user_id) {
   947             stored_own_userid = PEP_OWN_USERID;
   948             ident->user_id = strdup(PEP_OWN_USERID);
   949         }
   950         
   951         ident->me = true; // Just in case.
   952         
   953         // Ok, do it...
   954         status = set_identity(session, ident);
   955         if (status != PEP_STATUS_OK)
   956             return status;
   957         
   958         ident_curr = ident_curr->next;
   959     }
   960     
   961     return status;
   962 }
   963 
   964 DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
   965 {
   966     return ADD_TO_LOG(_myself(session, identity, true, false));
   967 }
   968 
   969 DYNAMIC_API PEP_STATUS register_examine_function(
   970         PEP_SESSION session, 
   971         examine_identity_t examine_identity,
   972         void *management
   973     )
   974 {
   975     assert(session);
   976     if (!session)
   977         return PEP_ILLEGAL_VALUE;
   978 
   979     session->examine_management = management;
   980     session->examine_identity = examine_identity;
   981 
   982     return PEP_STATUS_OK;
   983 }
   984 
   985 DYNAMIC_API PEP_STATUS do_keymanagement(
   986         retrieve_next_identity_t retrieve_next_identity,
   987         void *management
   988     )
   989 {
   990     PEP_SESSION session;
   991     pEp_identity *identity;
   992     PEP_STATUS status;
   993 
   994     assert(retrieve_next_identity);
   995     assert(management);
   996 
   997     if (!retrieve_next_identity || !management)
   998         return PEP_ILLEGAL_VALUE;
   999 
  1000     status = init(&session);
  1001     assert(status == PEP_STATUS_OK);
  1002     if (status != PEP_STATUS_OK)
  1003         return status;
  1004 
  1005     log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
  1006 
  1007     while ((identity = retrieve_next_identity(management))) 
  1008     {
  1009         assert(identity->address);
  1010         if(identity->address)
  1011         {
  1012             DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
  1013 
  1014             if (identity->me) {
  1015                 status = myself(session, identity);
  1016             } else {
  1017                 status = recv_key(session, identity->address);
  1018             }
  1019 
  1020             assert(status != PEP_OUT_OF_MEMORY);
  1021             if(status == PEP_OUT_OF_MEMORY)
  1022                 return PEP_OUT_OF_MEMORY;
  1023         }
  1024         free_identity(identity);
  1025     }
  1026 
  1027     log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
  1028 
  1029     release(session);
  1030     return PEP_STATUS_OK;
  1031 }
  1032 
  1033 DYNAMIC_API PEP_STATUS key_mistrusted(
  1034         PEP_SESSION session,
  1035         pEp_identity *ident
  1036     )
  1037 {
  1038     PEP_STATUS status = PEP_STATUS_OK;
  1039 
  1040     assert(session);
  1041     assert(ident);
  1042     assert(!EMPTYSTR(ident->fpr));
  1043 
  1044     if (!(session && ident && ident->fpr))
  1045         return PEP_ILLEGAL_VALUE;
  1046 
  1047     if (ident->me)
  1048     {
  1049         revoke_key(session, ident->fpr, NULL);
  1050         myself(session, ident);
  1051     }
  1052     else
  1053     {
  1054         // for undo
  1055         if (session->cached_mistrusted)
  1056             free(session->cached_mistrusted);
  1057         session->cached_mistrusted = identity_dup(ident);
  1058         status = mark_as_compromized(session, ident->fpr);
  1059     }
  1060 
  1061     return status;
  1062 }
  1063 
  1064 DYNAMIC_API PEP_STATUS undo_last_mistrust(PEP_SESSION session) {
  1065     assert(session);
  1066     
  1067     if (!session)
  1068         return PEP_ILLEGAL_VALUE;
  1069     
  1070     PEP_STATUS status = PEP_STATUS_OK;
  1071         
  1072     pEp_identity* cached_ident = session->cached_mistrusted;
  1073     
  1074     if (!cached_ident)
  1075         status = PEP_CANNOT_FIND_IDENTITY;
  1076     else {
  1077         status = set_identity(session, cached_ident);            
  1078         free_identity(session->cached_mistrusted);
  1079     }
  1080     
  1081     session->cached_mistrusted = NULL;
  1082 
  1083     return status;
  1084 }
  1085 
  1086 DYNAMIC_API PEP_STATUS key_reset_trust(
  1087         PEP_SESSION session,
  1088         pEp_identity *ident
  1089     )
  1090 {
  1091     PEP_STATUS status = PEP_STATUS_OK;
  1092 
  1093     assert(session);
  1094     assert(ident);
  1095     assert(!ident->me);
  1096     assert(!EMPTYSTR(ident->fpr));
  1097     assert(!EMPTYSTR(ident->address));
  1098     assert(!EMPTYSTR(ident->user_id));
  1099 
  1100     if (!(session && ident && !ident->me && ident->fpr && ident->address &&
  1101             ident->user_id))
  1102         return PEP_ILLEGAL_VALUE;
  1103 
  1104     status = update_identity(session, ident);
  1105     if (status != PEP_STATUS_OK)
  1106         return status;
  1107 
  1108     if (ident->comm_type == PEP_ct_mistrusted)
  1109         ident->comm_type = PEP_ct_unknown;
  1110     else
  1111         ident->comm_type &= ~PEP_ct_confirmed;
  1112 
  1113     status = set_identity(session, ident);
  1114     if (status != PEP_STATUS_OK)
  1115         return status;
  1116 
  1117     if (ident->comm_type == PEP_ct_unknown)
  1118         status = update_identity(session, ident);
  1119     return status;
  1120 }
  1121 
  1122 DYNAMIC_API PEP_STATUS trust_personal_key(
  1123         PEP_SESSION session,
  1124         pEp_identity *ident
  1125     )
  1126 {
  1127     PEP_STATUS status = PEP_STATUS_OK;
  1128 
  1129     assert(session);
  1130     assert(ident);
  1131     assert(!EMPTYSTR(ident->address));
  1132     assert(!EMPTYSTR(ident->user_id));
  1133     assert(!EMPTYSTR(ident->fpr));
  1134 
  1135     if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
  1136             EMPTYSTR(ident->fpr))
  1137         return PEP_ILLEGAL_VALUE;
  1138 
  1139     status = update_identity(session, ident);
  1140     if (status != PEP_STATUS_OK)
  1141         return status;
  1142 
  1143     if (ident->comm_type > PEP_ct_strong_but_unconfirmed) {
  1144         ident->comm_type |= PEP_ct_confirmed;
  1145         status = set_identity(session, ident);
  1146     }
  1147     else {
  1148         // MISSING: S/MIME has to be handled depending on trusted CAs
  1149         status = PEP_CANNOT_SET_TRUST;
  1150     }
  1151 
  1152     return status;
  1153 }
  1154 
  1155 DYNAMIC_API PEP_STATUS own_key_is_listed(
  1156         PEP_SESSION session,
  1157         const char *fpr,
  1158         bool *listed
  1159     )
  1160 {
  1161     PEP_STATUS status = PEP_STATUS_OK;
  1162     int count;
  1163     
  1164     assert(session && fpr && fpr[0] && listed);
  1165     
  1166     if (!(session && fpr && fpr[0] && listed))
  1167         return PEP_ILLEGAL_VALUE;
  1168     
  1169     *listed = false;
  1170     
  1171     sqlite3_reset(session->own_key_is_listed);
  1172     sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1, SQLITE_STATIC);
  1173     
  1174     int result;
  1175     
  1176     result = sqlite3_step(session->own_key_is_listed);
  1177     switch (result) {
  1178         case SQLITE_ROW:
  1179             count = sqlite3_column_int(session->own_key_is_listed, 0);
  1180             *listed = count > 0;
  1181             status = PEP_STATUS_OK;
  1182             break;
  1183             
  1184         default:
  1185             status = PEP_UNKNOWN_ERROR;
  1186     }
  1187     
  1188     sqlite3_reset(session->own_key_is_listed);
  1189     return status;
  1190 }
  1191 
  1192 PEP_STATUS _own_identities_retrieve(
  1193         PEP_SESSION session,
  1194         identity_list **own_identities,
  1195         identity_flags_t excluded_flags
  1196       )
  1197 {
  1198     PEP_STATUS status = PEP_STATUS_OK;
  1199     
  1200     assert(session && own_identities);
  1201     if (!(session && own_identities))
  1202         return PEP_ILLEGAL_VALUE;
  1203     
  1204     *own_identities = NULL;
  1205     identity_list *_own_identities = new_identity_list(NULL);
  1206     if (_own_identities == NULL)
  1207         goto enomem;
  1208     
  1209     sqlite3_reset(session->own_identities_retrieve);
  1210     
  1211     int result;
  1212     // address, fpr, username, user_id, comm_type, lang, flags
  1213     const char *address = NULL;
  1214     const char *fpr = NULL;
  1215     const char *username = NULL;
  1216     const char *user_id = NULL;
  1217     PEP_comm_type comm_type = PEP_ct_unknown;
  1218     const char *lang = NULL;
  1219     unsigned int flags = 0;
  1220     
  1221     identity_list *_bl = _own_identities;
  1222     do {
  1223         sqlite3_bind_int(session->own_identities_retrieve, 1, excluded_flags);
  1224         result = sqlite3_step(session->own_identities_retrieve);
  1225         switch (result) {
  1226             case SQLITE_ROW:
  1227                 address = (const char *)
  1228                     sqlite3_column_text(session->own_identities_retrieve, 0);
  1229                 fpr = (const char *)
  1230                     sqlite3_column_text(session->own_identities_retrieve, 1);
  1231                 user_id = (const char *)
  1232                     sqlite3_column_text(session->own_identities_retrieve, 2);
  1233                 username = (const char *)
  1234                     sqlite3_column_text(session->own_identities_retrieve, 3);
  1235                 comm_type = PEP_ct_pEp;
  1236                 lang = (const char *)
  1237                     sqlite3_column_text(session->own_identities_retrieve, 4);
  1238                 flags = (unsigned int)
  1239                     sqlite3_column_int(session->own_identities_retrieve, 5);
  1240 
  1241                 pEp_identity *ident = new_identity(address, fpr, user_id, username);
  1242                 if (!ident)
  1243                     goto enomem;
  1244                 ident->comm_type = comm_type;
  1245                 if (lang && lang[0]) {
  1246                     ident->lang[0] = lang[0];
  1247                     ident->lang[1] = lang[1];
  1248                     ident->lang[2] = 0;
  1249                 }
  1250                 ident->me = true;
  1251                 ident->flags = flags;
  1252 
  1253                 _bl = identity_list_add(_bl, ident);
  1254                 if (_bl == NULL) {
  1255                     free_identity(ident);
  1256                     goto enomem;
  1257                 }
  1258                 
  1259                 break;
  1260                 
  1261             case SQLITE_DONE:
  1262                 break;
  1263                 
  1264             default:
  1265                 status = PEP_UNKNOWN_ERROR;
  1266                 result = SQLITE_DONE;
  1267         }
  1268     } while (result != SQLITE_DONE);
  1269     
  1270     sqlite3_reset(session->own_identities_retrieve);
  1271     if (status == PEP_STATUS_OK)
  1272         *own_identities = _own_identities;
  1273     else
  1274         free_identity_list(_own_identities);
  1275     
  1276     goto the_end;
  1277     
  1278 enomem:
  1279     free_identity_list(_own_identities);
  1280     status = PEP_OUT_OF_MEMORY;
  1281     
  1282 the_end:
  1283     return status;
  1284 }
  1285 
  1286 DYNAMIC_API PEP_STATUS own_identities_retrieve(
  1287         PEP_SESSION session,
  1288         identity_list **own_identities
  1289       )
  1290 {
  1291     return _own_identities_retrieve(session, own_identities, 0);
  1292 }
  1293 
  1294 PEP_STATUS _own_keys_retrieve(
  1295         PEP_SESSION session,
  1296         stringlist_t **keylist,
  1297         identity_flags_t excluded_flags
  1298       )
  1299 {
  1300     PEP_STATUS status = PEP_STATUS_OK;
  1301     
  1302     assert(session && keylist);
  1303     if (!(session && keylist))
  1304         return PEP_ILLEGAL_VALUE;
  1305     
  1306     *keylist = NULL;
  1307     stringlist_t *_keylist = NULL;
  1308     
  1309     sqlite3_reset(session->own_keys_retrieve);
  1310     
  1311     int result;
  1312     char *fpr = NULL;
  1313     
  1314     stringlist_t *_bl = _keylist;
  1315     do {
  1316         sqlite3_bind_int(session->own_keys_retrieve, 1, excluded_flags);
  1317         result = sqlite3_step(session->own_keys_retrieve);
  1318         switch (result) {
  1319             case SQLITE_ROW:
  1320                 fpr = strdup((const char *) sqlite3_column_text(session->own_keys_retrieve, 0));
  1321                 if(fpr == NULL)
  1322                     goto enomem;
  1323 
  1324                 _bl = stringlist_add(_bl, fpr);
  1325                 if (_bl == NULL) {
  1326                     free(fpr);
  1327                     goto enomem;
  1328                 }
  1329                 if (_keylist == NULL)
  1330                     _keylist = _bl;
  1331                 
  1332                 break;
  1333                 
  1334             case SQLITE_DONE:
  1335                 break;
  1336                 
  1337             default:
  1338                 status = PEP_UNKNOWN_ERROR;
  1339                 result = SQLITE_DONE;
  1340         }
  1341     } while (result != SQLITE_DONE);
  1342     
  1343     sqlite3_reset(session->own_keys_retrieve);
  1344     if (status == PEP_STATUS_OK)
  1345         *keylist = _keylist;
  1346     else
  1347         free_stringlist(_keylist);
  1348     
  1349     goto the_end;
  1350     
  1351 enomem:
  1352     free_stringlist(_keylist);
  1353     status = PEP_OUT_OF_MEMORY;
  1354     
  1355 the_end:
  1356     return status;
  1357 }
  1358 
  1359 DYNAMIC_API PEP_STATUS own_keys_retrieve(PEP_SESSION session, stringlist_t **keylist)
  1360 {
  1361     return _own_keys_retrieve(session, keylist, 0);
  1362 }
  1363 
  1364 // FIXME: should it be be used when sync receive old keys ? (ENGINE-145)
  1365 DYNAMIC_API PEP_STATUS set_own_key(
  1366        PEP_SESSION session,
  1367        const char *address,
  1368        const char *fpr
  1369     )
  1370 {
  1371     PEP_STATUS status = PEP_STATUS_OK;
  1372     
  1373     assert(session &&
  1374            address &&
  1375            fpr && fpr[0]
  1376           );
  1377     
  1378     if (!(session &&
  1379           address &&
  1380           fpr && fpr[0]
  1381          ))
  1382         return PEP_ILLEGAL_VALUE;
  1383                         
  1384     // First see if we have it in own identities already, AND we retrieve
  1385     // our own user_id
  1386     char* my_user_id = NULL;
  1387     status = get_default_own_userid(session, &my_user_id);
  1388     if (status != PEP_STATUS_OK)
  1389         return status;
  1390         
  1391     if (!my_user_id) {
  1392         // We have no own user_id. So we cannot set it for an identity.
  1393         return PEP_CANNOT_FIND_IDENTITY;
  1394     }
  1395     
  1396     pEp_identity* my_id = NULL;
  1397     
  1398     status = get_identity(session, my_user_id, address, &my_id);
  1399 
  1400     if (status == PEP_STATUS_OK && my_id) {
  1401         if (my_id->fpr && strcasecmp(my_id->fpr, fpr) == 0) {
  1402             // We're done. It was already here.
  1403             goto pep_free;
  1404         }           
  1405     }
  1406                 
  1407     // If there's an id w/ user_id + address
  1408     if (my_id) {
  1409         free(my_id->fpr);
  1410         my_id->fpr = my_user_id;
  1411         my_id->comm_type = PEP_ct_pEp;
  1412         my_id->me = true;
  1413     }
  1414     else { // Else, we need a new identity
  1415         my_id = new_identity(address, fpr, my_user_id, NULL); 
  1416         if (status != PEP_STATUS_OK)
  1417             goto pep_free; 
  1418         my_id->me = true;
  1419         my_id->comm_type = PEP_ct_pEp;
  1420     }
  1421         
  1422     status = set_identity(session, my_id);
  1423     
  1424 pep_free:
  1425     free(my_id);
  1426     free(my_user_id);
  1427     return status;
  1428 }
  1429 
  1430 PEP_STATUS contains_priv_key(PEP_SESSION session, const char *fpr,
  1431                              bool *has_private) {
  1432 
  1433     assert(session);
  1434     assert(fpr);
  1435     assert(has_private);
  1436     
  1437     if (!(session && fpr && has_private))
  1438         return PEP_ILLEGAL_VALUE;
  1439 
  1440     return session->cryptotech[PEP_crypt_OpenPGP].contains_priv_key(session, fpr, has_private);
  1441 }