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