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