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