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