src/pEpEngine.c
author Edouard Tisserant <edouard@pep-project.org>
Mon, 03 Oct 2016 19:08:15 +0200
branchkeysync
changeset 1236 991afc1aa2a1
parent 1235 cfc9214a60a5
child 1237 18438a7595d7
permissions -rw-r--r--
sync : attach_sync_session
     1 #include "pEp_internal.h"
     2 #include "dynamic_api.h"
     3 #include "cryptotech.h"
     4 #include "transport.h"
     5 #include "blacklist.h"
     6 #include "sync_fsm.h"
     7 
     8 static int init_count = -1;
     9 
    10 static int user_version(void *_version, int count, char **text, char **name)
    11 {
    12     assert(_version);
    13     assert(count == 1);
    14     assert(text && text[0]);
    15     if (!(_version && count == 1 && text && text[0]))
    16         return -1;
    17 
    18     int *version = (int *) _version;
    19     *version = atoi(text[0]);
    20     return 0;
    21 }
    22 
    23 DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
    24 {
    25     PEP_STATUS status = PEP_STATUS_OK;
    26     int int_result;
    27     static const char *sql_log;
    28     static const char *sql_trustword;
    29     static const char *sql_get_identity;
    30     static const char *sql_set_person;
    31     static const char *sql_set_device_group;
    32     static const char *sql_get_device_group;
    33     static const char *sql_set_pgp_keypair;
    34     static const char *sql_set_identity;
    35     static const char *sql_set_identity_flags;
    36     static const char *sql_set_trust;
    37     static const char *sql_get_trust;
    38     static const char *sql_least_trust;
    39     static const char *sql_mark_as_compromized;
    40     static const char *sql_crashdump;
    41     static const char *sql_languagelist;
    42     static const char *sql_i18n_token;
    43 
    44     // blacklist
    45     static const char *sql_blacklist_add;
    46     static const char *sql_blacklist_delete;
    47     static const char *sql_blacklist_is_listed;
    48     static const char *sql_blacklist_retrieve;
    49 
    50     // Own keys
    51     static const char *sql_own_key_is_listed;
    52     static const char *sql_own_identities_retrieve;
    53 
    54     // Sequence
    55     static const char *sql_sequence_value1;
    56     static const char *sql_sequence_value2;
    57     static const char *sql_sequence_value3;
    58 
    59     // Revocation tracking
    60     static const char *sql_set_revoked;
    61     static const char *sql_get_revoked;
    62     
    63     bool in_first = false;
    64 
    65     assert(sqlite3_threadsafe());
    66     if (!sqlite3_threadsafe())
    67         return PEP_INIT_SQLITE3_WITHOUT_MUTEX;
    68 
    69     // a little race condition - but still a race condition
    70     // mitigated by calling caveat (see documentation)
    71 
    72     ++init_count;
    73     if (init_count == 0)
    74         in_first = true;
    75 
    76     assert(session);
    77     if (session == NULL)
    78         return PEP_ILLEGAL_VALUE;
    79 
    80     *session = NULL;
    81 
    82     pEpSession *_session = calloc(1, sizeof(pEpSession));
    83     assert(_session);
    84     if (_session == NULL)
    85         goto enomem;
    86 
    87     _session->version = PEP_ENGINE_VERSION;
    88 
    89     assert(LOCAL_DB);
    90     if (LOCAL_DB == NULL) {
    91         status = PEP_INIT_CANNOT_OPEN_DB;
    92         goto pep_error;
    93     }
    94 
    95     int_result = sqlite3_open_v2(
    96             LOCAL_DB,
    97             &_session->db,
    98             SQLITE_OPEN_READWRITE
    99                 | SQLITE_OPEN_CREATE
   100                 | SQLITE_OPEN_FULLMUTEX
   101                 | SQLITE_OPEN_PRIVATECACHE,
   102             NULL 
   103         );
   104 
   105     if (int_result != SQLITE_OK) {
   106         status = PEP_INIT_CANNOT_OPEN_DB;
   107         goto pep_error;
   108     }
   109 
   110     sqlite3_busy_timeout(_session->db, BUSY_WAIT_TIME);
   111 
   112     assert(SYSTEM_DB);
   113     if (SYSTEM_DB == NULL) {
   114         status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
   115         goto pep_error;
   116     }
   117 
   118     int_result = sqlite3_open_v2(
   119             SYSTEM_DB, &_session->system_db,
   120             SQLITE_OPEN_READONLY
   121                 | SQLITE_OPEN_FULLMUTEX
   122                 | SQLITE_OPEN_SHAREDCACHE,
   123             NULL
   124         );
   125 
   126     if (int_result != SQLITE_OK) {
   127         status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
   128         goto pep_error;
   129     }
   130 
   131     sqlite3_busy_timeout(_session->system_db, 1000);
   132 
   133 // increment this when patching DDL
   134 #define _DDL_USER_VERSION "3"
   135 
   136     if (in_first) {
   137 
   138         int_result = sqlite3_exec(
   139             _session->db,
   140                 "create table if not exists version_info (\n"
   141                 "   id integer primary key,\n"
   142                 "   timestamp integer default (datetime('now')),\n"
   143                 "   version text,\n"
   144                 "   comment text\n"
   145                 ");\n",
   146                 NULL,
   147                 NULL,
   148                 NULL
   149         );
   150         int_result = sqlite3_exec(
   151             _session->db,
   152                 "PRAGMA application_id = 0x23423423;\n"
   153                 "create table if not exists log (\n"
   154                 "   timestamp integer default (datetime('now')),\n"
   155                 "   title text not null,\n"
   156                 "   entity text not null,\n"
   157                 "   description text,\n"
   158                 "   comment text\n"
   159                 ");\n"
   160                 "create index if not exists log_timestamp on log (\n"
   161                 "   timestamp\n"
   162                 ");\n"
   163                 "create table if not exists pgp_keypair (\n"
   164                 "   fpr text primary key,\n"
   165                 "   public_id text unique,\n"
   166                 "   private_id text,\n"
   167                 "   created integer,\n"
   168                 "   expires integer,\n"
   169                 "   comment text,\n"
   170                 "   flags integer default 0\n"
   171                 ");\n"
   172                 "create index if not exists pgp_keypair_expires on pgp_keypair (\n"
   173                 "   expires\n"
   174                 ");\n"
   175                 "create table if not exists person (\n"
   176                 "   id text primary key,\n"
   177                 "   username text not null,\n"
   178                 "   main_key_id text\n"
   179                 "       references pgp_keypair (fpr)\n"
   180                 "       on delete set null,\n"
   181                 "   lang text,\n"
   182                 "   comment text,\n"
   183                 "   device_group text\n"
   184                 ");\n"
   185                 "create table if not exists identity (\n"
   186                 "   address text,\n"
   187                 "   user_id text\n"
   188                 "       references person (id)\n"
   189                 "       on delete cascade,\n"
   190                 "   main_key_id text\n"
   191                 "       references pgp_keypair (fpr)\n"
   192                 "       on delete set null,\n"
   193                 "   comment text,\n"
   194                 "   flags integer default 0,"
   195                 "   primary key (address, user_id)\n"
   196                 ");\n"
   197                 "create table if not exists trust (\n"
   198                 "   user_id text not null\n"
   199                 "       references person (id)\n"
   200                 "       on delete cascade,\n"
   201                 "   pgp_keypair_fpr text not null\n"
   202                 "       references pgp_keypair (fpr)\n"
   203                 "       on delete cascade,\n"
   204                 "   comm_type integer not null,\n"
   205                 "   comment text,\n"
   206                 "   primary key (user_id, pgp_keypair_fpr)\n"
   207                 ");\n"
   208                 // blacklist
   209                 "create table if not exists blacklist_keys (\n"
   210                 "   fpr text primary key\n"
   211                 ");\n"
   212                 // sequences
   213                 "create table if not exists sequences(\n"
   214                 "   name text primary key,\n"
   215                 "   value integer default 0,\n"
   216                 "   own integer default 0\n"
   217                 ");\n"
   218                 "create table if not exists revoked_keys (\n"
   219                 "   revoked_fpr text primary key,\n"
   220                 "   replacement_fpr text not null\n"
   221                 "       references pgp_keypair (fpr)\n"
   222                 "       on delete cascade,\n"
   223                 "   revocation_date integer\n"
   224                 ");\n"
   225                 ,
   226             NULL,
   227             NULL,
   228             NULL
   229         );
   230         assert(int_result == SQLITE_OK);
   231 
   232         int version;
   233         int_result = sqlite3_exec(
   234             _session->db,
   235             "pragma user_version;",
   236             user_version,
   237             &version,
   238             NULL
   239         );
   240         assert(int_result == SQLITE_OK);
   241 
   242         if (version < 1) {
   243             int_result = sqlite3_exec(
   244                 _session->db,
   245                 "alter table identity\n"
   246                 "   add column flags integer default 0;\n",
   247                 NULL,
   248                 NULL,
   249                 NULL
   250             );
   251         }
   252 
   253         if (version < 2) {
   254             int_result = sqlite3_exec(
   255                 _session->db,
   256                 "alter table pgp_keypair\n"
   257                 "   add column flags integer default 0;\n"
   258                 "alter table person\n"
   259                 "   add column device_group text;\n",
   260                 NULL,
   261                 NULL,
   262                 NULL
   263             );
   264         }
   265 
   266         if (version < 3) {
   267             int_result = sqlite3_exec(
   268                 _session->db,
   269                 "alter table sequences\n"
   270                 "   add column own integer default 0;\n",
   271                 NULL,
   272                 NULL,
   273                 NULL
   274             );
   275         }
   276 
   277         if (version < atoi(_DDL_USER_VERSION)) {
   278             int_result = sqlite3_exec(
   279                 _session->db,
   280                 "pragma user_version = "_DDL_USER_VERSION";\n"
   281                 "insert or replace into version_info (id, version)"
   282                     "values (1, '" PEP_ENGINE_VERSION "');",
   283                 NULL,
   284                 NULL,
   285                 NULL
   286             );
   287             assert(int_result == SQLITE_OK);
   288         }
   289 
   290         if (version <= atoi(_DDL_USER_VERSION)) {
   291             int_result = sqlite3_exec(
   292                 _session->db,
   293                 "pragma user_version = "_DDL_USER_VERSION";\n"
   294                 "insert or replace into version_info (id, version)"
   295                     "values (1, '" PEP_ENGINE_VERSION "');",
   296                 NULL,
   297                 NULL,
   298                 NULL
   299             );
   300             assert(int_result == SQLITE_OK);
   301         }
   302 
   303         sql_log = "insert into log (title, entity, description, comment)"
   304                   "values (?1, ?2, ?3, ?4);";
   305 
   306         sql_get_identity =  "select fpr, username, comm_type, lang,"
   307                             "   identity.flags | pgp_keypair.flags"
   308                             "   from identity"
   309                             "   join person on id = identity.user_id"
   310                             "   join pgp_keypair on fpr = identity.main_key_id"
   311                             "   join trust on id = trust.user_id"
   312                             "       and pgp_keypair_fpr = identity.main_key_id"
   313                             "   where address = ?1 and identity.user_id = ?2;";
   314 
   315         sql_trustword = "select id, word from wordlist where lang = lower(?1) "
   316                        "and id = ?2 ;";
   317 
   318         // Set person, but if already exist, only update.
   319         // if main_key_id already set, don't touch.
   320         sql_set_person = "insert or replace into person (id, username, lang, main_key_id)"
   321                          "  values (?1, ?2, ?3,"
   322                          "    (select coalesce((select main_key_id from person "
   323                          "      where id = ?1), upper(replace(?4,' ',''))))) ;";
   324 
   325         sql_set_device_group = "update person set device_group = ?1 "
   326                                "where user_id = '" PEP_OWN_USERID "';";
   327 
   328         sql_get_device_group = "select device_group from person "
   329                                "where user_id = '" PEP_OWN_USERID "';";
   330 
   331         sql_set_pgp_keypair = "insert or replace into pgp_keypair (fpr) "
   332                               "values (upper(replace(?1,' ',''))) ;";
   333 
   334         sql_set_identity = "insert or replace into identity (address, main_key_id, "
   335                            "user_id, flags) values (?1, upper(replace(?2,' ','')),"
   336                            "?3, ?4 & 255) ;";
   337 
   338         sql_set_identity_flags = "update identity set flags = ?1 & 255 "
   339                                  "where address = ?2 and user_id = ?3 ;";
   340 
   341         sql_set_trust = "insert or replace into trust (user_id, pgp_keypair_fpr, comm_type) "
   342                         "values (?1, upper(replace(?2,' ','')), ?3) ;";
   343 
   344         sql_get_trust = "select comm_type from trust where user_id = ?1 "
   345                         "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;";
   346 
   347         sql_least_trust = "select min(comm_type) from trust where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   348 
   349         sql_mark_as_compromized = "update trust not indexed set comm_type = 15"
   350                                   " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   351 
   352         sql_crashdump = "select timestamp, title, entity, description, comment"
   353                         " from log order by timestamp desc limit ?1 ;";
   354 
   355         sql_languagelist = "select i18n_language.lang, name, phrase from i18n_language join i18n_token using (lang) where i18n_token.id = 1000;" ;
   356 
   357         sql_i18n_token = "select phrase from i18n_token where lang = lower(?1) and id = ?2 ;";
   358 
   359         // blacklist
   360 
   361         sql_blacklist_add = "insert or replace into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;"
   362                             "delete from identity where main_key_id = upper(replace(?1,' ','')) ;"
   363                             "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;";
   364 
   365         sql_blacklist_delete = "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   366 
   367         sql_blacklist_is_listed = "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   368 
   369         sql_blacklist_retrieve = "select * from blacklist_keys ;";
   370         
   371         // Own keys
   372         
   373         sql_own_key_is_listed =
   374                                 "select count(*) from ("
   375                                 " select main_key_id from person "
   376                                 "   where main_key_id = upper(replace(?1,' ',''))"
   377                                 "    and id = '" PEP_OWN_USERID "' "
   378                                 " union "
   379                                 "  select main_key_id from identity "
   380                                 "   where main_key_id = upper(replace(?1,' ',''))"
   381                                 "    and user_id = '" PEP_OWN_USERID "' );";
   382 
   383         sql_own_identities_retrieve =  "select address, fpr, username, "
   384                             "   lang, identity.flags | pgp_keypair.flags"
   385                             "   from identity"
   386                             "   join person on id = identity.user_id"
   387                             "   join pgp_keypair on fpr = identity.main_key_id"
   388                             "   join trust on id = trust.user_id"
   389                             "       and pgp_keypair_fpr = identity.main_key_id"
   390                             "   where identity.user_id = '" PEP_OWN_USERID "';";
   391         
   392         sql_sequence_value1 = "insert or replace into sequences (name, value, own) "
   393                               "values (?1, "
   394                               "(select coalesce((select value + 1 from sequences "
   395                               "where name = ?1), 1 )), ?2) ; ";
   396         sql_sequence_value2 = "select value, own from sequences where name = ?1 ;";
   397         sql_sequence_value3 = "update sequences set value = ?2, own = ?3 where name = ?1 ;";
   398         
   399         sql_set_revoked =     "insert or replace into revoked_keys ("
   400                               "    revoked_fpr, replacement_fpr, revocation_date) "
   401                               "values (upper(replace(?1,' ','')),"
   402                               "        upper(replace(?2,' ','')),"
   403                               "        ?3) ;";
   404         
   405         sql_get_revoked =     "select revoked_fpr, revocation_date from revoked_keys"
   406                               "    where replacement_fpr = upper(replace(?1,' ','')) ;";
   407     }
   408 
   409     int_result = sqlite3_prepare_v2(_session->db, sql_log,
   410             (int)strlen(sql_log), &_session->log, NULL);
   411     assert(int_result == SQLITE_OK);
   412 
   413     int_result = sqlite3_prepare_v2(_session->system_db, sql_trustword,
   414             (int)strlen(sql_trustword), &_session->trustword, NULL);
   415     assert(int_result == SQLITE_OK);
   416 
   417     int_result = sqlite3_prepare_v2(_session->db, sql_get_identity,
   418             (int)strlen(sql_get_identity), &_session->get_identity, NULL);
   419     assert(int_result == SQLITE_OK);
   420 
   421     int_result = sqlite3_prepare_v2(_session->db, sql_set_person,
   422             (int)strlen(sql_set_person), &_session->set_person, NULL);
   423     assert(int_result == SQLITE_OK);
   424 
   425     int_result = sqlite3_prepare_v2(_session->db, sql_set_device_group,
   426             (int)strlen(sql_set_device_group), &_session->set_device_group, NULL);
   427     assert(int_result == SQLITE_OK);
   428 
   429     int_result = sqlite3_prepare_v2(_session->db, sql_get_device_group,
   430             (int)strlen(sql_get_device_group), &_session->get_device_group, NULL);
   431     assert(int_result == SQLITE_OK);
   432 
   433     int_result = sqlite3_prepare_v2(_session->db, sql_set_pgp_keypair,
   434             (int)strlen(sql_set_pgp_keypair), &_session->set_pgp_keypair,
   435             NULL);
   436     assert(int_result == SQLITE_OK);
   437 
   438     int_result = sqlite3_prepare_v2(_session->db, sql_set_identity,
   439             (int)strlen(sql_set_identity), &_session->set_identity, NULL);
   440     assert(int_result == SQLITE_OK);
   441 
   442     int_result = sqlite3_prepare_v2(_session->db, sql_set_identity_flags,
   443             (int)strlen(sql_set_identity_flags), &_session->set_identity_flags,
   444             NULL);
   445     assert(int_result == SQLITE_OK);
   446 
   447     int_result = sqlite3_prepare_v2(_session->db, sql_set_trust,
   448             (int)strlen(sql_set_trust), &_session->set_trust, NULL);
   449     assert(int_result == SQLITE_OK);
   450 
   451     int_result = sqlite3_prepare_v2(_session->db, sql_get_trust,
   452             (int)strlen(sql_get_trust), &_session->get_trust, NULL);
   453     assert(int_result == SQLITE_OK);
   454 
   455     int_result = sqlite3_prepare_v2(_session->db, sql_least_trust,
   456             (int)strlen(sql_least_trust), &_session->least_trust, NULL);
   457     assert(int_result == SQLITE_OK);
   458 
   459     int_result = sqlite3_prepare_v2(_session->db, sql_mark_as_compromized,
   460             (int)strlen(sql_mark_as_compromized), &_session->mark_compromized,
   461             NULL);
   462     assert(int_result == SQLITE_OK);
   463 
   464     int_result = sqlite3_prepare_v2(_session->db, sql_crashdump,
   465             (int)strlen(sql_crashdump), &_session->crashdump, NULL);
   466     assert(int_result == SQLITE_OK);
   467 
   468     int_result = sqlite3_prepare_v2(_session->system_db, sql_languagelist,
   469             (int)strlen(sql_languagelist), &_session->languagelist, NULL);
   470     assert(int_result == SQLITE_OK);
   471 
   472     int_result = sqlite3_prepare_v2(_session->system_db, sql_i18n_token,
   473             (int)strlen(sql_i18n_token), &_session->i18n_token, NULL);
   474     assert(int_result == SQLITE_OK);
   475 
   476     // blacklist
   477 
   478     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_add,
   479             (int)strlen(sql_blacklist_add), &_session->blacklist_add, NULL);
   480     assert(int_result == SQLITE_OK);
   481 
   482     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_delete,
   483             (int)strlen(sql_blacklist_delete), &_session->blacklist_delete,
   484             NULL);
   485     assert(int_result == SQLITE_OK);
   486 
   487     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_is_listed,
   488             (int)strlen(sql_blacklist_is_listed),
   489             &_session->blacklist_is_listed, NULL);
   490     assert(int_result == SQLITE_OK);
   491 
   492     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_retrieve,
   493             (int)strlen(sql_blacklist_retrieve), &_session->blacklist_retrieve,
   494             NULL);
   495     assert(int_result == SQLITE_OK);
   496 
   497     // Own keys
   498     
   499     int_result = sqlite3_prepare_v2(_session->db, sql_own_key_is_listed,
   500             (int)strlen(sql_own_key_is_listed), &_session->own_key_is_listed,
   501             NULL);
   502     assert(int_result == SQLITE_OK);
   503     
   504     int_result = sqlite3_prepare_v2(_session->db, sql_own_identities_retrieve,
   505             (int)strlen(sql_own_identities_retrieve),
   506             &_session->own_identities_retrieve, NULL);
   507     assert(int_result == SQLITE_OK);
   508  
   509     // Sequence
   510 
   511     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value1,
   512             (int)strlen(sql_sequence_value1), &_session->sequence_value1,
   513             NULL);
   514     assert(int_result == SQLITE_OK);
   515 
   516     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value2,
   517             (int)strlen(sql_sequence_value2), &_session->sequence_value2,
   518             NULL);
   519     assert(int_result == SQLITE_OK);
   520 
   521     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value3,
   522             (int)strlen(sql_sequence_value3), &_session->sequence_value3,
   523             NULL);
   524     assert(int_result == SQLITE_OK);
   525 
   526     // Revocation tracking
   527     
   528     int_result = sqlite3_prepare_v2(_session->db, sql_set_revoked,
   529             (int)strlen(sql_set_revoked), &_session->set_revoked, NULL);
   530     assert(int_result == SQLITE_OK);
   531     
   532     int_result = sqlite3_prepare_v2(_session->db, sql_get_revoked,
   533             (int)strlen(sql_get_revoked), &_session->get_revoked, NULL);
   534     assert(int_result == SQLITE_OK);
   535     
   536     status = init_cryptotech(_session, in_first);
   537     if (status != PEP_STATUS_OK)
   538         goto pep_error;
   539 
   540     status = init_transport_system(_session, in_first);
   541     if (status != PEP_STATUS_OK)
   542         goto pep_error;
   543 
   544     status = log_event(_session, "init", "pEp " PEP_ENGINE_VERSION, NULL, NULL);
   545     if (status != PEP_STATUS_OK)
   546         goto pep_error;
   547 
   548     // runtime config
   549 
   550 #ifdef ANDROID
   551     _session->use_only_own_private_keys = true;
   552 #elif TARGET_OS_IPHONE
   553     _session->use_only_own_private_keys = true;
   554 #else
   555     _session->use_only_own_private_keys = false;
   556 #endif
   557 
   558     *session = _session;
   559     return PEP_STATUS_OK;
   560 
   561 enomem:
   562     status = PEP_OUT_OF_MEMORY;
   563 
   564 pep_error:
   565     release(_session);
   566     return status;
   567 }
   568 
   569 DYNAMIC_API void release(PEP_SESSION session)
   570 {
   571     bool out_last = false;
   572 
   573     assert(init_count >= 0);
   574     assert(session);
   575 
   576     if (!((init_count >= 0) && session))
   577         return;
   578 
   579     // a small race condition but still a race condition
   580     // mitigated by calling caveat (see documentation)
   581 
   582     if (init_count == 0)
   583         out_last = true;
   584     --init_count;
   585 
   586     if (session) {
   587         if (session->sync_state != DeviceState_state_NONE)
   588             unregister_sync_callbacks(session);
   589 
   590         if (session->db) {
   591             if (session->log)
   592                 sqlite3_finalize(session->log);
   593             if (session->trustword)
   594                 sqlite3_finalize(session->trustword);
   595             if (session->get_identity)
   596                 sqlite3_finalize(session->get_identity);
   597             if (session->set_person)
   598                 sqlite3_finalize(session->set_person);
   599             if (session->set_device_group)
   600                 sqlite3_finalize(session->set_device_group);
   601             if (session->get_device_group)
   602                 sqlite3_finalize(session->get_device_group);
   603             if (session->set_pgp_keypair)
   604                 sqlite3_finalize(session->set_pgp_keypair);
   605             if (session->set_identity)
   606                 sqlite3_finalize(session->set_identity);
   607             if (session->set_identity_flags)
   608                 sqlite3_finalize(session->set_identity_flags);
   609             if (session->set_trust)
   610                 sqlite3_finalize(session->set_trust);
   611             if (session->get_trust)
   612                 sqlite3_finalize(session->get_trust);
   613             if (session->least_trust)
   614                 sqlite3_finalize(session->least_trust);
   615             if (session->mark_compromized)
   616                 sqlite3_finalize(session->mark_compromized);
   617             if (session->crashdump)
   618                 sqlite3_finalize(session->crashdump);
   619             if (session->languagelist)
   620                 sqlite3_finalize(session->languagelist);
   621             if (session->i18n_token)
   622                 sqlite3_finalize(session->i18n_token);
   623             if (session->blacklist_add)
   624                 sqlite3_finalize(session->blacklist_add);
   625             if (session->blacklist_delete)
   626                 sqlite3_finalize(session->blacklist_delete);
   627             if (session->blacklist_is_listed)
   628                 sqlite3_finalize(session->blacklist_is_listed);
   629             if (session->blacklist_retrieve)
   630                 sqlite3_finalize(session->blacklist_retrieve);
   631             if (session->own_key_is_listed)
   632                 sqlite3_finalize(session->own_key_is_listed);
   633             if (session->own_identities_retrieve)
   634                 sqlite3_finalize(session->own_identities_retrieve);
   635             if (session->sequence_value1)
   636                 sqlite3_finalize(session->sequence_value1);
   637             if (session->sequence_value2)
   638                 sqlite3_finalize(session->sequence_value2);
   639             if (session->sequence_value3)
   640                 sqlite3_finalize(session->sequence_value3);
   641             if (session->set_revoked)
   642                 sqlite3_finalize(session->set_revoked);
   643             if (session->get_revoked)
   644                 sqlite3_finalize(session->get_revoked);
   645 
   646             if (session->db)
   647                 sqlite3_close_v2(session->db);
   648             if (session->system_db)
   649                 sqlite3_close_v2(session->system_db);
   650         }
   651 
   652         release_transport_system(session, out_last);
   653         release_cryptotech(session, out_last);
   654 
   655         free(session);
   656     }
   657 }
   658 
   659 DYNAMIC_API void config_passive_mode(PEP_SESSION session, bool enable)
   660 {
   661     assert(session);
   662     session->passive_mode = enable;
   663 }
   664 
   665 DYNAMIC_API void config_unencrypted_subject(PEP_SESSION session, bool enable)
   666 {
   667     assert(session);
   668     session->unencrypted_subject = enable;
   669 }
   670 
   671 DYNAMIC_API void config_use_only_own_private_keys(PEP_SESSION session,
   672         bool enable)
   673 {
   674     assert(session);
   675     session->use_only_own_private_keys = enable;
   676 }
   677 
   678 DYNAMIC_API void config_keep_sync_msg(PEP_SESSION session, bool enable)
   679 {
   680     assert(session);
   681     session->keep_sync_msg = enable;
   682 }
   683 
   684 DYNAMIC_API PEP_STATUS log_event(
   685         PEP_SESSION session,
   686         const char *title,
   687         const char *entity,
   688         const char *description,
   689         const char *comment
   690     )
   691 {
   692     PEP_STATUS status = PEP_STATUS_OK;
   693     int result;
   694 
   695     assert(session);
   696     assert(title);
   697     assert(entity);
   698 
   699     if (!(session && title && entity))
   700         return PEP_ILLEGAL_VALUE;
   701 
   702     sqlite3_reset(session->log);
   703     sqlite3_bind_text(session->log, 1, title, -1, SQLITE_STATIC);
   704     sqlite3_bind_text(session->log, 2, entity, -1, SQLITE_STATIC);
   705     if (description)
   706         sqlite3_bind_text(session->log, 3, description, -1, SQLITE_STATIC);
   707     else
   708         sqlite3_bind_null(session->log, 3);
   709     if (comment)
   710         sqlite3_bind_text(session->log, 4, comment, -1, SQLITE_STATIC);
   711     else
   712         sqlite3_bind_null(session->log, 4);
   713     do {
   714         result = sqlite3_step(session->log);
   715         assert(result == SQLITE_DONE || result == SQLITE_BUSY);
   716         if (result != SQLITE_DONE && result != SQLITE_BUSY)
   717             status = PEP_UNKNOWN_ERROR;
   718     } while (result == SQLITE_BUSY);
   719     sqlite3_reset(session->log);
   720 
   721     return status;
   722 }
   723 
   724 DYNAMIC_API PEP_STATUS trustword(
   725             PEP_SESSION session, uint16_t value, const char *lang,
   726             char **word, size_t *wsize
   727         )
   728 {
   729     PEP_STATUS status = PEP_STATUS_OK;
   730 
   731     assert(session);
   732     assert(word);
   733     assert(wsize);
   734 
   735     if (!(session && word && wsize))
   736         return PEP_ILLEGAL_VALUE;
   737 
   738     *word = NULL;
   739     *wsize = 0;
   740 
   741     if (lang == NULL)
   742         lang = "en";
   743 
   744     assert((lang[0] >= 'A' && lang[0] <= 'Z')
   745             || (lang[0] >= 'a' && lang[0] <= 'z'));
   746     assert((lang[1] >= 'A' && lang[1] <= 'Z')
   747             || (lang[1] >= 'a' && lang[1] <= 'z'));
   748     assert(lang[2] == 0);
   749 
   750     sqlite3_reset(session->trustword);
   751     sqlite3_bind_text(session->trustword, 1, lang, -1, SQLITE_STATIC);
   752     sqlite3_bind_int(session->trustword, 2, value);
   753 
   754     const int result = sqlite3_step(session->trustword);
   755     if (result == SQLITE_ROW) {
   756         *word = strdup((const char *) sqlite3_column_text(session->trustword,
   757                     1));
   758         if (*word)
   759             *wsize = sqlite3_column_bytes(session->trustword, 1);
   760         else
   761             status = PEP_OUT_OF_MEMORY;
   762     } else
   763         status = PEP_TRUSTWORD_NOT_FOUND;
   764 
   765     sqlite3_reset(session->trustword);
   766     return status;
   767 }
   768 
   769 DYNAMIC_API PEP_STATUS trustwords(
   770         PEP_SESSION session, const char *fingerprint, const char *lang,
   771         char **words, size_t *wsize, int max_words
   772     )
   773 {
   774     const char *source = fingerprint;
   775     char *buffer;
   776     char *dest;
   777     size_t fsize;
   778 
   779     assert(session);
   780     assert(fingerprint);
   781     assert(words);
   782     assert(wsize);
   783     assert(max_words >= 0);
   784 
   785     if (!(session && fingerprint && words && wsize && max_words >= 0))
   786         return PEP_ILLEGAL_VALUE;
   787 
   788     *words = NULL;
   789     *wsize = 0;
   790 
   791     buffer = calloc(1, MAX_TRUSTWORDS_SPACE);
   792     assert(buffer);
   793     if (buffer == NULL)
   794         return PEP_OUT_OF_MEMORY;
   795     dest = buffer;
   796 
   797     fsize = strlen(fingerprint);
   798 
   799     if (!lang || !lang[0])
   800         lang = "en";
   801 
   802     assert((lang[0] >= 'A' && lang[0] <= 'Z')
   803             || (lang[0] >= 'a' && lang[0] <= 'z'));
   804     assert((lang[1] >= 'A' && lang[1] <= 'Z')
   805             || (lang[1] >= 'a' && lang[1] <= 'z'));
   806     assert(lang[2] == 0);
   807 
   808     int n_words = 0;
   809     while (source < fingerprint + fsize) {
   810         PEP_STATUS _status;
   811         uint16_t value;
   812         char *word;
   813         size_t _wsize;
   814         int j;
   815 
   816         for (value=0, j=0; j < 4 && source < fingerprint + fsize; ) {
   817             if (*source >= 'a' && *source <= 'f')
   818                 value += (*source - 'a' + 10) << (3 - j++) * 4;
   819             else if (*source >= 'A' && *source <= 'F')
   820                 value += (*source - 'A' + 10) << (3 - j++) * 4;
   821             else if (*source >= '0' && *source <= '9')
   822                 value += (*source - '0') << (3 - j++) * 4;
   823             
   824             source++;
   825         }
   826 
   827         _status = trustword(session, value, lang, &word, &_wsize);
   828         if (_status == PEP_OUT_OF_MEMORY) {
   829             free(buffer);
   830             return PEP_OUT_OF_MEMORY;
   831         }
   832         if (word == NULL) {
   833             free(buffer);
   834             return PEP_TRUSTWORD_NOT_FOUND;
   835         }
   836 
   837         if (dest + _wsize < buffer + MAX_TRUSTWORDS_SPACE - 1) {
   838             strncpy(dest, word, _wsize);
   839             free(word);
   840             dest += _wsize;
   841         }
   842         else {
   843             free(word);
   844             break; // buffer full
   845         }
   846 
   847         if (source < fingerprint + fsize
   848                 && dest + _wsize < buffer + MAX_TRUSTWORDS_SPACE - 1)
   849             *dest++ = ' ';
   850 
   851         ++n_words;
   852         if (max_words && n_words >= max_words)
   853             break;
   854     }
   855 
   856     *words = buffer;
   857     *wsize = dest - buffer;
   858     return PEP_STATUS_OK;
   859 }
   860 
   861 pEp_identity *new_identity(
   862         const char *address, const char *fpr, const char *user_id,
   863         const char *username
   864     )
   865 {
   866     pEp_identity *result = calloc(1, sizeof(pEp_identity));
   867     assert(result);
   868     if (result) {
   869         if (address) {
   870             result->address = strdup(address);
   871             assert(result->address);
   872             if (result->address == NULL) {
   873                 free(result);
   874                 return NULL;
   875             }
   876         }
   877         if (fpr) {
   878             result->fpr = strdup(fpr);
   879             assert(result->fpr);
   880             if (result->fpr == NULL) {
   881                 free_identity(result);
   882                 return NULL;
   883             }
   884         }
   885         if (user_id) {
   886             result->user_id = strdup(user_id);
   887             assert(result->user_id);
   888             if (result->user_id == NULL) {
   889                 free_identity(result);
   890                 return NULL;
   891             }
   892         }
   893         if (username) {
   894             result->username = strdup(username);
   895             assert(result->username);
   896             if (result->username == NULL) {
   897                 free_identity(result);
   898                 return NULL;
   899             }
   900         }
   901     }
   902     return result;
   903 }
   904 
   905 pEp_identity *identity_dup(const pEp_identity *src)
   906 {
   907     assert(src);
   908 
   909     pEp_identity *dup = new_identity(src->address, src->fpr, src->user_id,
   910             src->username);
   911     assert(dup);
   912     if (dup == NULL)
   913         return NULL;
   914     
   915     dup->comm_type = src->comm_type;
   916     dup->lang[0] = src->lang[0];
   917     dup->lang[1] = src->lang[1];
   918     dup->lang[2] = 0;
   919     dup->me = src->me;
   920     dup->flags = src->flags;
   921 
   922     return dup;
   923 }
   924 
   925 void free_identity(pEp_identity *identity)
   926 {
   927     if (identity) {
   928         free(identity->address);
   929         free(identity->fpr);
   930         free(identity->user_id);
   931         free(identity->username);
   932         free(identity);
   933     }
   934 }
   935 
   936 DYNAMIC_API PEP_STATUS get_identity(
   937         PEP_SESSION session,
   938         const char *address,
   939         const char *user_id,
   940         pEp_identity **identity
   941     )
   942 {
   943     PEP_STATUS status = PEP_STATUS_OK;
   944     static pEp_identity *_identity;
   945 
   946     assert(session);
   947     assert(address);
   948     assert(address[0]);
   949     assert(identity);
   950 
   951     if (!(session && address && address[0] && identity))
   952         return PEP_ILLEGAL_VALUE;
   953 
   954     *identity = NULL;
   955 
   956     sqlite3_reset(session->get_identity);
   957     sqlite3_bind_text(session->get_identity, 1, address, -1, SQLITE_STATIC);
   958     sqlite3_bind_text(session->get_identity, 2, user_id, -1, SQLITE_STATIC);
   959 
   960     const int result = sqlite3_step(session->get_identity);
   961     switch (result) {
   962     case SQLITE_ROW:
   963         _identity = new_identity(
   964                 address,
   965                 (const char *) sqlite3_column_text(session->get_identity, 0),
   966                 user_id,
   967                 (const char *) sqlite3_column_text(session->get_identity, 1)
   968                 );
   969         assert(_identity);
   970         if (_identity == NULL)
   971             return PEP_OUT_OF_MEMORY;
   972 
   973         _identity->comm_type = (PEP_comm_type)
   974             sqlite3_column_int(session->get_identity, 2);
   975         const char* const _lang = (const char *)
   976             sqlite3_column_text(session->get_identity, 3);
   977         if (_lang && _lang[0]) {
   978             assert(_lang[0] >= 'a' && _lang[0] <= 'z');
   979             assert(_lang[1] >= 'a' && _lang[1] <= 'z');
   980             assert(_lang[2] == 0);
   981             _identity->lang[0] = _lang[0];
   982             _identity->lang[1] = _lang[1];
   983             _identity->lang[2] = 0;
   984         }
   985         _identity->flags = (unsigned int)
   986             sqlite3_column_int(session->get_identity, 4);
   987         *identity = _identity;
   988         break;
   989     default:
   990         status = PEP_CANNOT_FIND_IDENTITY;
   991         *identity = NULL;
   992     }
   993 
   994     sqlite3_reset(session->get_identity);
   995     return status;
   996 }
   997 
   998 DYNAMIC_API PEP_STATUS set_identity(
   999         PEP_SESSION session, const pEp_identity *identity
  1000     )
  1001 {
  1002     int result;
  1003 
  1004     assert(session);
  1005     assert(identity);
  1006     assert(identity->address);
  1007     assert(identity->fpr);
  1008     assert(identity->user_id);
  1009     assert(identity->username);
  1010 
  1011     if (!(session && identity && identity->address && identity->fpr &&
  1012                 identity->user_id && identity->username))
  1013         return PEP_ILLEGAL_VALUE;
  1014 
  1015     bool listed;
  1016     PEP_STATUS status = blacklist_is_listed(session, identity->fpr, &listed);
  1017     assert(status == PEP_STATUS_OK);
  1018     if (status != PEP_STATUS_OK)
  1019         return status;
  1020 
  1021     if (listed)
  1022         return PEP_KEY_BLACKLISTED;
  1023 
  1024     sqlite3_exec(session->db, "BEGIN ;", NULL, NULL, NULL);
  1025 
  1026     if (identity->lang[0]) {
  1027         assert(identity->lang[0] >= 'a' && identity->lang[0] <= 'z');
  1028         assert(identity->lang[1] >= 'a' && identity->lang[1] <= 'z');
  1029         assert(identity->lang[2] == 0);
  1030     }
  1031 
  1032     sqlite3_reset(session->set_person);
  1033     sqlite3_bind_text(session->set_person, 1, identity->user_id, -1,
  1034             SQLITE_STATIC);
  1035     sqlite3_bind_text(session->set_person, 2, identity->username, -1,
  1036             SQLITE_STATIC);
  1037     if (identity->lang[0])
  1038         sqlite3_bind_text(session->set_person, 3, identity->lang, 2,
  1039                 SQLITE_STATIC);
  1040     else
  1041         sqlite3_bind_null(session->set_person, 3);
  1042     sqlite3_bind_text(session->set_person, 4, identity->fpr, -1,
  1043                       SQLITE_STATIC);
  1044     result = sqlite3_step(session->set_person);
  1045     sqlite3_reset(session->set_person);
  1046     if (result != SQLITE_DONE) {
  1047         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  1048         return PEP_CANNOT_SET_PERSON;
  1049     }
  1050 
  1051     sqlite3_reset(session->set_pgp_keypair);
  1052     sqlite3_bind_text(session->set_pgp_keypair, 1, identity->fpr, -1,
  1053             SQLITE_STATIC);
  1054     result = sqlite3_step(session->set_pgp_keypair);
  1055     sqlite3_reset(session->set_pgp_keypair);
  1056     if (result != SQLITE_DONE) {
  1057         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  1058         return PEP_CANNOT_SET_PGP_KEYPAIR;
  1059     }
  1060 
  1061     sqlite3_reset(session->set_identity);
  1062     sqlite3_bind_text(session->set_identity, 1, identity->address, -1,
  1063             SQLITE_STATIC);
  1064     sqlite3_bind_text(session->set_identity, 2, identity->fpr, -1,
  1065             SQLITE_STATIC);
  1066     sqlite3_bind_text(session->set_identity, 3, identity->user_id, -1,
  1067             SQLITE_STATIC);
  1068     sqlite3_bind_int(session->set_identity, 4, identity->flags);
  1069     result = sqlite3_step(session->set_identity);
  1070     sqlite3_reset(session->set_identity);
  1071     if (result != SQLITE_DONE) {
  1072         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  1073         return PEP_CANNOT_SET_IDENTITY;
  1074     }
  1075 
  1076     sqlite3_reset(session->set_trust);
  1077     sqlite3_bind_text(session->set_trust, 1, identity->user_id, -1,
  1078             SQLITE_STATIC);
  1079     sqlite3_bind_text(session->set_trust, 2, identity->fpr, -1,
  1080             SQLITE_STATIC);
  1081     sqlite3_bind_int(session->set_trust, 3, identity->comm_type);
  1082     result = sqlite3_step(session->set_trust);
  1083     sqlite3_reset(session->set_trust);
  1084     if (result != SQLITE_DONE) {
  1085         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  1086         return PEP_CANNOT_SET_TRUST;
  1087     }
  1088 
  1089     result = sqlite3_exec(session->db, "COMMIT ;", NULL, NULL, NULL);
  1090     if (result == SQLITE_OK)
  1091         return PEP_STATUS_OK;
  1092     else
  1093         return PEP_COMMIT_FAILED;
  1094 }
  1095 
  1096 DYNAMIC_API PEP_STATUS set_device_group(
  1097         PEP_SESSION session,
  1098         const char *group_name
  1099     )
  1100 {
  1101     int result;
  1102 
  1103     assert(session);
  1104     assert(group_name);
  1105 
  1106     if (!(session && group_name))
  1107         return PEP_ILLEGAL_VALUE;
  1108 
  1109     sqlite3_reset(session->set_device_group);
  1110     sqlite3_bind_text(session->set_device_group, 1, group_name, -1,
  1111             SQLITE_STATIC);
  1112     result = sqlite3_step(session->set_device_group);
  1113     sqlite3_reset(session->set_device_group);
  1114     if (result != SQLITE_DONE)
  1115         return PEP_CANNOT_SET_PERSON;
  1116 
  1117     return PEP_STATUS_OK;
  1118 }
  1119 
  1120 DYNAMIC_API PEP_STATUS get_device_group(PEP_SESSION session, char **group_name)
  1121 {
  1122     PEP_STATUS status = PEP_STATUS_OK;
  1123     int result;
  1124 
  1125     assert(session);
  1126     assert(group_name);
  1127 
  1128     if (!(session && group_name))
  1129         return PEP_ILLEGAL_VALUE;
  1130 
  1131     sqlite3_reset(session->get_device_group);
  1132 
  1133     result = sqlite3_step(session->get_device_group);
  1134     switch (result) {
  1135     case SQLITE_ROW: {
  1136         *group_name = strdup(
  1137             (const char *) sqlite3_column_text(session->get_device_group, 0));
  1138             if(*group_name == NULL)
  1139                 status = PEP_OUT_OF_MEMORY;
  1140         break;
  1141     }
  1142  
  1143     default:
  1144         status = PEP_RECORD_NOT_FOUND;
  1145     }
  1146 
  1147     sqlite3_reset(session->get_device_group);
  1148     return status;
  1149 }
  1150 
  1151 DYNAMIC_API PEP_STATUS set_identity_flags(
  1152         PEP_SESSION session,
  1153         pEp_identity *identity,
  1154         unsigned int flags
  1155     )
  1156 {
  1157     int result;
  1158 
  1159     assert(session);
  1160     assert(identity);
  1161     assert(identity->address);
  1162     assert(identity->user_id);
  1163 
  1164     if (!(session && identity && identity->address && identity->user_id))
  1165         return PEP_ILLEGAL_VALUE;
  1166 
  1167     sqlite3_reset(session->set_identity_flags);
  1168     sqlite3_bind_int(session->set_identity_flags, 1, flags);
  1169     sqlite3_bind_text(session->set_identity_flags, 2, identity->address, -1,
  1170             SQLITE_STATIC);
  1171     sqlite3_bind_text(session->set_identity_flags, 3, identity->user_id, -1,
  1172             SQLITE_STATIC);
  1173     result = sqlite3_step(session->set_identity_flags);
  1174     sqlite3_reset(session->set_identity_flags);
  1175     if (result != SQLITE_DONE)
  1176         return PEP_CANNOT_SET_IDENTITY;
  1177 
  1178     identity->flags = flags;
  1179     return PEP_STATUS_OK;
  1180 }
  1181 
  1182 DYNAMIC_API PEP_STATUS mark_as_compromized(
  1183         PEP_SESSION session,
  1184         const char *fpr
  1185     )
  1186 {
  1187     int result;
  1188 
  1189     assert(session);
  1190     assert(fpr && fpr[0]);
  1191 
  1192     if (!(session && fpr && fpr[0]))
  1193         return PEP_ILLEGAL_VALUE;
  1194 
  1195     sqlite3_reset(session->mark_compromized);
  1196     sqlite3_bind_text(session->mark_compromized, 1, fpr, -1,
  1197             SQLITE_STATIC);
  1198     result = sqlite3_step(session->mark_compromized);
  1199     sqlite3_reset(session->mark_compromized);
  1200 
  1201     if (result != SQLITE_DONE)
  1202         return PEP_CANNOT_SET_TRUST;
  1203 
  1204     return PEP_STATUS_OK;
  1205 }
  1206 
  1207 void pEp_free(void *p)
  1208 {
  1209     free(p);
  1210 }
  1211 
  1212 DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity)
  1213 {
  1214     PEP_STATUS status = PEP_STATUS_OK;
  1215     int result;
  1216 
  1217     assert(session);
  1218     assert(identity);
  1219     assert(identity->user_id);
  1220     assert(identity->user_id[0]);
  1221     assert(identity->fpr);
  1222     assert(identity->fpr[0]);
  1223 
  1224     if (!(session && identity && identity->user_id && identity->user_id[0] &&
  1225                 identity->fpr && identity->fpr[0]))
  1226         return PEP_ILLEGAL_VALUE;
  1227 
  1228     identity->comm_type = PEP_ct_unknown;
  1229 
  1230     sqlite3_reset(session->get_trust);
  1231     sqlite3_bind_text(session->get_trust, 1, identity->user_id, -1,
  1232             SQLITE_STATIC);
  1233     sqlite3_bind_text(session->get_trust, 2, identity->fpr, -1, SQLITE_STATIC);
  1234 
  1235     result = sqlite3_step(session->get_trust);
  1236     switch (result) {
  1237     case SQLITE_ROW: {
  1238         int comm_type = (PEP_comm_type) sqlite3_column_int(session->get_trust,
  1239                 0);
  1240         identity->comm_type = comm_type;
  1241         break;
  1242     }
  1243  
  1244     default:
  1245         status = PEP_CANNOT_FIND_IDENTITY;
  1246     }
  1247 
  1248     sqlite3_reset(session->get_trust);
  1249     return status;
  1250 }
  1251 
  1252 DYNAMIC_API PEP_STATUS least_trust(
  1253         PEP_SESSION session,
  1254         const char *fpr,
  1255         PEP_comm_type *comm_type
  1256     )
  1257 {
  1258     PEP_STATUS status = PEP_STATUS_OK;
  1259     int result;
  1260 
  1261     assert(session);
  1262     assert(fpr);
  1263     assert(comm_type);
  1264 
  1265     if (!(session && fpr && comm_type))
  1266         return PEP_ILLEGAL_VALUE;
  1267 
  1268     *comm_type = PEP_ct_unknown;
  1269 
  1270     sqlite3_reset(session->least_trust);
  1271     sqlite3_bind_text(session->least_trust, 1, fpr, -1, SQLITE_STATIC);
  1272 
  1273     result = sqlite3_step(session->least_trust);
  1274     switch (result) {
  1275         case SQLITE_ROW: {
  1276             int _comm_type = sqlite3_column_int(session->least_trust, 0);
  1277             *comm_type = (PEP_comm_type) _comm_type;
  1278             break;
  1279         }
  1280         default:
  1281             status = PEP_CANNOT_FIND_IDENTITY;
  1282     }
  1283 
  1284     sqlite3_reset(session->least_trust);
  1285     return status;
  1286 }
  1287 
  1288 DYNAMIC_API PEP_STATUS decrypt_and_verify(
  1289     PEP_SESSION session, const char *ctext, size_t csize,
  1290     char **ptext, size_t *psize, stringlist_t **keylist
  1291     )
  1292 {
  1293     assert(session);
  1294     assert(ctext);
  1295     assert(csize);
  1296     assert(ptext);
  1297     assert(psize);
  1298     assert(keylist);
  1299 
  1300     if (!(session && ctext && csize && ptext && psize && keylist))
  1301         return PEP_ILLEGAL_VALUE;
  1302 
  1303     return session->cryptotech[PEP_crypt_OpenPGP].decrypt_and_verify(
  1304             session, ctext, csize, ptext, psize, keylist);
  1305 }
  1306 
  1307 DYNAMIC_API PEP_STATUS encrypt_and_sign(
  1308     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1309     size_t psize, char **ctext, size_t *csize
  1310     )
  1311 {
  1312     assert(session);
  1313     assert(keylist);
  1314     assert(ptext);
  1315     assert(psize);
  1316     assert(ctext);
  1317     assert(csize);
  1318 
  1319     if (!(session && keylist && ptext && psize && ctext && csize))
  1320         return PEP_ILLEGAL_VALUE;
  1321 
  1322     return session->cryptotech[PEP_crypt_OpenPGP].encrypt_and_sign(session,
  1323             keylist, ptext, psize, ctext, csize);
  1324 }
  1325 
  1326 DYNAMIC_API PEP_STATUS verify_text(
  1327     PEP_SESSION session, const char *text, size_t size,
  1328     const char *signature, size_t sig_size, stringlist_t **keylist
  1329     )
  1330 {
  1331     assert(session);
  1332     assert(text);
  1333     assert(size);
  1334     assert(signature);
  1335     assert(sig_size);
  1336     assert(keylist);
  1337 
  1338     if (!(session && text && size && signature && sig_size && keylist))
  1339         return PEP_ILLEGAL_VALUE;
  1340 
  1341     return session->cryptotech[PEP_crypt_OpenPGP].verify_text(session, text,
  1342             size, signature, sig_size, keylist);
  1343 }
  1344 
  1345 DYNAMIC_API PEP_STATUS delete_keypair(PEP_SESSION session, const char *fpr)
  1346 {
  1347     assert(session);
  1348     assert(fpr);
  1349 
  1350     if (!(session && fpr))
  1351         return PEP_ILLEGAL_VALUE;
  1352 
  1353     return session->cryptotech[PEP_crypt_OpenPGP].delete_keypair(session, fpr);
  1354 }
  1355 
  1356 DYNAMIC_API PEP_STATUS export_key(
  1357         PEP_SESSION session, const char *fpr, char **key_data, size_t *size
  1358     )
  1359 {
  1360     assert(session);
  1361     assert(fpr);
  1362     assert(key_data);
  1363     assert(size);
  1364 
  1365     if (!(session && fpr && key_data && size))
  1366         return PEP_ILLEGAL_VALUE;
  1367 
  1368     return session->cryptotech[PEP_crypt_OpenPGP].export_key(session, fpr,
  1369             key_data, size, false);
  1370 }
  1371 
  1372 DYNAMIC_API PEP_STATUS export_secrect_key(
  1373         PEP_SESSION session, const char *fpr, char **key_data, size_t *size
  1374     )
  1375 {
  1376     assert(session);
  1377     assert(fpr);
  1378     assert(key_data);
  1379     assert(size);
  1380 
  1381     if (!(session && fpr && key_data && size))
  1382         return PEP_ILLEGAL_VALUE;
  1383 
  1384     // don't accept key IDs but full fingerprints only
  1385     if (strlen(fpr) < 16)
  1386         return PEP_ILLEGAL_VALUE;
  1387 
  1388     return session->cryptotech[PEP_crypt_OpenPGP].export_key(session, fpr,
  1389             key_data, size, true);
  1390 }
  1391 
  1392 DYNAMIC_API PEP_STATUS find_keys(
  1393         PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1394     )
  1395 {
  1396     assert(session);
  1397     assert(pattern);
  1398     assert(keylist);
  1399 
  1400     if (!(session && pattern && keylist))
  1401         return PEP_ILLEGAL_VALUE;
  1402 
  1403     return session->cryptotech[PEP_crypt_OpenPGP].find_keys(session, pattern,
  1404             keylist);
  1405 }
  1406 
  1407 
  1408 DYNAMIC_API PEP_STATUS generate_keypair(
  1409         PEP_SESSION session, pEp_identity *identity
  1410     )
  1411 {
  1412     assert(session);
  1413     assert(identity);
  1414     assert(identity->address);
  1415     assert(identity->fpr == NULL || identity->fpr[0] == 0);
  1416     assert(identity->username);
  1417 
  1418     if (!(session && identity && identity->address &&
  1419             (identity->fpr == NULL || identity->fpr[0] == 0) &&
  1420             identity->username))
  1421         return PEP_ILLEGAL_VALUE;
  1422 
  1423     PEP_STATUS status =
  1424         session->cryptotech[PEP_crypt_OpenPGP].generate_keypair(session,
  1425                 identity);
  1426     if (status != PEP_STATUS_OK)
  1427         return status;
  1428 
  1429     return status;
  1430 }
  1431 
  1432 DYNAMIC_API PEP_STATUS get_key_rating(
  1433         PEP_SESSION session,
  1434         const char *fpr,
  1435         PEP_comm_type *comm_type
  1436     )
  1437 {
  1438     assert(session);
  1439     assert(fpr);
  1440     assert(comm_type);
  1441 
  1442     if (!(session && fpr && comm_type))
  1443         return PEP_ILLEGAL_VALUE;
  1444 
  1445     return session->cryptotech[PEP_crypt_OpenPGP].get_key_rating(session, fpr,
  1446             comm_type);
  1447 }
  1448 
  1449 DYNAMIC_API PEP_STATUS import_key(
  1450         PEP_SESSION session,
  1451         const char *key_data,
  1452         size_t size,
  1453         identity_list **private_keys
  1454     )
  1455 {
  1456     assert(session);
  1457     assert(key_data);
  1458 
  1459     if (!(session && key_data))
  1460         return PEP_ILLEGAL_VALUE;
  1461 
  1462     return session->cryptotech[PEP_crypt_OpenPGP].import_key(session, key_data,
  1463             size, private_keys);
  1464 }
  1465 
  1466 DYNAMIC_API PEP_STATUS recv_key(PEP_SESSION session, const char *pattern)
  1467 {
  1468     assert(session);
  1469     assert(pattern);
  1470 
  1471     if (!(session && pattern))
  1472         return PEP_ILLEGAL_VALUE;
  1473 
  1474     return session->cryptotech[PEP_crypt_OpenPGP].recv_key(session, pattern);
  1475 }
  1476 
  1477 DYNAMIC_API PEP_STATUS send_key(PEP_SESSION session, const char *pattern)
  1478 {
  1479     assert(session);
  1480     assert(pattern);
  1481 
  1482     if (!(session && pattern))
  1483         return PEP_ILLEGAL_VALUE;
  1484 
  1485     return session->cryptotech[PEP_crypt_OpenPGP].send_key(session, pattern);
  1486 }
  1487 
  1488 DYNAMIC_API PEP_STATUS renew_key(
  1489         PEP_SESSION session,
  1490         const char *fpr,
  1491         const timestamp *ts
  1492     )
  1493 {
  1494     assert(session);
  1495     assert(fpr);
  1496 
  1497     if (!(session && fpr))
  1498         return PEP_ILLEGAL_VALUE;
  1499 
  1500     return session->cryptotech[PEP_crypt_OpenPGP].renew_key(session, fpr, ts);
  1501 }
  1502 
  1503 DYNAMIC_API PEP_STATUS revoke_key(
  1504         PEP_SESSION session,
  1505         const char *fpr,
  1506         const char *reason
  1507     )
  1508 {
  1509     assert(session);
  1510     assert(fpr);
  1511 
  1512     if (!(session && fpr))
  1513         return PEP_ILLEGAL_VALUE;
  1514 
  1515     return session->cryptotech[PEP_crypt_OpenPGP].revoke_key(session, fpr,
  1516             reason);
  1517 }
  1518 
  1519 DYNAMIC_API PEP_STATUS key_expired(
  1520         PEP_SESSION session,
  1521         const char *fpr,
  1522         const time_t when,
  1523         bool *expired
  1524     )
  1525 {
  1526     assert(session);
  1527     assert(fpr);
  1528     assert(expired);
  1529 
  1530     if (!(session && fpr && expired))
  1531         return PEP_ILLEGAL_VALUE;
  1532 
  1533     return session->cryptotech[PEP_crypt_OpenPGP].key_expired(session, fpr,
  1534             when, expired);
  1535 }
  1536 
  1537 DYNAMIC_API PEP_STATUS key_revoked(
  1538        PEP_SESSION session,
  1539        const char *fpr,
  1540        bool *revoked
  1541    )
  1542 {
  1543     assert(session);
  1544     assert(fpr);
  1545     assert(revoked);
  1546     
  1547     if (!(session && fpr && revoked))
  1548         return PEP_ILLEGAL_VALUE;
  1549     
  1550     return session->cryptotech[PEP_crypt_OpenPGP].key_revoked(session, fpr,
  1551             revoked);
  1552 }
  1553 
  1554 static void _clean_log_value(char *text)
  1555 {
  1556     if (text) {
  1557         for (char *c = text; *c; c++) {
  1558             if (*c < 32 && *c != '\n')
  1559                 *c = 32;
  1560             else if (*c == '"')
  1561                 *c = '\'';
  1562         }
  1563     }
  1564 }
  1565 
  1566 static char *_concat_string(char *str1, const char *str2, char delim)
  1567 {
  1568     str2 = str2 ? str2 : "";
  1569     size_t len1 = str1 ? strlen(str1) : 0;
  1570     size_t len2 = strlen(str2);
  1571     size_t len = len1 + len2 + 3;
  1572     char * result = realloc(str1, len + 1);
  1573 
  1574     if (result) {
  1575         result[len1] = '"';
  1576         strcpy(result + len1 + 1, str2);
  1577         result[len - 2] = '"';
  1578         result[len - 1] = delim;
  1579         result[len] = 0;
  1580     }
  1581     else {
  1582         free(str1);
  1583     }
  1584 
  1585     return result;
  1586 }
  1587 
  1588 DYNAMIC_API PEP_STATUS get_crashdump_log(
  1589         PEP_SESSION session,
  1590         int maxlines,
  1591         char **logdata
  1592     )
  1593 {
  1594     PEP_STATUS status = PEP_STATUS_OK;
  1595     char *_logdata= NULL;
  1596 
  1597     assert(session);
  1598     assert(maxlines >= 0 && maxlines <= CRASHDUMP_MAX_LINES);
  1599     assert(logdata);
  1600 
  1601     if (!(session && logdata && maxlines >= 0 && maxlines <=
  1602             CRASHDUMP_MAX_LINES))
  1603         return PEP_ILLEGAL_VALUE;
  1604 
  1605     *logdata = NULL;
  1606 
  1607     int limit = maxlines ? maxlines : CRASHDUMP_DEFAULT_LINES;
  1608     const char *timestamp = NULL;
  1609     const char *title = NULL;
  1610     const char *entity = NULL;
  1611     const char *desc = NULL;
  1612     const char *comment = NULL;
  1613 
  1614     sqlite3_reset(session->crashdump);
  1615     sqlite3_bind_int(session->crashdump, 1, limit);
  1616 
  1617     int result;
  1618 
  1619     do {
  1620         result = sqlite3_step(session->crashdump);
  1621         switch (result) {
  1622         case SQLITE_ROW:
  1623             timestamp = (const char *) sqlite3_column_text(session->crashdump,
  1624                     0);
  1625             title   = (const char *) sqlite3_column_text(session->crashdump,
  1626                     1);
  1627             entity  = (const char *) sqlite3_column_text(session->crashdump,
  1628                     2);
  1629             desc    = (const char *) sqlite3_column_text(session->crashdump,
  1630                     3);
  1631             comment = (const char *) sqlite3_column_text(session->crashdump,
  1632                     4);
  1633 
  1634             _logdata = _concat_string(_logdata, timestamp, ',');
  1635             if (_logdata == NULL)
  1636                 goto enomem;
  1637 
  1638             _logdata = _concat_string(_logdata, title, ',');
  1639             if (_logdata == NULL)
  1640                 goto enomem;
  1641 
  1642             _logdata = _concat_string(_logdata, entity, ',');
  1643             if (_logdata == NULL)
  1644                 goto enomem;
  1645 
  1646             _logdata = _concat_string(_logdata, desc, ',');
  1647             if (_logdata == NULL)
  1648                 goto enomem;
  1649 
  1650             _logdata = _concat_string(_logdata, comment, '\n');
  1651             if (_logdata == NULL)
  1652                 goto enomem;
  1653 
  1654             _clean_log_value(_logdata);
  1655             break;
  1656 
  1657         case SQLITE_DONE:
  1658             break;
  1659 
  1660         default:
  1661             status = PEP_UNKNOWN_ERROR;
  1662             result = SQLITE_DONE;
  1663         }
  1664     } while (result != SQLITE_DONE);
  1665 
  1666     sqlite3_reset(session->crashdump);
  1667     if (status == PEP_STATUS_OK)
  1668         *logdata = _logdata;
  1669 
  1670     goto the_end;
  1671 
  1672 enomem:
  1673     status = PEP_OUT_OF_MEMORY;
  1674 
  1675 the_end:
  1676     return status;
  1677 }
  1678 
  1679 DYNAMIC_API PEP_STATUS get_languagelist(
  1680         PEP_SESSION session,
  1681         char **languages
  1682     )
  1683 {
  1684     PEP_STATUS status = PEP_STATUS_OK;
  1685     char *_languages= NULL;
  1686 
  1687     assert(session);
  1688     assert(languages);
  1689 
  1690     if (!(session && languages))
  1691         return PEP_ILLEGAL_VALUE;
  1692 
  1693     *languages = NULL;
  1694 
  1695     const char *lang = NULL;
  1696     const char *name = NULL;
  1697     const char *phrase = NULL;
  1698 
  1699     sqlite3_reset(session->languagelist);
  1700 
  1701     int result;
  1702 
  1703     do {
  1704         result = sqlite3_step(session->languagelist);
  1705         switch (result) {
  1706         case SQLITE_ROW:
  1707             lang = (const char *) sqlite3_column_text(session->languagelist,
  1708                     0);
  1709             name = (const char *) sqlite3_column_text(session->languagelist,
  1710                     1);
  1711             phrase = (const char *) sqlite3_column_text(session->languagelist,
  1712                     2);
  1713 
  1714             _languages = _concat_string(_languages, lang, ',');
  1715             if (_languages == NULL)
  1716                 goto enomem;
  1717 
  1718             _languages = _concat_string(_languages, name, ',');
  1719             if (_languages == NULL)
  1720                 goto enomem;
  1721 
  1722             _languages = _concat_string(_languages, phrase, '\n');
  1723             if (_languages == NULL)
  1724                 goto enomem;
  1725 
  1726             break;
  1727 
  1728         case SQLITE_DONE:
  1729             break;
  1730 
  1731         default:
  1732             status = PEP_UNKNOWN_ERROR;
  1733             result = SQLITE_DONE;
  1734         }
  1735     } while (result != SQLITE_DONE);
  1736 
  1737     sqlite3_reset(session->languagelist);
  1738     if (status == PEP_STATUS_OK)
  1739         *languages = _languages;
  1740 
  1741     goto the_end;
  1742 
  1743 enomem:
  1744     status = PEP_OUT_OF_MEMORY;
  1745 
  1746 the_end:
  1747     return status;
  1748 }
  1749 
  1750 DYNAMIC_API PEP_STATUS get_phrase(
  1751         PEP_SESSION session,
  1752         const char *lang,
  1753         int phrase_id,
  1754         char **phrase
  1755     )
  1756 {
  1757     PEP_STATUS status = PEP_STATUS_OK;
  1758 
  1759     assert(session && lang && lang[0] && lang[1] && lang[2] == 0 && phrase);
  1760     if (!(session && lang && lang[0] && lang[1] && lang[2] == 0 && phrase))
  1761         return PEP_ILLEGAL_VALUE;
  1762 
  1763     *phrase = NULL;
  1764 
  1765     sqlite3_reset(session->i18n_token);
  1766     sqlite3_bind_text(session->i18n_token, 1, lang, -1, SQLITE_STATIC);
  1767     sqlite3_bind_int(session->i18n_token, 2, phrase_id);
  1768 
  1769     const char *_phrase = NULL;
  1770     int result;
  1771 
  1772     result = sqlite3_step(session->i18n_token);
  1773     switch (result) {
  1774     case SQLITE_ROW:
  1775         _phrase = (const char *) sqlite3_column_text(session->i18n_token, 0);
  1776         break;
  1777 
  1778     case SQLITE_DONE:
  1779         status = PEP_PHRASE_NOT_FOUND;
  1780         break;
  1781 
  1782     default:
  1783         status = PEP_UNKNOWN_ERROR;
  1784     }
  1785 
  1786     if (status == PEP_STATUS_OK) {
  1787         *phrase = strdup(_phrase);
  1788         if (*phrase == NULL)
  1789             goto enomem;
  1790     }
  1791 
  1792     sqlite3_reset(session->i18n_token);
  1793     goto the_end;
  1794 
  1795 enomem:
  1796     status = PEP_OUT_OF_MEMORY;
  1797 
  1798 the_end:
  1799     return status;
  1800 }
  1801 
  1802 static PEP_STATUS _get_sequence_value(PEP_SESSION session, const char *name,
  1803         int32_t *value)
  1804 {
  1805     assert(session && name && value);
  1806     if (!(session && name && value))
  1807         return PEP_ILLEGAL_VALUE;
  1808 
  1809     PEP_STATUS status = PEP_STATUS_OK;
  1810 
  1811     sqlite3_reset(session->sequence_value2);
  1812     sqlite3_bind_text(session->sequence_value2, 1, name, -1,
  1813             SQLITE_STATIC);
  1814     int result = sqlite3_step(session->sequence_value2);
  1815     switch (result) {
  1816         case SQLITE_ROW: {
  1817             int32_t _value = (int32_t)
  1818                     sqlite3_column_int(session->sequence_value2, 0);
  1819             int _own = (int)
  1820                     sqlite3_column_int(session->sequence_value2, 1);
  1821             *value = _value;
  1822             if (_own)
  1823                 status = PEP_OWN_SEQUENCE;
  1824             break;
  1825         }
  1826         case SQLITE_DONE:
  1827             status = PEP_RECORD_NOT_FOUND;
  1828             break;
  1829         default:
  1830             status = PEP_UNKNOWN_ERROR;
  1831     }
  1832     sqlite3_reset(session->sequence_value2);
  1833 
  1834     return status;
  1835 }
  1836 
  1837 static PEP_STATUS _increment_sequence_value(PEP_SESSION session,
  1838         const char *name, int own)
  1839 {
  1840     assert(session && name);
  1841     if (!(session && name))
  1842         return PEP_ILLEGAL_VALUE;
  1843 
  1844     sqlite3_reset(session->sequence_value1);
  1845     sqlite3_bind_text(session->sequence_value1, 1, name, -1, SQLITE_STATIC);
  1846     sqlite3_bind_int(session->sequence_value1, 2, own);
  1847     int result = sqlite3_step(session->sequence_value1);
  1848     assert(result == SQLITE_DONE);
  1849     sqlite3_reset(session->sequence_value1);
  1850     if (result == SQLITE_DONE)
  1851         return PEP_STATUS_OK;
  1852     else
  1853         return PEP_CANNOT_INCREASE_SEQUENCE;
  1854 }
  1855 
  1856 static PEP_STATUS _set_sequence_value(PEP_SESSION session,
  1857         const char *name, int32_t value, int own)
  1858 {
  1859     assert(session && name && value > 0);
  1860     if (!(session && name && value > 0))
  1861         return PEP_ILLEGAL_VALUE;
  1862 
  1863     sqlite3_reset(session->sequence_value3);
  1864     sqlite3_bind_text(session->sequence_value3, 1, name, -1, SQLITE_STATIC);
  1865     sqlite3_bind_int(session->sequence_value3, 2, value);
  1866     sqlite3_bind_int(session->sequence_value3, 3, own);
  1867     int result = sqlite3_step(session->sequence_value3);
  1868     assert(result == SQLITE_DONE);
  1869     sqlite3_reset(session->sequence_value3);
  1870     if (result == SQLITE_DONE)
  1871         return PEP_STATUS_OK;
  1872     else
  1873         return PEP_CANNOT_SET_SEQUENCE_VALUE;
  1874 }
  1875 
  1876 DYNAMIC_API PEP_STATUS sequence_value(
  1877         PEP_SESSION session,
  1878         char *name,
  1879         int32_t *value
  1880     )
  1881 {
  1882     PEP_STATUS status = PEP_STATUS_OK;
  1883 
  1884     assert(session);
  1885     assert(name && value && *value >= 0);
  1886 
  1887     if (!(session && name && value && *value >= 0))
  1888         return PEP_ILLEGAL_VALUE;
  1889 
  1890     int own = 0;
  1891     if (!name[0]) {
  1892         unsigned char uuid[16];
  1893         uuid_generate_random(uuid);
  1894         uuid_unparse_upper(uuid, name);
  1895         own = 1;
  1896     }
  1897     else {
  1898         if (name == session->sync_uuid || strcmp(name, session->sync_uuid) == 0)
  1899             own = 1;
  1900     }
  1901 
  1902     if (*value) {
  1903         int32_t old_value = 0;
  1904         status = _get_sequence_value(session, name, &old_value);
  1905         if (status != PEP_STATUS_OK && status != PEP_RECORD_NOT_FOUND)
  1906             return status;
  1907 
  1908         if (old_value >= *value) {
  1909             return PEP_SEQUENCE_VIOLATED;
  1910         }
  1911         else {
  1912             status = _set_sequence_value(session, name, *value, own);
  1913             return status;
  1914         }
  1915     }
  1916 
  1917     assert(*value == 0);
  1918     status = _increment_sequence_value(session, name, own);
  1919     if (status == PEP_STATUS_OK) {
  1920         status = _get_sequence_value(session, name, value);
  1921         assert(*value < INT32_MAX);
  1922         if (*value == INT32_MAX)
  1923             return PEP_CANNOT_INCREASE_SEQUENCE;
  1924     }
  1925     return status;
  1926 }
  1927 
  1928 DYNAMIC_API PEP_STATUS set_revoked(
  1929        PEP_SESSION session,
  1930        const char *revoked_fpr,
  1931        const char *replacement_fpr,
  1932        const uint64_t revocation_date
  1933     )
  1934 {
  1935     PEP_STATUS status = PEP_STATUS_OK;
  1936     
  1937     assert(session &&
  1938            revoked_fpr && revoked_fpr[0] &&
  1939            replacement_fpr && replacement_fpr[0]
  1940           );
  1941     
  1942     if (!(session &&
  1943           revoked_fpr && revoked_fpr[0] &&
  1944           replacement_fpr && replacement_fpr[0]
  1945          ))
  1946         return PEP_ILLEGAL_VALUE;
  1947     
  1948     sqlite3_reset(session->set_revoked);
  1949     sqlite3_bind_text(session->set_revoked, 1, revoked_fpr, -1, SQLITE_STATIC);
  1950     sqlite3_bind_text(session->set_revoked, 2, replacement_fpr, -1,
  1951             SQLITE_STATIC);
  1952     sqlite3_bind_int64(session->set_revoked, 3, revocation_date);
  1953 
  1954     int result;
  1955     
  1956     result = sqlite3_step(session->set_revoked);
  1957     switch (result) {
  1958         case SQLITE_DONE:
  1959             status = PEP_STATUS_OK;
  1960             break;
  1961             
  1962         default:
  1963             status = PEP_UNKNOWN_ERROR;
  1964     }
  1965     
  1966     sqlite3_reset(session->set_revoked);
  1967     return status;
  1968 }
  1969 
  1970 DYNAMIC_API PEP_STATUS get_revoked(
  1971         PEP_SESSION session,
  1972         const char *fpr,
  1973         char **revoked_fpr,
  1974         uint64_t *revocation_date
  1975     )
  1976 {
  1977     PEP_STATUS status = PEP_STATUS_OK;
  1978 
  1979     assert(session &&
  1980            revoked_fpr &&
  1981            fpr && fpr[0]
  1982           );
  1983     
  1984     if (!(session &&
  1985            revoked_fpr &&
  1986            fpr && fpr[0]
  1987           ))
  1988         return PEP_ILLEGAL_VALUE;
  1989 
  1990     *revoked_fpr = NULL;
  1991     *revocation_date = 0;
  1992 
  1993     sqlite3_reset(session->get_revoked);
  1994     sqlite3_bind_text(session->get_revoked, 1, fpr, -1, SQLITE_STATIC);
  1995 
  1996     int result;
  1997     
  1998     result = sqlite3_step(session->get_revoked);
  1999     switch (result) {
  2000         case SQLITE_ROW: {
  2001             *revoked_fpr = strdup((const char *)
  2002                     sqlite3_column_text(session->get_revoked, 0));
  2003             if(*revoked_fpr)
  2004                 *revocation_date = sqlite3_column_int64(session->get_revoked,
  2005                         1);
  2006             else
  2007                 status = PEP_OUT_OF_MEMORY;
  2008 
  2009             break;
  2010         }
  2011         default:
  2012             status = PEP_CANNOT_FIND_IDENTITY;
  2013     }
  2014 
  2015     sqlite3_reset(session->get_revoked);
  2016 
  2017     return status;
  2018 }
  2019 
  2020 PEP_STATUS key_created(
  2021         PEP_SESSION session,
  2022         const char *fpr,
  2023         time_t *created
  2024     )
  2025 {
  2026     assert(session && fpr && created);
  2027     if (!(session && fpr && created))
  2028         return PEP_ILLEGAL_VALUE;
  2029 
  2030     return session->cryptotech[PEP_crypt_OpenPGP].key_created(session, fpr,
  2031             created);
  2032 }
  2033 
  2034 DYNAMIC_API const char* get_engine_version() {
  2035     return PEP_ENGINE_VERSION;
  2036 }
  2037 
  2038 
  2039 DYNAMIC_API PEP_STATUS reset_peptest_hack(PEP_SESSION session)
  2040 {
  2041     assert(session);
  2042 
  2043     if (!session)
  2044         return PEP_ILLEGAL_VALUE;
  2045 
  2046     int int_result = sqlite3_exec(
  2047         session->db,
  2048         "delete from identity where address like '%@peptest.ch' ;",
  2049         NULL,
  2050         NULL,
  2051         NULL
  2052     );
  2053     assert(int_result == SQLITE_OK);
  2054 
  2055     return PEP_STATUS_OK;
  2056 }
  2057