src/keymanagement.c
author Roker <roker@pep-project.org>
Tue, 09 May 2017 09:31:15 +0200
branchENGINE-199
changeset 1764 e1c31ee55aad
parent 1753 01faac16cec6
parent 1760 f691b9603e8b
child 1765 1693d16c36ea
permissions -rw-r--r--
merge "default" into my branch
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "platform.h"
     5 
     6 #include <string.h>
     7 #include <stdio.h>
     8 #include <stdlib.h>
     9 #include <assert.h>
    10 #include <ctype.h>
    11 
    12 #include "pEp_internal.h"
    13 #include "keymanagement.h"
    14 
    15 #include "sync_fsm.h"
    16 #include "blacklist.h"
    17 
    18 #ifndef EMPTYSTR
    19 #define EMPTYSTR(STR) ((STR) == NULL || (STR)[0] == '\0')
    20 #endif
    21 
    22 #define KEY_EXPIRE_DELTA (60 * 60 * 24 * 365)
    23 
    24 PEP_STATUS elect_pubkey(
    25         PEP_SESSION session, pEp_identity * identity
    26     )
    27 {
    28     PEP_STATUS status;
    29     stringlist_t *keylist = NULL;
    30     char *_fpr = "";
    31     identity->comm_type = PEP_ct_unknown;
    32 
    33     status = find_keys(session, identity->address, &keylist);
    34     assert(status != PEP_OUT_OF_MEMORY);
    35     if (status == PEP_OUT_OF_MEMORY)
    36         return PEP_OUT_OF_MEMORY;
    37 
    38     stringlist_t *_keylist;
    39     for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
    40         PEP_comm_type _comm_type_key;
    41 
    42         status = get_key_rating(session, _keylist->value, &_comm_type_key);
    43         assert(status != PEP_OUT_OF_MEMORY);
    44         if (status == PEP_OUT_OF_MEMORY) {
    45             free_stringlist(keylist);
    46             return PEP_OUT_OF_MEMORY;
    47         }
    48 
    49         if (_comm_type_key != PEP_ct_compromized &&
    50             _comm_type_key != PEP_ct_unknown)
    51         {
    52             if (identity->comm_type == PEP_ct_unknown ||
    53                 _comm_type_key > identity->comm_type)
    54             {
    55                 bool blacklisted;
    56                 status = blacklist_is_listed(session, _keylist->value, &blacklisted);
    57                 if (status == PEP_STATUS_OK && !blacklisted) {
    58                     identity->comm_type = _comm_type_key;
    59                     _fpr = _keylist->value;
    60                 }
    61             }
    62         }
    63     }
    64 
    65     
    66 //    if (_fpr) {
    67     free(identity->fpr);
    68 
    69     identity->fpr = strdup(_fpr);
    70     if (identity->fpr == NULL) {
    71         free_stringlist(keylist);
    72         return PEP_OUT_OF_MEMORY;
    73     }
    74 //    }
    75     free_stringlist(keylist);
    76     return PEP_STATUS_OK;
    77 }
    78 
    79 PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags);
    80 
    81 DYNAMIC_API PEP_STATUS update_identity(
    82         PEP_SESSION session, pEp_identity * identity
    83     )
    84 {
    85     pEp_identity *stored_identity = NULL;
    86     pEp_identity *temp_id = NULL;
    87     PEP_STATUS status;
    88 
    89     assert(session);
    90     assert(identity);
    91     assert(!EMPTYSTR(identity->address));
    92 
    93     if (!(session && identity && !EMPTYSTR(identity->address)))
    94         return ERROR(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 except if 
   183                        is unknown or is expired (but key not expired anymore) */
   184                     temp_id->comm_type = stored_identity->comm_type;
   185                     if (temp_id->comm_type == PEP_ct_unknown ||
   186                         temp_id->comm_type == PEP_ct_key_expired) {
   187                         temp_id->comm_type = _comm_type_key;
   188                     }
   189                 }
   190             }
   191         }
   192         else {
   193             status = elect_pubkey(session, temp_id);
   194             if (status != PEP_STATUS_OK){
   195                 goto exit_free;
   196             } else {
   197                 _did_elect_new_key = 1;
   198             }
   199         }
   200         
   201         /* ok, from here on out, use temp_id */
   202         
   203         
   204         /* At this point, we either have a non-blacklisted fpr we can work */
   205         /* with, or we've got nada.                                        */
   206 
   207         if (EMPTYSTR(temp_id->fpr)) {
   208             /* nada : set comm_type accordingly */
   209             temp_id->comm_type = PEP_ct_key_not_found;
   210         }
   211         
   212         if (EMPTYSTR(temp_id->username)) {
   213             free(temp_id->username);
   214             temp_id->username = strdup(stored_identity->username);
   215             assert(temp_id->username);
   216             if (temp_id->username == NULL){
   217                 status = PEP_OUT_OF_MEMORY;
   218                 goto exit_free;
   219             }
   220         }
   221 
   222         if (temp_id->lang[0] == 0) {
   223             temp_id->lang[0] = stored_identity->lang[0];
   224             temp_id->lang[1] = stored_identity->lang[1];
   225             temp_id->lang[2] = 0;
   226         }
   227 
   228         temp_id->flags = stored_identity->flags;
   229     }
   230     else /* stored_identity == NULL */ {
   231         temp_id->flags = 0;
   232 
   233         /* We elect a pubkey */
   234         status = elect_pubkey(session, temp_id);
   235         if (status != PEP_STATUS_OK)
   236             goto exit_free;
   237         
   238         /* Work with the elected key */
   239         if (!EMPTYSTR(temp_id->fpr)) {
   240             
   241             PEP_comm_type _comm_type_key = temp_id->comm_type;
   242             
   243             _did_elect_new_key = 1;
   244 
   245             // We don't want to lose a previous trust entry!!!
   246             status = get_trust(session, temp_id);
   247 
   248             bool has_trust_status = (status == PEP_STATUS_OK);
   249 
   250             if (!has_trust_status)
   251                 temp_id->comm_type = _comm_type_key;
   252         }
   253     }
   254 
   255     if (temp_id->fpr == NULL) {
   256         temp_id->fpr = strdup("");
   257         if (temp_id->fpr == NULL) {
   258             status = PEP_OUT_OF_MEMORY;
   259             goto exit_free;
   260         }
   261     }
   262     
   263     
   264     status = PEP_STATUS_OK;
   265 
   266     if (temp_id->comm_type != PEP_ct_unknown && !EMPTYSTR(temp_id->user_id)) {
   267 
   268         if (EMPTYSTR(temp_id->username)) { // mitigate
   269             free(temp_id->username);
   270             temp_id->username = strdup("anonymous");
   271             assert(temp_id->username);
   272             if (temp_id->username == NULL){
   273                 status = PEP_OUT_OF_MEMORY;
   274                 goto exit_free;
   275             }
   276         }
   277 
   278         // Identity doesn't get stored if call was just about checking existing
   279         // user by address (i.e. no user id given but already stored)
   280         if (!(_no_user_id && stored_identity) || _did_elect_new_key)
   281         {
   282             status = set_identity(session, temp_id);
   283             assert(status == PEP_STATUS_OK);
   284             if (status != PEP_STATUS_OK) {
   285                 goto exit_free;
   286             }
   287         }
   288     }
   289 
   290     if (temp_id->comm_type != PEP_ct_compromized &&
   291             temp_id->comm_type < PEP_ct_strong_but_unconfirmed)
   292         if (session->examine_identity)
   293             session->examine_identity(temp_id, session->examine_management);
   294     
   295     /* ok, we got to the end. So we can assign the output identity */
   296     free(identity->address);
   297     identity->address = strdup(temp_id->address);
   298     free(identity->fpr);
   299     identity->fpr = strdup(temp_id->fpr);
   300     free(identity->user_id);
   301     identity->user_id = strdup(temp_id->user_id);
   302     free(identity->username);
   303     identity->username = strdup(temp_id->username ? temp_id->username : "anonymous");
   304     identity->comm_type = temp_id->comm_type;
   305     identity->lang[0] = temp_id->lang[0];
   306     identity->lang[1] = temp_id->lang[1];
   307     identity->lang[2] = 0;
   308     identity->me = temp_id->me;
   309     identity->flags = temp_id->flags;
   310 
   311 exit_free :
   312     free_identity(stored_identity);
   313     free_identity(temp_id);
   314     
   315     return ERROR(status);
   316 }
   317 
   318 PEP_STATUS elect_ownkey(
   319         PEP_SESSION session, pEp_identity * identity
   320     )
   321 {
   322     PEP_STATUS status;
   323     stringlist_t *keylist = NULL;
   324 
   325     free(identity->fpr);
   326     identity->fpr = NULL;
   327 
   328     status = find_private_keys(session, identity->address, &keylist);
   329     assert(status != PEP_OUT_OF_MEMORY);
   330     if (status == PEP_OUT_OF_MEMORY)
   331         return PEP_OUT_OF_MEMORY;
   332     
   333     if (keylist != NULL && keylist->value != NULL)
   334     {
   335         char *_fpr = NULL;
   336         identity->comm_type = PEP_ct_unknown;
   337 
   338         stringlist_t *_keylist;
   339         for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
   340             bool is_own = false;
   341             
   342             status = own_key_is_listed(session, _keylist->value, &is_own);
   343             assert(status == PEP_STATUS_OK);
   344             if (status != PEP_STATUS_OK) {
   345                 free_stringlist(keylist);
   346                 return status;
   347             }
   348             
   349             if (is_own)
   350             {
   351                 PEP_comm_type _comm_type_key;
   352                 
   353                 status = get_key_rating(session, _keylist->value, &_comm_type_key);
   354                 assert(status != PEP_OUT_OF_MEMORY);
   355                 if (status == PEP_OUT_OF_MEMORY) {
   356                     free_stringlist(keylist);
   357                     return PEP_OUT_OF_MEMORY;
   358                 }
   359                 
   360                 if (_comm_type_key != PEP_ct_compromized &&
   361                     _comm_type_key != PEP_ct_unknown)
   362                 {
   363                     if (identity->comm_type == PEP_ct_unknown ||
   364                         _comm_type_key > identity->comm_type)
   365                     {
   366                         identity->comm_type = _comm_type_key;
   367                         _fpr = _keylist->value;
   368                     }
   369                 }
   370             }
   371         }
   372         
   373         if (_fpr)
   374         {
   375             identity->fpr = strdup(_fpr);
   376             assert(identity->fpr);
   377             if (identity->fpr == NULL)
   378             {
   379                 free_stringlist(keylist);
   380                 return PEP_OUT_OF_MEMORY;
   381             }
   382         }
   383         free_stringlist(keylist);
   384     }
   385     return PEP_STATUS_OK;
   386 }
   387 
   388 PEP_STATUS _has_usable_priv_key(PEP_SESSION session, char* fpr,
   389                                 bool* is_usable) {
   390     
   391     bool dont_use_fpr = true;
   392     
   393     PEP_STATUS status = blacklist_is_listed(session, fpr, &dont_use_fpr);
   394     if (status == PEP_STATUS_OK && !dont_use_fpr) {
   395         // Make sure there is a *private* key associated with this fpr
   396         bool has_private = false;
   397         status = contains_priv_key(session, fpr, &has_private);
   398 
   399         if (status == PEP_STATUS_OK)
   400             dont_use_fpr = !has_private;
   401     }
   402     
   403     *is_usable = !dont_use_fpr;
   404     
   405     return ERROR(status);
   406 }
   407 
   408 PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags)
   409 {
   410     pEp_identity *stored_identity = NULL;
   411     PEP_STATUS status;
   412 
   413     assert(session);
   414     assert(identity);
   415     assert(!EMPTYSTR(identity->address));
   416 
   417     assert(EMPTYSTR(identity->user_id) ||
   418            strcmp(identity->user_id, PEP_OWN_USERID) == 0);
   419 
   420     if (!(session && identity && !EMPTYSTR(identity->address) &&
   421             (EMPTYSTR(identity->user_id) ||
   422             strcmp(identity->user_id, PEP_OWN_USERID) == 0)))
   423         return ERROR(PEP_ILLEGAL_VALUE);
   424 
   425     identity->comm_type = PEP_ct_pEp;
   426     identity->me = true;
   427     if(ignore_flags)
   428         identity->flags = 0;
   429     
   430     if (EMPTYSTR(identity->user_id))
   431     {
   432         free(identity->user_id);
   433         identity->user_id = strdup(PEP_OWN_USERID);
   434         assert(identity->user_id);
   435         if (identity->user_id == NULL)
   436             return PEP_OUT_OF_MEMORY;
   437     }
   438 
   439     if (EMPTYSTR(identity->username))
   440     {
   441         free(identity->username);
   442         identity->username = strdup("anonymous");
   443         assert(identity->username);
   444         if (identity->username == NULL)
   445             return PEP_OUT_OF_MEMORY;
   446     }
   447 
   448     DEBUG_LOG("myself", "debug", identity->address);
   449  
   450     status = get_identity(session,
   451                           identity->address,
   452                           identity->user_id,
   453                           &stored_identity);
   454     
   455     assert(status != PEP_OUT_OF_MEMORY);
   456     if (status == PEP_OUT_OF_MEMORY)
   457         return PEP_OUT_OF_MEMORY;
   458 
   459     bool dont_use_stored_fpr = true;
   460     bool dont_use_input_fpr = true;
   461         
   462     if (stored_identity)
   463     {
   464         if (EMPTYSTR(identity->fpr)) {
   465             
   466             bool has_private = false;
   467             
   468             status = _has_usable_priv_key(session, stored_identity->fpr, &has_private); 
   469             
   470             // N.B. has_private is never true if the returned status is not PEP_STATUS_OK
   471             if (has_private) {
   472                 identity->fpr = strdup(stored_identity->fpr);
   473                 assert(identity->fpr);
   474                 if (identity->fpr == NULL)
   475                 {
   476                     return PEP_OUT_OF_MEMORY;
   477                 }
   478                 dont_use_stored_fpr = false;
   479             }
   480         }
   481         
   482         identity->flags = (identity->flags & 255) | stored_identity->flags;
   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 ERROR(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         if (status != PEP_STATUS_OK) 
   542         {
   543             status = elect_ownkey(session, identity);
   544             assert(status == PEP_STATUS_OK);
   545             if (status != PEP_STATUS_OK) {
   546                 return ERROR(status);
   547             }
   548         } 
   549         else if (status != PEP_STATUS_OK) 
   550         {
   551             return ERROR(status);
   552         }
   553     }
   554    
   555     bool new_key_generated = false;
   556 
   557     if (EMPTYSTR(identity->fpr) || revoked)
   558     {
   559         if(!do_keygen){
   560             return ERROR(PEP_GET_KEY_FAILED);
   561         }
   562 
   563         if(revoked)
   564         {
   565             r_fpr = identity->fpr;
   566             identity->fpr = NULL;
   567         }
   568         
   569         DEBUG_LOG("generating key pair", "debug", identity->address);
   570         status = generate_keypair(session, identity);
   571         assert(status != PEP_OUT_OF_MEMORY);
   572         if (status != PEP_STATUS_OK) {
   573             char buf[11];
   574             snprintf(buf, 11, "%d", status);
   575             DEBUG_LOG("generating key pair failed", "debug", buf);
   576             if(revoked && r_fpr)
   577                 free(r_fpr);
   578             return ERROR(status);
   579         }
   580 
   581         new_key_generated = true;
   582         
   583         if(revoked)
   584         {
   585             status = set_revoked(session, r_fpr,
   586                                  identity->fpr, time(NULL));
   587             free(r_fpr);
   588             if (status != PEP_STATUS_OK) {
   589                 return ERROR(status);
   590             }
   591         }
   592     }
   593     else
   594     {
   595         bool expired;
   596         status = key_expired(session, identity->fpr, 
   597                              time(NULL) + (7*24*3600), // In a week
   598                              &expired);
   599 
   600         assert(status == PEP_STATUS_OK);
   601         if (status != PEP_STATUS_OK) {
   602             return ERROR(status);
   603         }
   604 
   605         if (status == PEP_STATUS_OK && expired) {
   606             timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
   607             renew_key(session, identity->fpr, ts);
   608             free_timestamp(ts);
   609         }
   610     }
   611 
   612     if (!identity->username)
   613         identity->username = strdup("");
   614     
   615     status = set_identity(session, identity);
   616     assert(status == PEP_STATUS_OK);
   617     if (status != PEP_STATUS_OK) {
   618         return status;
   619     }
   620 
   621     if(new_key_generated)
   622     {
   623         // if a state machine for keysync is in place, inject notify
   624         status = inject_DeviceState_event(session, KeyGen, NULL, NULL);
   625         if (status == PEP_OUT_OF_MEMORY){
   626             return PEP_OUT_OF_MEMORY;
   627         }
   628     }
   629 
   630     return ERROR(PEP_STATUS_OK);
   631 }
   632 
   633 DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
   634 {
   635     return ERROR(_myself(session, identity, true, false));
   636 }
   637 
   638 DYNAMIC_API PEP_STATUS register_examine_function(
   639         PEP_SESSION session, 
   640         examine_identity_t examine_identity,
   641         void *management
   642     )
   643 {
   644     assert(session);
   645     if (!session)
   646         return PEP_ILLEGAL_VALUE;
   647 
   648     session->examine_management = management;
   649     session->examine_identity = examine_identity;
   650 
   651     return PEP_STATUS_OK;
   652 }
   653 
   654 DYNAMIC_API PEP_STATUS do_keymanagement(
   655         retrieve_next_identity_t retrieve_next_identity,
   656         void *management
   657     )
   658 {
   659     PEP_SESSION session;
   660     pEp_identity *identity;
   661     PEP_STATUS status;
   662 
   663     assert(retrieve_next_identity);
   664     assert(management);
   665 
   666     if (!retrieve_next_identity || !management)
   667         return PEP_ILLEGAL_VALUE;
   668 
   669     status = init(&session);
   670     assert(status == PEP_STATUS_OK);
   671     if (status != PEP_STATUS_OK)
   672         return status;
   673 
   674     log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
   675 
   676     while ((identity = retrieve_next_identity(management))) 
   677     {
   678         assert(identity->address);
   679         if(identity->address)
   680         {
   681             DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
   682 
   683             if (identity->me) {
   684                 status = myself(session, identity);
   685             } else {
   686                 status = recv_key(session, identity->address);
   687             }
   688 
   689             assert(status != PEP_OUT_OF_MEMORY);
   690             if(status == PEP_OUT_OF_MEMORY)
   691                 return PEP_OUT_OF_MEMORY;
   692         }
   693         free_identity(identity);
   694     }
   695 
   696     log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
   697 
   698     release(session);
   699     return PEP_STATUS_OK;
   700 }
   701 
   702 DYNAMIC_API PEP_STATUS key_mistrusted(
   703         PEP_SESSION session,
   704         pEp_identity *ident
   705     )
   706 {
   707     PEP_STATUS status = PEP_STATUS_OK;
   708 
   709     assert(session);
   710     assert(ident);
   711     assert(!EMPTYSTR(ident->fpr));
   712 
   713     if (!(session && ident && ident->fpr))
   714         return PEP_ILLEGAL_VALUE;
   715 
   716     if (ident->me)
   717     {
   718         revoke_key(session, ident->fpr, NULL);
   719         myself(session, ident);
   720     }
   721     else
   722     {
   723         status = mark_as_compromized(session, ident->fpr);
   724     }
   725 
   726     return status;
   727 }
   728 
   729 DYNAMIC_API PEP_STATUS key_reset_trust(
   730         PEP_SESSION session,
   731         pEp_identity *ident
   732     )
   733 {
   734     PEP_STATUS status = PEP_STATUS_OK;
   735 
   736     assert(session);
   737     assert(ident);
   738     assert(!ident->me);
   739     assert(!EMPTYSTR(ident->fpr));
   740     assert(!EMPTYSTR(ident->address));
   741     assert(!EMPTYSTR(ident->user_id));
   742 
   743     if (!(session && ident && !ident->me && ident->fpr && ident->address &&
   744             ident->user_id))
   745         return PEP_ILLEGAL_VALUE;
   746 
   747     status = update_identity(session, ident);
   748     if (status != PEP_STATUS_OK)
   749         return status;
   750 
   751     if (ident->comm_type == PEP_ct_mistrusted)
   752         ident->comm_type = PEP_ct_unknown;
   753     else
   754         ident->comm_type &= ~PEP_ct_confirmed;
   755 
   756     status = set_identity(session, ident);
   757     if (status != PEP_STATUS_OK)
   758         return status;
   759 
   760     if (ident->comm_type == PEP_ct_unknown)
   761         status = update_identity(session, ident);
   762     return status;
   763 }
   764 
   765 DYNAMIC_API PEP_STATUS trust_personal_key(
   766         PEP_SESSION session,
   767         pEp_identity *ident
   768     )
   769 {
   770     PEP_STATUS status = PEP_STATUS_OK;
   771 
   772     assert(session);
   773     assert(ident);
   774     assert(!EMPTYSTR(ident->address));
   775     assert(!EMPTYSTR(ident->user_id));
   776     assert(!EMPTYSTR(ident->fpr));
   777 //    assert(!ident->me);
   778 
   779     if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
   780             EMPTYSTR(ident->fpr)) // || ident->me)
   781         return PEP_ILLEGAL_VALUE;
   782 
   783     status = update_identity(session, ident);
   784     if (status != PEP_STATUS_OK)
   785         return status;
   786 
   787     if (ident->comm_type > PEP_ct_strong_but_unconfirmed) {
   788         ident->comm_type |= PEP_ct_confirmed;
   789         status = set_identity(session, ident);
   790     }
   791     else {
   792         // MISSING: S/MIME has to be handled depending on trusted CAs
   793         status = PEP_CANNOT_SET_TRUST;
   794     }
   795 
   796     return status;
   797 }
   798 
   799 DYNAMIC_API PEP_STATUS own_key_is_listed(
   800         PEP_SESSION session,
   801         const char *fpr,
   802         bool *listed
   803     )
   804 {
   805     PEP_STATUS status = PEP_STATUS_OK;
   806     int count;
   807     
   808     assert(session && fpr && fpr[0] && listed);
   809     
   810     if (!(session && fpr && fpr[0] && listed))
   811         return PEP_ILLEGAL_VALUE;
   812     
   813     *listed = false;
   814     
   815     sqlite3_reset(session->own_key_is_listed);
   816     sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1, SQLITE_STATIC);
   817     
   818     int result;
   819     
   820     result = sqlite3_step(session->own_key_is_listed);
   821     switch (result) {
   822         case SQLITE_ROW:
   823             count = sqlite3_column_int(session->own_key_is_listed, 0);
   824             *listed = count > 0;
   825             status = PEP_STATUS_OK;
   826             break;
   827             
   828         default:
   829             status = PEP_UNKNOWN_ERROR;
   830     }
   831     
   832     sqlite3_reset(session->own_key_is_listed);
   833     return status;
   834 }
   835 
   836 PEP_STATUS _own_identities_retrieve(
   837         PEP_SESSION session,
   838         identity_list **own_identities,
   839         identity_flags_t excluded_flags
   840       )
   841 {
   842     PEP_STATUS status = PEP_STATUS_OK;
   843     
   844     assert(session && own_identities);
   845     if (!(session && own_identities))
   846         return PEP_ILLEGAL_VALUE;
   847     
   848     *own_identities = NULL;
   849     identity_list *_own_identities = new_identity_list(NULL);
   850     if (_own_identities == NULL)
   851         goto enomem;
   852     
   853     sqlite3_reset(session->own_identities_retrieve);
   854     
   855     int result;
   856     // address, fpr, username, user_id, comm_type, lang, flags
   857     const char *address = NULL;
   858     const char *fpr = NULL;
   859     const char *username = NULL;
   860     const char *user_id = NULL;
   861     PEP_comm_type comm_type = PEP_ct_unknown;
   862     const char *lang = NULL;
   863     unsigned int flags = 0;
   864     
   865     identity_list *_bl = _own_identities;
   866     do {
   867         sqlite3_bind_int(session->own_identities_retrieve, 1, excluded_flags);
   868         result = sqlite3_step(session->own_identities_retrieve);
   869         switch (result) {
   870             case SQLITE_ROW:
   871                 address = (const char *)
   872                     sqlite3_column_text(session->own_identities_retrieve, 0);
   873                 fpr = (const char *)
   874                     sqlite3_column_text(session->own_identities_retrieve, 1);
   875                 user_id = PEP_OWN_USERID;
   876                 username = (const char *)
   877                     sqlite3_column_text(session->own_identities_retrieve, 2);
   878                 comm_type = PEP_ct_pEp;
   879                 lang = (const char *)
   880                     sqlite3_column_text(session->own_identities_retrieve, 3);
   881                 flags = (unsigned int)
   882                     sqlite3_column_int(session->own_identities_retrieve, 4);
   883 
   884                 pEp_identity *ident = new_identity(address, fpr, user_id, username);
   885                 if (!ident)
   886                     goto enomem;
   887                 ident->comm_type = comm_type;
   888                 if (lang && lang[0]) {
   889                     ident->lang[0] = lang[0];
   890                     ident->lang[1] = lang[1];
   891                     ident->lang[2] = 0;
   892                 }
   893                 ident->me = true;
   894                 ident->flags = flags;
   895 
   896                 _bl = identity_list_add(_bl, ident);
   897                 if (_bl == NULL) {
   898                     free_identity(ident);
   899                     goto enomem;
   900                 }
   901                 
   902                 break;
   903                 
   904             case SQLITE_DONE:
   905                 break;
   906                 
   907             default:
   908                 status = PEP_UNKNOWN_ERROR;
   909                 result = SQLITE_DONE;
   910         }
   911     } while (result != SQLITE_DONE);
   912     
   913     sqlite3_reset(session->own_identities_retrieve);
   914     if (status == PEP_STATUS_OK)
   915         *own_identities = _own_identities;
   916     else
   917         free_identity_list(_own_identities);
   918     
   919     goto the_end;
   920     
   921 enomem:
   922     free_identity_list(_own_identities);
   923     status = PEP_OUT_OF_MEMORY;
   924     
   925 the_end:
   926     return status;
   927 }
   928 
   929 DYNAMIC_API PEP_STATUS own_identities_retrieve(
   930         PEP_SESSION session,
   931         identity_list **own_identities
   932       )
   933 {
   934     return _own_identities_retrieve(session, own_identities, 0);
   935 }
   936 
   937 PEP_STATUS _own_keys_retrieve(
   938         PEP_SESSION session,
   939         stringlist_t **keylist,
   940         identity_flags_t excluded_flags
   941       )
   942 {
   943     PEP_STATUS status = PEP_STATUS_OK;
   944     
   945     assert(session && keylist);
   946     if (!(session && keylist))
   947         return PEP_ILLEGAL_VALUE;
   948     
   949     *keylist = NULL;
   950     stringlist_t *_keylist = NULL;
   951     
   952     sqlite3_reset(session->own_keys_retrieve);
   953     
   954     int result;
   955     char *fpr = NULL;
   956     
   957     stringlist_t *_bl = _keylist;
   958     do {
   959         sqlite3_bind_int(session->own_keys_retrieve, 1, excluded_flags);
   960         result = sqlite3_step(session->own_keys_retrieve);
   961         switch (result) {
   962             case SQLITE_ROW:
   963                 fpr = strdup((const char *) sqlite3_column_text(session->own_keys_retrieve, 0));
   964                 if(fpr == NULL)
   965                     goto enomem;
   966 
   967                 _bl = stringlist_add(_bl, fpr);
   968                 if (_bl == NULL) {
   969                     free(fpr);
   970                     goto enomem;
   971                 }
   972                 if (_keylist == NULL)
   973                     _keylist = _bl;
   974                 
   975                 break;
   976                 
   977             case SQLITE_DONE:
   978                 break;
   979                 
   980             default:
   981                 status = PEP_UNKNOWN_ERROR;
   982                 result = SQLITE_DONE;
   983         }
   984     } while (result != SQLITE_DONE);
   985     
   986     sqlite3_reset(session->own_keys_retrieve);
   987     if (status == PEP_STATUS_OK)
   988         *keylist = _keylist;
   989     else
   990         free_stringlist(_keylist);
   991     
   992     goto the_end;
   993     
   994 enomem:
   995     free_stringlist(_keylist);
   996     status = PEP_OUT_OF_MEMORY;
   997     
   998 the_end:
   999     return status;
  1000 }
  1001 
  1002 DYNAMIC_API PEP_STATUS own_keys_retrieve(PEP_SESSION session, stringlist_t **keylist)
  1003 {
  1004     return _own_keys_retrieve(session, keylist, 0);
  1005 }
  1006 
  1007 // FIXME: should it be be used when sync receive old keys ? (ENGINE-145)
  1008 DYNAMIC_API PEP_STATUS set_own_key(
  1009        PEP_SESSION session,
  1010        const char *address,
  1011        const char *fpr
  1012     )
  1013 {
  1014     PEP_STATUS status = PEP_STATUS_OK;
  1015     
  1016     assert(session &&
  1017            address &&
  1018            fpr && fpr[0]
  1019           );
  1020     
  1021     if (!(session &&
  1022           address &&
  1023           fpr && fpr[0]
  1024          ))
  1025         return PEP_ILLEGAL_VALUE;
  1026     
  1027     sqlite3_reset(session->set_own_key);
  1028     sqlite3_bind_text(session->set_own_key, 1, address, -1, SQLITE_STATIC);
  1029     sqlite3_bind_text(session->set_own_key, 2, fpr, -1, SQLITE_STATIC);
  1030 
  1031     int result;
  1032     
  1033     result = sqlite3_step(session->set_own_key);
  1034     switch (result) {
  1035         case SQLITE_DONE:
  1036             status = PEP_STATUS_OK;
  1037             break;
  1038             
  1039         default:
  1040             status = PEP_UNKNOWN_ERROR;
  1041     }
  1042     
  1043     sqlite3_reset(session->set_own_key);
  1044     return status;
  1045 }
  1046 
  1047 PEP_STATUS contains_priv_key(PEP_SESSION session, const char *fpr,
  1048                              bool *has_private) {
  1049 
  1050     assert(session);
  1051     assert(fpr);
  1052     assert(has_private);
  1053     
  1054     if (!(session && fpr && has_private))
  1055         return PEP_ILLEGAL_VALUE;
  1056 
  1057     return session->cryptotech[PEP_crypt_OpenPGP].contains_priv_key(session, fpr, has_private);
  1058 }