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