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