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