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