src/keymanagement.c
author Krista Grothoff <krista@pep-project.org>
Fri, 13 Jan 2017 15:37:35 +0100
changeset 1535 3efb259b8d2c
parent 1522 57c2dbcb70dd
child 1559 c6506bc6a0df
permissions -rw-r--r--
Removed assert, because an empty username is totally valid input from an email, and we deal with it directly in the code that follows where the assert was.
     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;
    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;
    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     
   312     if (stored_identity){
   313         free_identity(stored_identity);
   314     }
   315 
   316     if (temp_id)
   317         free_identity(temp_id);
   318     
   319     return status;
   320 }
   321 
   322 PEP_STATUS elect_ownkey(
   323         PEP_SESSION session, pEp_identity * identity
   324     )
   325 {
   326     PEP_STATUS status;
   327     stringlist_t *keylist = NULL;
   328 
   329     free(identity->fpr);
   330     identity->fpr = NULL;
   331 
   332     status = find_private_keys(session, identity->address, &keylist);
   333     assert(status != PEP_OUT_OF_MEMORY);
   334     if (status == PEP_OUT_OF_MEMORY)
   335         return PEP_OUT_OF_MEMORY;
   336     
   337     if (keylist != NULL && keylist->value != NULL)
   338     {
   339         char *_fpr = NULL;
   340         identity->comm_type = PEP_ct_unknown;
   341 
   342         stringlist_t *_keylist;
   343         for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
   344             bool is_own = false;
   345             
   346             if (session->use_only_own_private_keys)
   347             {
   348                 status = own_key_is_listed(session, _keylist->value, &is_own);
   349                 assert(status == PEP_STATUS_OK);
   350                 if (status != PEP_STATUS_OK) {
   351                     free_stringlist(keylist);
   352                     return status;
   353                 }
   354             }
   355 
   356             // TODO : also accept synchronized device group keys ?
   357             
   358             if (!session->use_only_own_private_keys || is_own)
   359             {
   360                 PEP_comm_type _comm_type_key;
   361                 
   362                 status = get_key_rating(session, _keylist->value, &_comm_type_key);
   363                 assert(status != PEP_OUT_OF_MEMORY);
   364                 if (status == PEP_OUT_OF_MEMORY) {
   365                     free_stringlist(keylist);
   366                     return PEP_OUT_OF_MEMORY;
   367                 }
   368                 
   369                 if (_comm_type_key != PEP_ct_compromized &&
   370                     _comm_type_key != PEP_ct_unknown)
   371                 {
   372                     if (identity->comm_type == PEP_ct_unknown ||
   373                         _comm_type_key > identity->comm_type)
   374                     {
   375                         identity->comm_type = _comm_type_key;
   376                         _fpr = _keylist->value;
   377                     }
   378                 }
   379             }
   380         }
   381         
   382         if (_fpr)
   383         {
   384             identity->fpr = strdup(_fpr);
   385             assert(identity->fpr);
   386             if (identity->fpr == NULL)
   387             {
   388                 free_stringlist(keylist);
   389                 return PEP_OUT_OF_MEMORY;
   390             }
   391         }
   392         free_stringlist(keylist);
   393     }
   394     return PEP_STATUS_OK;
   395 }
   396 
   397 PEP_STATUS _has_usable_priv_key(PEP_SESSION session, char* fpr,
   398                                 bool* is_usable) {
   399     
   400     bool dont_use_fpr = true;
   401     
   402     PEP_STATUS status = blacklist_is_listed(session, fpr, &dont_use_fpr);
   403     if (status == PEP_STATUS_OK && !dont_use_fpr) {
   404         // Make sure there is a *private* key associated with this fpr
   405         bool has_private = false;
   406         status = contains_priv_key(session, fpr, &has_private);
   407 
   408         if (status == PEP_STATUS_OK)
   409             dont_use_fpr = !has_private;
   410     }
   411     
   412     *is_usable = !dont_use_fpr;
   413     
   414     return status;
   415 }
   416 
   417 PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags)
   418 {
   419     pEp_identity *stored_identity;
   420     PEP_STATUS status;
   421 
   422     assert(session);
   423     assert(identity);
   424     assert(!EMPTYSTR(identity->address));
   425 
   426     assert(EMPTYSTR(identity->user_id) ||
   427            strcmp(identity->user_id, PEP_OWN_USERID) == 0);
   428 
   429     if (!(session && identity && !EMPTYSTR(identity->address) &&
   430             (EMPTYSTR(identity->user_id) ||
   431             strcmp(identity->user_id, PEP_OWN_USERID) == 0)))
   432         return PEP_ILLEGAL_VALUE;
   433 
   434     identity->comm_type = PEP_ct_pEp;
   435     identity->me = true;
   436     if(ignore_flags)
   437         identity->flags = 0;
   438     
   439     if (EMPTYSTR(identity->user_id))
   440     {
   441         free(identity->user_id);
   442         identity->user_id = strdup(PEP_OWN_USERID);
   443         assert(identity->user_id);
   444         if (identity->user_id == NULL)
   445             return PEP_OUT_OF_MEMORY;
   446     }
   447 
   448     if (EMPTYSTR(identity->username))
   449     {
   450         free(identity->username);
   451         identity->username = strdup("anonymous");
   452         assert(identity->username);
   453         if (identity->username == NULL)
   454             return PEP_OUT_OF_MEMORY;
   455     }
   456 
   457     DEBUG_LOG("myself", "debug", identity->address);
   458  
   459     status = get_identity(session,
   460                           identity->address,
   461                           identity->user_id,
   462                           &stored_identity);
   463     
   464     assert(status != PEP_OUT_OF_MEMORY);
   465     if (status == PEP_OUT_OF_MEMORY)
   466         return PEP_OUT_OF_MEMORY;
   467 
   468     bool dont_use_stored_fpr = true;
   469     bool dont_use_input_fpr = true;
   470         
   471     if (stored_identity)
   472     {
   473         if (EMPTYSTR(identity->fpr)) {
   474             
   475             bool has_private = false;
   476             
   477             status = _has_usable_priv_key(session, stored_identity->fpr, &has_private); 
   478             
   479             // N.B. has_private is never true if the returned status is not PEP_STATUS_OK
   480             if (has_private) {
   481                 identity->fpr = strdup(stored_identity->fpr);
   482                 assert(identity->fpr);
   483                 if (identity->fpr == NULL)
   484                 {
   485                     return PEP_OUT_OF_MEMORY;
   486                 }
   487                 dont_use_stored_fpr = false;
   488             }
   489         }
   490         
   491         identity->flags = (identity->flags & 255) | stored_identity->flags;
   492 
   493         free_identity(stored_identity);
   494     }
   495     
   496     if (dont_use_stored_fpr && !EMPTYSTR(identity->fpr))
   497     {
   498         // App must have a good reason to give fpr, such as explicit
   499         // import of private key, or similar.
   500 
   501         // Take given fpr as-is.
   502 
   503         // BUT:
   504         // First check to see if it's blacklisted or private part is missing?
   505         bool has_private = false;
   506         
   507         status = _has_usable_priv_key(session, identity->fpr, &has_private); 
   508         
   509         // N.B. has_private is never true if the returned status is not PEP_STATUS_OK
   510         if (has_private) {
   511             dont_use_input_fpr = false;
   512         }
   513     }
   514     
   515     // Ok, we failed to get keys either way, so let's elect one.
   516     if (dont_use_input_fpr && dont_use_stored_fpr)
   517     {
   518         status = elect_ownkey(session, identity);
   519         assert(status == PEP_STATUS_OK);
   520         if (status != PEP_STATUS_OK) {
   521             return status;
   522         }
   523 
   524         bool has_private = false;
   525         if (identity->fpr) {
   526             // ok, we elected something.
   527             // elect_ownkey only returns private keys, so we don't check again.
   528             // Check to see if it's blacklisted
   529             bool listed;
   530             status = blacklist_is_listed(session, identity->fpr, &listed); 
   531 
   532             if (status == PEP_STATUS_OK)
   533                 has_private = !listed;
   534         }
   535         
   536         if (has_private) {
   537             dont_use_input_fpr = false;
   538         }
   539         else { // OK, we've tried everything. Time to generate new keys.
   540             free(identity->fpr); // It can stay in this state (unallocated) because we'll generate a new key 
   541             identity->fpr = NULL;
   542         }
   543     }
   544 
   545     bool revoked = false;
   546     char *r_fpr = NULL;
   547     if (!EMPTYSTR(identity->fpr))
   548     {
   549         status = key_revoked(session, identity->fpr, &revoked);
   550 
   551         // Forces re-election if key is missing and own-key-only not forced
   552         if (!session->use_only_own_private_keys && status == PEP_KEY_NOT_FOUND) 
   553         {
   554             status = elect_ownkey(session, identity);
   555             assert(status == PEP_STATUS_OK);
   556             if (status != PEP_STATUS_OK) {
   557                 return status;
   558             }
   559         } 
   560         else if (status != PEP_STATUS_OK) 
   561         {
   562             return status;
   563         }
   564     }
   565    
   566     bool new_key_generated = false;
   567 
   568     if (EMPTYSTR(identity->fpr) || revoked)
   569     {        
   570         if(!do_keygen){
   571             return PEP_GET_KEY_FAILED;
   572         }
   573 
   574         if(revoked)
   575         {
   576             r_fpr = identity->fpr;
   577             identity->fpr = NULL;
   578         }
   579         
   580         DEBUG_LOG("generating key pair", "debug", identity->address);
   581         status = generate_keypair(session, identity);
   582         assert(status != PEP_OUT_OF_MEMORY);
   583         if (status != PEP_STATUS_OK) {
   584             char buf[11];
   585             snprintf(buf, 11, "%d", status);
   586             DEBUG_LOG("generating key pair failed", "debug", buf);
   587             if(revoked && r_fpr)
   588                 free(r_fpr);
   589             return status;
   590         }
   591 
   592         new_key_generated = true;
   593         
   594         if(revoked)
   595         {
   596             status = set_revoked(session, r_fpr,
   597                                  identity->fpr, time(NULL));
   598             free(r_fpr);
   599             if (status != PEP_STATUS_OK) {
   600                 return status;
   601             }
   602         }
   603     }
   604     else
   605     {
   606         bool expired;
   607         status = key_expired(session, identity->fpr, 
   608                              time(NULL) + (7*24*3600), // In a week
   609                              &expired);
   610 
   611         assert(status == PEP_STATUS_OK);
   612         if (status != PEP_STATUS_OK) {
   613             return status;
   614         }
   615 
   616         if (status == PEP_STATUS_OK && expired) {
   617             timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
   618             renew_key(session, identity->fpr, ts);
   619             free_timestamp(ts);
   620         }
   621     }
   622 
   623     if (!identity->username)
   624         identity->username = strdup("");
   625     
   626     status = set_identity(session, identity);
   627     assert(status == PEP_STATUS_OK);
   628     if (status != PEP_STATUS_OK) {
   629         return status;
   630     }
   631 
   632     if(new_key_generated)
   633     {
   634         // if a state machine for keysync is in place, inject notify
   635         status = inject_DeviceState_event(session, KeyGen, NULL, NULL);
   636         if (status == PEP_OUT_OF_MEMORY){
   637             return PEP_OUT_OF_MEMORY;
   638         }
   639     }
   640 
   641     return PEP_STATUS_OK;
   642 
   643 }
   644 
   645 DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
   646 {
   647     return _myself(session, identity, true, false);
   648 }
   649 
   650 DYNAMIC_API PEP_STATUS register_examine_function(
   651         PEP_SESSION session, 
   652         examine_identity_t examine_identity,
   653         void *management
   654     )
   655 {
   656     assert(session);
   657     if (!session)
   658         return PEP_ILLEGAL_VALUE;
   659 
   660     session->examine_management = management;
   661     session->examine_identity = examine_identity;
   662 
   663     return PEP_STATUS_OK;
   664 }
   665 
   666 DYNAMIC_API PEP_STATUS do_keymanagement(
   667         retrieve_next_identity_t retrieve_next_identity,
   668         void *management
   669     )
   670 {
   671     PEP_SESSION session;
   672     pEp_identity *identity;
   673     PEP_STATUS status;
   674 
   675     assert(retrieve_next_identity);
   676     assert(management);
   677 
   678     if (!retrieve_next_identity || !management)
   679         return PEP_ILLEGAL_VALUE;
   680 
   681     status = init(&session);
   682     assert(status == PEP_STATUS_OK);
   683     if (status != PEP_STATUS_OK)
   684         return status;
   685 
   686     log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
   687 
   688     while ((identity = retrieve_next_identity(management))) 
   689     {
   690         assert(identity->address);
   691         if(identity->address)
   692         {
   693             DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
   694 
   695             if (identity->me) {
   696                 status = myself(session, identity);
   697             } else {
   698                 status = recv_key(session, identity->address);
   699             }
   700 
   701             assert(status != PEP_OUT_OF_MEMORY);
   702             if(status == PEP_OUT_OF_MEMORY)
   703                 return PEP_OUT_OF_MEMORY;
   704         }
   705         free_identity(identity);
   706     }
   707 
   708     log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
   709 
   710     release(session);
   711     return PEP_STATUS_OK;
   712 }
   713 
   714 DYNAMIC_API PEP_STATUS key_mistrusted(
   715         PEP_SESSION session,
   716         pEp_identity *ident
   717     )
   718 {
   719     PEP_STATUS status = PEP_STATUS_OK;
   720 
   721     assert(session);
   722     assert(ident);
   723     assert(!EMPTYSTR(ident->fpr));
   724 
   725     if (!(session && ident && ident->fpr))
   726         return PEP_ILLEGAL_VALUE;
   727 
   728     if (ident->me)
   729     {
   730         revoke_key(session, ident->fpr, NULL);
   731         myself(session, ident);
   732     }
   733     else
   734     {
   735         status = mark_as_compromized(session, ident->fpr);
   736     }
   737 
   738     return status;
   739 }
   740 
   741 DYNAMIC_API PEP_STATUS key_reset_trust(
   742         PEP_SESSION session,
   743         pEp_identity *ident
   744     )
   745 {
   746     PEP_STATUS status = PEP_STATUS_OK;
   747 
   748     assert(session);
   749     assert(ident);
   750     assert(!ident->me);
   751     assert(!EMPTYSTR(ident->fpr));
   752     assert(!EMPTYSTR(ident->address));
   753     assert(!EMPTYSTR(ident->user_id));
   754 
   755     if (!(session && ident && !ident->me && ident->fpr && ident->address &&
   756             ident->user_id))
   757         return PEP_ILLEGAL_VALUE;
   758 
   759     status = update_identity(session, ident);
   760     if (status != PEP_STATUS_OK)
   761         return status;
   762 
   763     if (ident->comm_type == PEP_ct_mistrusted)
   764         ident->comm_type = PEP_ct_unknown;
   765     else
   766         ident->comm_type &= ~PEP_ct_confirmed;
   767 
   768     status = set_identity(session, ident);
   769     if (status != PEP_STATUS_OK)
   770         return status;
   771 
   772     if (ident->comm_type == PEP_ct_unknown)
   773         status = update_identity(session, ident);
   774     return status;
   775 }
   776 
   777 DYNAMIC_API PEP_STATUS trust_personal_key(
   778         PEP_SESSION session,
   779         pEp_identity *ident
   780     )
   781 {
   782     PEP_STATUS status = PEP_STATUS_OK;
   783 
   784     assert(session);
   785     assert(ident);
   786     assert(!EMPTYSTR(ident->address));
   787     assert(!EMPTYSTR(ident->user_id));
   788     assert(!EMPTYSTR(ident->fpr));
   789     assert(!ident->me);
   790 
   791     if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
   792             EMPTYSTR(ident->fpr) || ident->me)
   793         return PEP_ILLEGAL_VALUE;
   794 
   795     status = update_identity(session, ident);
   796     if (status != PEP_STATUS_OK)
   797         return status;
   798 
   799     if (ident->comm_type > PEP_ct_strong_but_unconfirmed) {
   800         ident->comm_type |= PEP_ct_confirmed;
   801         status = set_identity(session, ident);
   802     }
   803     else {
   804         // MISSING: S/MIME has to be handled depending on trusted CAs
   805         status = PEP_CANNOT_SET_TRUST;
   806     }
   807 
   808     return status;
   809 }
   810 
   811 DYNAMIC_API PEP_STATUS own_key_is_listed(
   812         PEP_SESSION session,
   813         const char *fpr,
   814         bool *listed
   815     )
   816 {
   817     PEP_STATUS status = PEP_STATUS_OK;
   818     int count;
   819     
   820     assert(session && fpr && fpr[0] && listed);
   821     
   822     if (!(session && fpr && fpr[0] && listed))
   823         return PEP_ILLEGAL_VALUE;
   824     
   825     *listed = false;
   826     
   827     sqlite3_reset(session->own_key_is_listed);
   828     sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1, SQLITE_STATIC);
   829     
   830     int result;
   831     
   832     result = sqlite3_step(session->own_key_is_listed);
   833     switch (result) {
   834         case SQLITE_ROW:
   835             count = sqlite3_column_int(session->own_key_is_listed, 0);
   836             *listed = count > 0;
   837             status = PEP_STATUS_OK;
   838             break;
   839             
   840         default:
   841             status = PEP_UNKNOWN_ERROR;
   842     }
   843     
   844     sqlite3_reset(session->own_key_is_listed);
   845     return status;
   846 }
   847 
   848 PEP_STATUS _own_identities_retrieve(
   849         PEP_SESSION session,
   850         identity_list **own_identities,
   851         identity_flags_t excluded_flags
   852       )
   853 {
   854     PEP_STATUS status = PEP_STATUS_OK;
   855     
   856     assert(session && own_identities);
   857     if (!(session && own_identities))
   858         return PEP_ILLEGAL_VALUE;
   859     
   860     *own_identities = NULL;
   861     identity_list *_own_identities = new_identity_list(NULL);
   862     if (_own_identities == NULL)
   863         goto enomem;
   864     
   865     sqlite3_reset(session->own_identities_retrieve);
   866     
   867     int result;
   868     // address, fpr, username, user_id, comm_type, lang, flags
   869     const char *address = NULL;
   870     const char *fpr = NULL;
   871     const char *username = NULL;
   872     const char *user_id = NULL;
   873     PEP_comm_type comm_type = PEP_ct_unknown;
   874     const char *lang = NULL;
   875     unsigned int flags = 0;
   876     
   877     identity_list *_bl = _own_identities;
   878     do {
   879         sqlite3_bind_int(session->own_identities_retrieve, 1, excluded_flags);
   880         result = sqlite3_step(session->own_identities_retrieve);
   881         switch (result) {
   882             case SQLITE_ROW:
   883                 address = (const char *)
   884                     sqlite3_column_text(session->own_identities_retrieve, 0);
   885                 fpr = (const char *)
   886                     sqlite3_column_text(session->own_identities_retrieve, 1);
   887                 user_id = PEP_OWN_USERID;
   888                 username = (const char *)
   889                     sqlite3_column_text(session->own_identities_retrieve, 2);
   890                 comm_type = PEP_ct_pEp;
   891                 lang = (const char *)
   892                     sqlite3_column_text(session->own_identities_retrieve, 3);
   893                 flags = (unsigned int)
   894                     sqlite3_column_int(session->own_identities_retrieve, 4);
   895 
   896                 pEp_identity *ident = new_identity(address, fpr, user_id, username);
   897                 if (!ident)
   898                     goto enomem;
   899                 ident->comm_type = comm_type;
   900                 if (lang && lang[0]) {
   901                     ident->lang[0] = lang[0];
   902                     ident->lang[1] = lang[1];
   903                     ident->lang[2] = 0;
   904                 }
   905                 ident->me = true;
   906                 ident->flags = flags;
   907 
   908                 _bl = identity_list_add(_bl, ident);
   909                 if (_bl == NULL) {
   910                     free_identity(ident);
   911                     goto enomem;
   912                 }
   913                 
   914                 break;
   915                 
   916             case SQLITE_DONE:
   917                 break;
   918                 
   919             default:
   920                 status = PEP_UNKNOWN_ERROR;
   921                 result = SQLITE_DONE;
   922         }
   923     } while (result != SQLITE_DONE);
   924     
   925     sqlite3_reset(session->own_identities_retrieve);
   926     if (status == PEP_STATUS_OK)
   927         *own_identities = _own_identities;
   928     else
   929         free_identity_list(_own_identities);
   930     
   931     goto the_end;
   932     
   933 enomem:
   934     free_identity_list(_own_identities);
   935     status = PEP_OUT_OF_MEMORY;
   936     
   937 the_end:
   938     return status;
   939 }
   940 
   941 DYNAMIC_API PEP_STATUS own_identities_retrieve(
   942         PEP_SESSION session,
   943         identity_list **own_identities
   944       )
   945 {
   946     return _own_identities_retrieve(session, own_identities, 0);
   947 }
   948 
   949 PEP_STATUS _own_keys_retrieve(
   950         PEP_SESSION session,
   951         stringlist_t **keylist,
   952         identity_flags_t excluded_flags
   953       )
   954 {
   955     PEP_STATUS status = PEP_STATUS_OK;
   956     
   957     assert(session && keylist);
   958     if (!(session && keylist))
   959         return PEP_ILLEGAL_VALUE;
   960     
   961     *keylist = NULL;
   962     stringlist_t *_keylist = NULL;
   963     
   964     sqlite3_reset(session->own_keys_retrieve);
   965     
   966     int result;
   967     char *fpr = NULL;
   968     
   969     stringlist_t *_bl = _keylist;
   970     do {
   971         sqlite3_bind_int(session->own_keys_retrieve, 1, excluded_flags);
   972         result = sqlite3_step(session->own_keys_retrieve);
   973         switch (result) {
   974             case SQLITE_ROW:
   975                 fpr = strdup((const char *) sqlite3_column_text(session->own_keys_retrieve, 0));
   976                 if(fpr == NULL)
   977                     goto enomem;
   978 
   979                 _bl = stringlist_add(_bl, fpr);
   980                 if (_bl == NULL) {
   981                     free(fpr);
   982                     goto enomem;
   983                 }
   984                 if (_keylist == NULL)
   985                     _keylist = _bl;
   986                 
   987                 break;
   988                 
   989             case SQLITE_DONE:
   990                 break;
   991                 
   992             default:
   993                 status = PEP_UNKNOWN_ERROR;
   994                 result = SQLITE_DONE;
   995         }
   996     } while (result != SQLITE_DONE);
   997     
   998     sqlite3_reset(session->own_keys_retrieve);
   999     if (status == PEP_STATUS_OK)
  1000         *keylist = _keylist;
  1001     else
  1002         free_stringlist(_keylist);
  1003     
  1004     goto the_end;
  1005     
  1006 enomem:
  1007     free_stringlist(_keylist);
  1008     status = PEP_OUT_OF_MEMORY;
  1009     
  1010 the_end:
  1011     return status;
  1012 }
  1013 
  1014 DYNAMIC_API PEP_STATUS own_keys_retrieve(PEP_SESSION session, stringlist_t **keylist)
  1015 {
  1016     return _own_keys_retrieve(session, keylist, 0);
  1017 }
  1018 
  1019 // TODO: Unused for now, but should be used when sync receive old keys (ENGINE-145)
  1020 DYNAMIC_API PEP_STATUS set_own_key(
  1021        PEP_SESSION session,
  1022        const char *address,
  1023        const char *fpr
  1024     )
  1025 {
  1026     PEP_STATUS status = PEP_STATUS_OK;
  1027     
  1028     assert(session &&
  1029            address && address[0] &&
  1030            fpr && fpr[0]
  1031           );
  1032     
  1033     if (!(session &&
  1034           address && address[0] &&
  1035           fpr && fpr[0]
  1036          ))
  1037         return PEP_ILLEGAL_VALUE;
  1038     
  1039     sqlite3_reset(session->set_own_key);
  1040     sqlite3_bind_text(session->set_own_key, 1, address, -1, SQLITE_STATIC);
  1041     sqlite3_bind_text(session->set_own_key, 2, fpr, -1, SQLITE_STATIC);
  1042 
  1043     int result;
  1044     
  1045     result = sqlite3_step(session->set_own_key);
  1046     switch (result) {
  1047         case SQLITE_DONE:
  1048             status = PEP_STATUS_OK;
  1049             break;
  1050             
  1051         default:
  1052             status = PEP_UNKNOWN_ERROR;
  1053     }
  1054     
  1055     sqlite3_reset(session->set_own_key);
  1056     return status;
  1057 }
  1058 
  1059 PEP_STATUS contains_priv_key(PEP_SESSION session, const char *fpr,
  1060                              bool *has_private) {
  1061 
  1062     assert(session);
  1063     assert(fpr);
  1064     assert(has_private);
  1065     
  1066     if (!(session && fpr && has_private))
  1067         return PEP_ILLEGAL_VALUE;
  1068 
  1069     return session->cryptotech[PEP_crypt_OpenPGP].contains_priv_key(session, fpr, has_private);
  1070 }