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