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