src/pgp_sequoia.c
author Neal H. Walfield <neal@pep.foundation>
Fri, 10 May 2019 11:35:31 +0200
branchsync
changeset 3659 bd1c82a4f0ff
parent 3658 733edb269d7d
child 3661 448ed57fac2c
child 3662 54d7ca4f7529
permissions -rw-r--r--
sequoia: Track Sequoia API changes
neal@3191
     1
// This file is under GNU General Public License 3.0
neal@3191
     2
// see LICENSE.txt
neal@3191
     3
vb@3543
     4
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
vb@3543
     5
neal@3191
     6
#define _GNU_SOURCE 1
neal@3191
     7
neal@3191
     8
#include "platform.h"
neal@3191
     9
#include "pEp_internal.h"
neal@3191
    10
#include "pgp_gpg.h"
neal@3191
    11
neal@3191
    12
#include <limits.h>
neal@3191
    13
#include <sys/stat.h>
neal@3191
    14
#include <sys/types.h>
neal@3191
    15
neal@3191
    16
#include "wrappers.h"
neal@3191
    17
neal@3332
    18
#define TRACING 0
neal@3211
    19
#ifndef TRACING
neal@3211
    20
#  ifndef NDEBUG
neal@3211
    21
#    define TRACING 0
neal@3211
    22
#  else
neal@3211
    23
#    define TRACING 1
neal@3211
    24
#  endif
neal@3211
    25
#endif
neal@3211
    26
vb@3197
    27
// enable tracing if in debugging mode
neal@3211
    28
#if TRACING
vb@3624
    29
#include "status_to_string.h"
neal@3191
    30
#  define _T(...) do {                          \
neal@3191
    31
        fprintf(stderr, ##__VA_ARGS__);         \
neal@3191
    32
    } while (0)
neal@3191
    33
#else
neal@3191
    34
#  define _T(...) do { } while (0)
neal@3191
    35
#endif
neal@3191
    36
neal@3191
    37
// Show the start of a tracepoint (i.e., don't print a newline).
neal@3191
    38
#define TC(...) do {       \
neal@3191
    39
    _T("%s: ", __func__);  \
neal@3191
    40
    _T(__VA_ARGS__);       \
neal@3191
    41
} while (0)
neal@3191
    42
neal@3191
    43
// Show a trace point.
neal@3191
    44
#  define T(...) do {  \
neal@3191
    45
    TC(__VA_ARGS__); \
neal@3191
    46
    _T("\n");          \
neal@3191
    47
} while(0)
neal@3191
    48
neal@3191
    49
// Verbosely displays errors.
neal@3643
    50
#  define DUMP_STATUS(__de_sq_status, __de_pep_status, ...) do { \
neal@3643
    51
    TC(__VA_ARGS__);                                            \
neal@3643
    52
    _T(": ");                                                   \
neal@3643
    53
    if (__de_sq_status) {                                       \
neal@3643
    54
        _T("Sequoia: %s => ", pgp_status_to_string(__de_sq_status));   \
neal@3643
    55
    }                                                           \
neal@3643
    56
    _T("%s\n", pEp_status_to_string(__de_pep_status));          \
neal@3643
    57
} while(0)
neal@3643
    58
neal@3332
    59
#  define DUMP_ERR(__de_err, __de_status, ...) do {             \
neal@3332
    60
    TC(__VA_ARGS__);                                            \
neal@3332
    61
    _T(": ");                                                   \
neal@3332
    62
    if (__de_err) {                                             \
neal@3332
    63
        _T("Sequoia: %s => ", pgp_error_to_string(__de_err));   \
neal@3332
    64
        pgp_error_free(__de_err);                               \
neal@3332
    65
    }                                                           \
vb@3621
    66
    _T("%s\n", pEp_status_to_string(__de_status));              \
neal@3191
    67
} while(0)
neal@3191
    68
neal@3191
    69
// If __ec_status is an error, then disable the error, set 'status' to
neal@3191
    70
// it, and jump to 'out'.
neal@3332
    71
#define ERROR_OUT(__e_err, __ec_status, ...) do {                   \
neal@3191
    72
    PEP_STATUS ___ec_status = (__ec_status);                        \
neal@3191
    73
    if ((___ec_status) != PEP_STATUS_OK) {                          \
neal@3332
    74
        DUMP_ERR((__e_err), (___ec_status), ##__VA_ARGS__);         \
neal@3191
    75
        status = (___ec_status);                                    \
neal@3191
    76
        goto out;                                                   \
neal@3191
    77
    }                                                               \
neal@3191
    78
} while(0)
neal@3191
    79
neal@3650
    80
int email_cmp(void *cookie, int a_len, const void *a, int b_len, const void *b)
neal@3650
    81
{
neal@3650
    82
    pgp_packet_t a_userid = pgp_user_id_from_raw (a, a_len);
neal@3650
    83
    pgp_packet_t b_userid = pgp_user_id_from_raw (b, b_len);
neal@3650
    84
neal@3657
    85
    T("(%.*s, %.*s)", a_len, (const char *) a, b_len, (const char *) b);
neal@3650
    86
neal@3650
    87
    char *a_address = NULL;
neal@3650
    88
    pgp_user_id_address_normalized(NULL, a_userid, &a_address);
neal@3650
    89
neal@3650
    90
    char *b_address = NULL;
neal@3650
    91
    pgp_user_id_address_normalized(NULL, b_userid, &b_address);
neal@3650
    92
neal@3650
    93
    pgp_packet_free(a_userid);
neal@3650
    94
    pgp_packet_free(b_userid);
neal@3650
    95
neal@3650
    96
    // return an integer that is negative, zero, or positive if the
neal@3650
    97
    // first string is less than, equal to, or greater than the
neal@3650
    98
    // second, respectively.
neal@3650
    99
    int result;
neal@3650
   100
    if (!a_address && !b_address)
neal@3650
   101
        result = 0;
neal@3650
   102
    else if (!a_address)
neal@3650
   103
        result = -1;
neal@3650
   104
    else if (!b_address)
neal@3650
   105
        result = 1;
neal@3650
   106
    else
neal@3650
   107
        result = strcmp(a_address, b_address);
neal@3650
   108
neal@3650
   109
    if (true) {
neal@3650
   110
        T("'%s' %s '%s'",
neal@3650
   111
          a_address,
neal@3650
   112
          result == 0 ? "==" : result < 0 ? "<" : ">",
neal@3650
   113
          b_address);
neal@3650
   114
    }
neal@3650
   115
neal@3650
   116
    free(a_address);
neal@3650
   117
    free(b_address);
neal@3650
   118
neal@3650
   119
    return result;
neal@3650
   120
}
neal@3650
   121
neal@3191
   122
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
neal@3191
   123
{
neal@3191
   124
    PEP_STATUS status = PEP_STATUS_OK;
neal@3191
   125
neal@3191
   126
    // Create the home directory.
neal@3191
   127
    char *home_env = getenv("HOME");
neal@3191
   128
    if (!home_env)
neal@3332
   129
        ERROR_OUT(NULL, PEP_INIT_GPGME_INIT_FAILED, "HOME unset");
neal@3191
   130
neal@3191
   131
    // Create the DB and initialize it.
huss@3546
   132
    size_t path_size = strlen(home_env)+13+1;
huss@3546
   133
    char *path = (char *) calloc(1, path_size);
huss@3546
   134
    assert(path);
neal@3191
   135
    if (!path)
neal@3332
   136
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
neal@3191
   137
huss@3546
   138
    int r = snprintf(path, path_size, "%s/.pEp_keys.db", home_env);
huss@3546
   139
    assert(r >= 0 && r < path_size);
huss@3546
   140
    if (r < 0)
huss@3546
   141
        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR, "snprintf");
huss@3546
   142
neal@3191
   143
    int sqlite_result;
neal@3191
   144
    sqlite_result = sqlite3_open_v2(path,
neal@3191
   145
                                    &session->key_db,
neal@3191
   146
                                    SQLITE_OPEN_READWRITE
neal@3191
   147
                                    | SQLITE_OPEN_CREATE
neal@3191
   148
                                    | SQLITE_OPEN_FULLMUTEX
neal@3191
   149
                                    | SQLITE_OPEN_PRIVATECACHE,
neal@3191
   150
                                    NULL);
neal@3191
   151
    free(path);
neal@3191
   152
    if (sqlite_result != SQLITE_OK)
neal@3332
   153
        ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
neal@3332
   154
                  "opening keys DB: %s", sqlite3_errmsg(session->key_db));
neal@3191
   155
neal@3191
   156
    sqlite_result = sqlite3_exec(session->key_db,
neal@3213
   157
                                 "PRAGMA secure_delete=true;\n"
neal@3213
   158
                                 "PRAGMA foreign_keys=true;\n"
neal@3191
   159
                                 "PRAGMA locking_mode=NORMAL;\n"
neal@3191
   160
                                 "PRAGMA journal_mode=WAL;\n",
neal@3191
   161
                                 NULL, NULL, NULL);
neal@3191
   162
    if (sqlite_result != SQLITE_OK)
neal@3332
   163
        ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
neal@3191
   164
                  "setting pragmas: %s", sqlite3_errmsg(session->key_db));
neal@3191
   165
neal@3191
   166
    sqlite3_busy_timeout(session->key_db, BUSY_WAIT_TIME);
neal@3191
   167
neal@3650
   168
    sqlite_result =
neal@3650
   169
        sqlite3_create_collation(session->key_db,
neal@3650
   170
                                "EMAIL",
neal@3650
   171
                                SQLITE_UTF8,
neal@3650
   172
                                /* pArg (cookie) */ NULL,
neal@3650
   173
                                email_cmp);
neal@3650
   174
    if (sqlite_result != SQLITE_OK)
neal@3650
   175
        ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
neal@3650
   176
                  "registering EMAIL collation function: %s",
neal@3650
   177
                  sqlite3_errmsg(session->key_db));
neal@3650
   178
neal@3191
   179
    sqlite_result = sqlite3_exec(session->key_db,
neal@3191
   180
                                 "CREATE TABLE IF NOT EXISTS keys (\n"
us@3209
   181
                                 "   primary_key TEXT UNIQUE PRIMARY KEY,\n"
us@3209
   182
                                 "   secret BOOLEAN,\n"
us@3209
   183
                                 "   tpk BLOB\n"
us@3209
   184
                                 ");\n"
us@3209
   185
                                 "CREATE INDEX IF NOT EXISTS keys_index\n"
us@3209
   186
                                 "  ON keys (primary_key, secret)\n",
neal@3191
   187
                                 NULL, NULL, NULL);
neal@3191
   188
    if (sqlite_result != SQLITE_OK)
neal@3332
   189
        ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
neal@3191
   190
                  "creating keys table: %s",
neal@3191
   191
                  sqlite3_errmsg(session->key_db));
neal@3191
   192
neal@3191
   193
    sqlite_result = sqlite3_exec(session->key_db,
neal@3191
   194
                                 "CREATE TABLE IF NOT EXISTS subkeys (\n"
us@3209
   195
                                 "   subkey TEXT NOT NULL,\n"
us@3209
   196
                                 "   primary_key TEXT NOT NULL,\n"
us@3209
   197
                                 "   UNIQUE(subkey, primary_key),\n"
neal@3191
   198
                                 "   FOREIGN KEY (primary_key)\n"
neal@3191
   199
                                 "       REFERENCES keys(primary_key)\n"
neal@3191
   200
                                 "     ON DELETE CASCADE\n"
us@3209
   201
                                 ");\n"
us@3209
   202
                                 "CREATE INDEX IF NOT EXISTS subkeys_index\n"
us@3209
   203
                                 "  ON subkeys (subkey, primary_key)\n",
neal@3191
   204
                                 NULL, NULL, NULL);
neal@3191
   205
    if (sqlite_result != SQLITE_OK)
neal@3332
   206
        ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
neal@3191
   207
                  "creating subkeys table: %s",
neal@3191
   208
                  sqlite3_errmsg(session->key_db));
neal@3191
   209
us@3209
   210
    sqlite_result = sqlite3_exec(session->key_db,
us@3209
   211
                                 "CREATE TABLE IF NOT EXISTS userids (\n"
neal@3650
   212
                                 "   userid TEXT NOT NULL COLLATE EMAIL,\n"
us@3209
   213
                                 "   primary_key TEXT NOT NULL,\n"
us@3209
   214
                                 "   UNIQUE(userid, primary_key),\n"
us@3209
   215
                                 "   FOREIGN KEY (primary_key)\n"
us@3209
   216
                                 "       REFERENCES keys(primary_key)\n"
us@3209
   217
                                 "     ON DELETE CASCADE\n"
us@3209
   218
                                 ");\n"
us@3209
   219
                                 "CREATE INDEX IF NOT EXISTS userids_index\n"
neal@3650
   220
                                 "  ON userids (userid COLLATE EMAIL, primary_key)\n",
us@3209
   221
                                 NULL, NULL, NULL);
us@3209
   222
    if (sqlite_result != SQLITE_OK)
neal@3332
   223
        ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
us@3209
   224
                  "creating userids table: %s",
us@3209
   225
                  sqlite3_errmsg(session->key_db));
us@3209
   226
neal@3191
   227
    sqlite_result
neal@3191
   228
        = sqlite3_prepare_v2(session->key_db, "begin transaction",
neal@3212
   229
                             -1, &session->sq_sql.begin_transaction, NULL);
neal@3191
   230
    assert(sqlite_result == SQLITE_OK);
neal@3191
   231
neal@3191
   232
    sqlite_result
neal@3191
   233
        = sqlite3_prepare_v2(session->key_db, "commit transaction",
neal@3212
   234
                             -1, &session->sq_sql.commit_transaction, NULL);
neal@3191
   235
    assert(sqlite_result == SQLITE_OK);
neal@3191
   236
neal@3191
   237
    sqlite_result
neal@3191
   238
        = sqlite3_prepare_v2(session->key_db, "rollback transaction",
neal@3212
   239
                             -1, &session->sq_sql.rollback_transaction, NULL);
neal@3191
   240
    assert(sqlite_result == SQLITE_OK);
neal@3191
   241
neal@3191
   242
    sqlite_result
neal@3191
   243
        = sqlite3_prepare_v2(session->key_db,
us@3209
   244
                             "SELECT tpk, secret FROM keys"
us@3209
   245
                             " WHERE primary_key == ?",
neal@3212
   246
                             -1, &session->sq_sql.tpk_find, NULL);
us@3209
   247
    assert(sqlite_result == SQLITE_OK);
us@3209
   248
us@3209
   249
    sqlite_result
us@3209
   250
        = sqlite3_prepare_v2(session->key_db,
us@3209
   251
                             "SELECT tpk, secret FROM keys"
us@3209
   252
                             " WHERE primary_key == ? and secret == 1",
neal@3212
   253
                             -1, &session->sq_sql.tsk_find, NULL);
us@3209
   254
    assert(sqlite_result == SQLITE_OK);
us@3209
   255
us@3209
   256
    sqlite_result
us@3209
   257
        = sqlite3_prepare_v2(session->key_db,
us@3209
   258
                             "SELECT tpk, secret FROM subkeys"
us@3209
   259
                             " LEFT JOIN keys"
us@3209
   260
                             "  ON subkeys.primary_key == keys.primary_key"
us@3209
   261
                             " WHERE subkey == ?",
neal@3212
   262
                             -1, &session->sq_sql.tpk_find_by_keyid, NULL);
us@3209
   263
    assert(sqlite_result == SQLITE_OK);
us@3209
   264
us@3209
   265
    sqlite_result
us@3209
   266
        = sqlite3_prepare_v2(session->key_db,
us@3209
   267
                             "SELECT tpk, secret FROM subkeys"
us@3209
   268
                             " LEFT JOIN keys"
us@3209
   269
                             "  ON subkeys.primary_key == keys.primary_key"
us@3209
   270
                             " WHERE subkey == ?",
neal@3212
   271
                             -1, &session->sq_sql.tpk_find_by_keyid, NULL);
us@3209
   272
    assert(sqlite_result == SQLITE_OK);
us@3209
   273
us@3209
   274
    sqlite_result
us@3209
   275
        = sqlite3_prepare_v2(session->key_db,
us@3209
   276
                             "SELECT tpk, secret FROM subkeys"
us@3209
   277
                             " LEFT JOIN keys"
us@3209
   278
                             "  ON subkeys.primary_key == keys.primary_key"
us@3209
   279
                             " WHERE subkey == ? and keys.secret == 1",
neal@3212
   280
                             -1, &session->sq_sql.tsk_find_by_keyid, NULL);
us@3209
   281
    assert(sqlite_result == SQLITE_OK);
us@3209
   282
us@3209
   283
    sqlite_result
us@3209
   284
        = sqlite3_prepare_v2(session->key_db,
us@3209
   285
                             "SELECT tpk, secret FROM userids"
us@3209
   286
                             " LEFT JOIN keys"
us@3209
   287
                             "  ON userids.primary_key == keys.primary_key"
us@3209
   288
                             " WHERE userid == ?",
neal@3212
   289
                             -1, &session->sq_sql.tpk_find_by_email, NULL);
us@3209
   290
    assert(sqlite_result == SQLITE_OK);
us@3209
   291
us@3209
   292
    sqlite_result
us@3209
   293
        = sqlite3_prepare_v2(session->key_db,
us@3209
   294
                             "SELECT tpk, secret FROM userids"
us@3209
   295
                             " LEFT JOIN keys"
us@3209
   296
                             "  ON userids.primary_key == keys.primary_key"
us@3209
   297
                             " WHERE userid == ? and keys.secret == 1",
neal@3212
   298
                             -1, &session->sq_sql.tsk_find_by_email, NULL);
us@3209
   299
    assert(sqlite_result == SQLITE_OK);
us@3209
   300
us@3209
   301
    sqlite_result
us@3209
   302
        = sqlite3_prepare_v2(session->key_db,
us@3209
   303
                             "select tpk, secret from keys",
neal@3212
   304
                             -1, &session->sq_sql.tpk_all, NULL);
us@3209
   305
    assert(sqlite_result == SQLITE_OK);
us@3209
   306
us@3209
   307
    sqlite_result
us@3209
   308
        = sqlite3_prepare_v2(session->key_db,
us@3209
   309
                             "select tpk, secret from keys where secret = 1",
neal@3212
   310
                             -1, &session->sq_sql.tsk_all, NULL);
us@3209
   311
    assert(sqlite_result == SQLITE_OK);
us@3209
   312
us@3209
   313
    sqlite_result
us@3209
   314
        = sqlite3_prepare_v2(session->key_db,
neal@3191
   315
                             "INSERT OR REPLACE INTO keys"
us@3209
   316
                             "   (primary_key, secret, tpk)"
us@3209
   317
                             " VALUES (?, ?, ?)",
neal@3212
   318
                             -1, &session->sq_sql.tpk_save_insert_primary, NULL);
neal@3191
   319
    assert(sqlite_result == SQLITE_OK);
neal@3191
   320
neal@3191
   321
    sqlite_result
neal@3191
   322
        = sqlite3_prepare_v2(session->key_db,
neal@3191
   323
                             "INSERT OR REPLACE INTO subkeys"
neal@3191
   324
                             "   (subkey, primary_key)"
neal@3191
   325
                             " VALUES (?, ?)",
neal@3212
   326
                             -1, &session->sq_sql.tpk_save_insert_subkeys, NULL);
neal@3191
   327
    assert(sqlite_result == SQLITE_OK);
neal@3191
   328
neal@3191
   329
    sqlite_result
neal@3191
   330
        = sqlite3_prepare_v2(session->key_db,
us@3209
   331
                             "INSERT OR REPLACE INTO userids"
us@3209
   332
                             "   (userid, primary_key)"
us@3209
   333
                             " VALUES (?, ?)",
neal@3212
   334
                             -1, &session->sq_sql.tpk_save_insert_userids, NULL);
neal@3191
   335
    assert(sqlite_result == SQLITE_OK);
neal@3191
   336
neal@3191
   337
 out:
neal@3191
   338
    if (status != PEP_STATUS_OK)
neal@3191
   339
        pgp_release(session, in_first);
neal@3191
   340
    return status;
neal@3191
   341
}
neal@3191
   342
neal@3191
   343
void pgp_release(PEP_SESSION session, bool out_last)
neal@3191
   344
{
neal@3212
   345
    sqlite3_stmt **stmts = (sqlite3_stmt **) &session->sq_sql;
neal@3212
   346
    for (int i = 0; i < sizeof(session->sq_sql) / sizeof(*stmts); i ++)
neal@3212
   347
        if (stmts[i]) {
neal@3212
   348
            sqlite3_finalize(stmts[i]);
neal@3212
   349
            stmts[i] = NULL;
neal@3212
   350
        }
neal@3191
   351
neal@3191
   352
    if (session->key_db) {
neal@3191
   353
        int result = sqlite3_close_v2(session->key_db);
neal@3191
   354
        if (result != 0)
neal@3332
   355
            DUMP_ERR(NULL, PEP_UNKNOWN_ERROR,
neal@3191
   356
                     "Closing key DB: sqlite3_close_v2: %s",
neal@3191
   357
                     sqlite3_errstr(result));
neal@3191
   358
        session->key_db = NULL;
neal@3191
   359
    }
neal@3191
   360
}
neal@3191
   361
vb@3542
   362
/* commented out to omit compiler warning about unused function
vb@3542
   363
neal@3191
   364
// Ensures that a fingerprint is in canonical form.  A canonical
neal@3191
   365
// fingerprint doesn't contain any white space.
neal@3191
   366
//
neal@3191
   367
// This function does *not* consume fpr.
neal@3332
   368
static char *pgp_fingerprint_canonicalize(const char *) __attribute__((nonnull));
neal@3332
   369
static char *pgp_fingerprint_canonicalize(const char *fpr)
neal@3191
   370
{
neal@3332
   371
    pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(fpr);
neal@3332
   372
    char *fpr_canonicalized = pgp_fingerprint_to_hex(pgp_fpr);
neal@3332
   373
    pgp_fingerprint_free(pgp_fpr);
neal@3191
   374
neal@3191
   375
    return fpr_canonicalized;
neal@3191
   376
}
neal@3191
   377
vb@3542
   378
*/
vb@3542
   379
us@3209
   380
// step statement and load the tpk and secret.
neal@3332
   381
static PEP_STATUS key_load(PEP_SESSION, sqlite3_stmt *, pgp_tpk_t *, int *)
us@3209
   382
    __attribute__((nonnull(1, 2)));
us@3209
   383
static PEP_STATUS key_load(PEP_SESSION session, sqlite3_stmt *stmt,
neal@3332
   384
                           pgp_tpk_t *tpkp, int *secretp)
neal@3191
   385
{
neal@3191
   386
    PEP_STATUS status = PEP_STATUS_OK;
neal@3191
   387
    int sqlite_result = sqlite3_step(stmt);
neal@3191
   388
    switch (sqlite_result) {
neal@3191
   389
    case SQLITE_ROW:
us@3209
   390
        if (tpkp) {
neal@3191
   391
            int data_len = sqlite3_column_bytes(stmt, 0);
neal@3191
   392
            const void *data = sqlite3_column_blob(stmt, 0);
neal@3191
   393
neal@3332
   394
            pgp_error_t err = NULL;
neal@3332
   395
            *tpkp = pgp_tpk_from_bytes(&err, data, data_len);
us@3209
   396
            if (!*tpkp)
neal@3332
   397
                ERROR_OUT(err, PEP_GET_KEY_FAILED, "parsing TPK");
us@3209
   398
        }
neal@3191
   399
us@3209
   400
        if (secretp)
us@3209
   401
            *secretp = sqlite3_column_int(stmt, 1);
us@3209
   402
neal@3191
   403
        break;
neal@3191
   404
    case SQLITE_DONE:
neal@3191
   405
        // Got nothing.
neal@3191
   406
        status = PEP_KEY_NOT_FOUND;
neal@3191
   407
        break;
neal@3191
   408
    default:
neal@3332
   409
        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
us@3209
   410
                  "stepping: %s", sqlite3_errmsg(session->key_db));
neal@3191
   411
    }
neal@3191
   412
neal@3191
   413
 out:
vb@3621
   414
    T(" -> %s", pEp_status_to_string(status));
neal@3191
   415
    return status;
neal@3191
   416
}
neal@3191
   417
us@3209
   418
// step statement until exhausted and load the tpks.
neal@3332
   419
static PEP_STATUS key_loadn(PEP_SESSION, sqlite3_stmt *, pgp_tpk_t **, int *)
us@3209
   420
    __attribute__((nonnull));
us@3209
   421
static PEP_STATUS key_loadn(PEP_SESSION session, sqlite3_stmt *stmt,
neal@3332
   422
                            pgp_tpk_t **tpksp, int *tpks_countp)
us@3209
   423
{
us@3209
   424
    PEP_STATUS status = PEP_STATUS_OK;
us@3209
   425
    int tpks_count = 0;
us@3209
   426
    int tpks_capacity = 8;
neal@3332
   427
    pgp_tpk_t *tpks = calloc(tpks_capacity, sizeof(pgp_tpk_t));
us@3209
   428
    if (!tpks)
neal@3332
   429
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
us@3209
   430
us@3209
   431
    for (;;) {
neal@3332
   432
        pgp_tpk_t tpk = NULL;
us@3209
   433
        status = key_load(session, stmt, &tpk, NULL);
us@3209
   434
        if (status == PEP_KEY_NOT_FOUND) {
us@3209
   435
            status = PEP_STATUS_OK;
us@3209
   436
            break;
us@3209
   437
        }
neal@3332
   438
        ERROR_OUT(NULL, status, "loading TPK");
us@3209
   439
us@3209
   440
        if (tpks_count == tpks_capacity) {
us@3209
   441
            tpks_capacity *= 2;
us@3209
   442
            tpks = realloc(tpks, sizeof(tpks[0]) * tpks_capacity);
us@3209
   443
            if (!tpks)
neal@3332
   444
                ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "tpks");
us@3209
   445
        }
us@3209
   446
        tpks[tpks_count ++] = tpk;
us@3209
   447
    }
us@3209
   448
us@3209
   449
 out:
us@3209
   450
    if (status != PEP_STATUS_OK) {
us@3209
   451
        for (int i = 0; i < tpks_count; i ++)
neal@3332
   452
            pgp_tpk_free(tpks[i]);
us@3209
   453
        free(tpks);
us@3209
   454
    } else {
us@3209
   455
        *tpksp = tpks;
us@3209
   456
        *tpks_countp = tpks_count;
us@3209
   457
    }
us@3209
   458
vb@3621
   459
    T(" -> %s (%d tpks)", pEp_status_to_string(status), *tpks_countp);
us@3209
   460
    return status;
us@3209
   461
}
us@3209
   462
us@3209
   463
// Returns the TPK identified by the provided fingerprint.
us@3209
   464
//
us@3209
   465
// This function only matches on the primary key!
neal@3332
   466
static PEP_STATUS tpk_find(PEP_SESSION, pgp_fingerprint_t, int, pgp_tpk_t *, int *)
neal@3191
   467
    __attribute__((nonnull(1, 2)));
us@3209
   468
static PEP_STATUS tpk_find(PEP_SESSION session,
neal@3332
   469
                           pgp_fingerprint_t fpr, int private_only,
neal@3332
   470
                           pgp_tpk_t *tpk, int *secret)
us@3209
   471
{
us@3209
   472
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
   473
    char *fpr_str = pgp_fingerprint_to_hex(fpr);
us@3209
   474
us@3209
   475
    T("(%s, %d)", fpr_str, private_only);
us@3209
   476
neal@3332
   477
    sqlite3_stmt *stmt
neal@3332
   478
        = private_only ? session->sq_sql.tsk_find : session->sq_sql.tpk_find;
us@3209
   479
    sqlite3_bind_text(stmt, 1, fpr_str, -1, SQLITE_STATIC);
us@3209
   480
us@3209
   481
    status = key_load(session, stmt, tpk, secret);
neal@3332
   482
    ERROR_OUT(NULL, status, "Looking up %s", fpr_str);
us@3209
   483
us@3209
   484
 out:
us@3209
   485
    sqlite3_reset(stmt);
vb@3621
   486
    T("(%s, %d) -> %s", fpr_str, private_only, pEp_status_to_string(status));
us@3209
   487
    free(fpr_str);
us@3209
   488
    return status;
us@3209
   489
}
us@3209
   490
us@3209
   491
// Returns the TPK identified by the provided keyid.
us@3209
   492
//
us@3209
   493
// This function matches on both primary keys and subkeys!
us@3209
   494
//
us@3209
   495
// Note: There can be multiple TPKs for a given keyid.  This can
us@3209
   496
// occur, because an encryption subkey can be bound to multiple TPKs.
us@3209
   497
// Also, it is possible to collide key ids.  If there are multiple key
us@3209
   498
// ids for a given key, this just returns one of them.
us@3209
   499
//
us@3209
   500
// If private_only is set, this will only consider TPKs with some
us@3209
   501
// secret key material.
neal@3332
   502
static PEP_STATUS tpk_find_by_keyid_hex(PEP_SESSION, const char *, int, pgp_tpk_t *, int *)
us@3209
   503
  __attribute__((nonnull(1, 2)));
us@3209
   504
static PEP_STATUS tpk_find_by_keyid_hex(
us@3209
   505
        PEP_SESSION session, const char *keyid_hex, int private_only,
neal@3332
   506
        pgp_tpk_t *tpkp, int *secretp)
us@3209
   507
{
us@3209
   508
    PEP_STATUS status = PEP_STATUS_OK;
us@3209
   509
    T("(%s, %d)", keyid_hex, private_only);
us@3209
   510
us@3209
   511
    sqlite3_stmt *stmt
neal@3212
   512
        = private_only ? session->sq_sql.tsk_find_by_keyid : session->sq_sql.tpk_find_by_keyid;
us@3209
   513
    sqlite3_bind_text(stmt, 1, keyid_hex, -1, SQLITE_STATIC);
us@3209
   514
us@3209
   515
    status = key_load(session, stmt, tpkp, secretp);
neal@3332
   516
    ERROR_OUT(NULL, status, "Looking up %s", keyid_hex);
us@3209
   517
us@3209
   518
 out:
us@3209
   519
    sqlite3_reset(stmt);
vb@3621
   520
    T("(%s, %d) -> %s", keyid_hex, private_only, pEp_status_to_string(status));
us@3209
   521
    return status;
us@3209
   522
}
us@3209
   523
us@3209
   524
// See tpk_find_by_keyid_hex.
neal@3332
   525
PEP_STATUS tpk_find_by_keyid(PEP_SESSION, pgp_keyid_t, int, pgp_tpk_t *, int *)
us@3209
   526
    __attribute__((nonnull(1, 2)));
us@3209
   527
PEP_STATUS tpk_find_by_keyid(PEP_SESSION session,
neal@3332
   528
                             pgp_keyid_t keyid, int private_only,
neal@3332
   529
                             pgp_tpk_t *tpkp, int *secretp)
neal@3191
   530
{
neal@3332
   531
    char *keyid_hex = pgp_keyid_to_hex(keyid);
neal@3191
   532
    if (! keyid_hex)
neal@3191
   533
        return PEP_OUT_OF_MEMORY;
us@3209
   534
    PEP_STATUS status
us@3209
   535
        = tpk_find_by_keyid_hex(session, keyid_hex, private_only, tpkp, secretp);
neal@3191
   536
    free(keyid_hex);
neal@3191
   537
    return status;
neal@3191
   538
}
neal@3191
   539
us@3209
   540
// See tpk_find_by_keyid_hex.
neal@3332
   541
static PEP_STATUS tpk_find_by_fpr(PEP_SESSION, pgp_fingerprint_t, int,
neal@3332
   542
                                  pgp_tpk_t *, int *)
neal@3191
   543
    __attribute__((nonnull(1, 2)));
us@3209
   544
static PEP_STATUS tpk_find_by_fpr(
neal@3332
   545
    PEP_SESSION session, pgp_fingerprint_t fpr, int private_only,
neal@3332
   546
    pgp_tpk_t *tpkp, int *secretp)
neal@3191
   547
{
neal@3332
   548
    pgp_keyid_t keyid = pgp_fingerprint_to_keyid(fpr);
neal@3191
   549
    if (! keyid)
neal@3191
   550
        return PEP_OUT_OF_MEMORY;
us@3209
   551
    PEP_STATUS status
us@3209
   552
        = tpk_find_by_keyid(session, keyid, private_only, tpkp, secretp);
neal@3332
   553
    pgp_keyid_free(keyid);
neal@3191
   554
    return status;
neal@3191
   555
}
neal@3191
   556
us@3209
   557
// See tpk_find_by_keyid_hex.
neal@3332
   558
static PEP_STATUS tpk_find_by_fpr_hex(PEP_SESSION, const char *, int, pgp_tpk_t *, int *secret)
neal@3191
   559
    __attribute__((nonnull(1, 2)));
us@3209
   560
static PEP_STATUS tpk_find_by_fpr_hex(
us@3209
   561
    PEP_SESSION session, const char *fpr, int private_only,
neal@3332
   562
    pgp_tpk_t *tpkp, int *secretp)
neal@3191
   563
{
neal@3332
   564
    pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(fpr);
neal@3332
   565
    if (! pgp_fpr)
neal@3191
   566
        return PEP_OUT_OF_MEMORY;
us@3209
   567
    PEP_STATUS status
neal@3332
   568
        = tpk_find_by_fpr(session, pgp_fpr, private_only, tpkp, secretp);
neal@3332
   569
    pgp_fingerprint_free(pgp_fpr);
neal@3191
   570
    return status;
neal@3191
   571
}
neal@3191
   572
us@3209
   573
// Returns all known TPKs.
neal@3332
   574
static PEP_STATUS tpk_all(PEP_SESSION, int, pgp_tpk_t **, int *) __attribute__((nonnull));
us@3209
   575
static PEP_STATUS tpk_all(PEP_SESSION session, int private_only,
neal@3332
   576
                          pgp_tpk_t **tpksp, int *tpks_countp) {
us@3209
   577
    PEP_STATUS status = PEP_STATUS_OK;
neal@3212
   578
    sqlite3_stmt *stmt = private_only ? session->sq_sql.tsk_all : session->sq_sql.tpk_all;
us@3209
   579
    status = key_loadn(session, stmt, tpksp, tpks_countp);
neal@3332
   580
    ERROR_OUT(NULL, status, "loading TPKs");
us@3209
   581
 out:
us@3209
   582
    sqlite3_reset(stmt);
us@3209
   583
    return status;
us@3209
   584
}
neal@3191
   585
us@3209
   586
// Returns keys that have a user id that matches the specified pattern.
neal@3191
   587
//
neal@3332
   588
// The keys returned must be freed using pgp_tpk_free.
neal@3332
   589
static PEP_STATUS tpk_find_by_email(PEP_SESSION, const char *, int, pgp_tpk_t **, int *)
us@3209
   590
    __attribute__((nonnull));
us@3209
   591
static PEP_STATUS tpk_find_by_email(PEP_SESSION session,
us@3209
   592
                                    const char *pattern, int private_only,
neal@3332
   593
                                    pgp_tpk_t **tpksp, int *countp)
us@3209
   594
{
us@3209
   595
    PEP_STATUS status = PEP_STATUS_OK;
us@3209
   596
    T("(%s)", pattern);
us@3209
   597
us@3209
   598
    sqlite3_stmt *stmt
neal@3212
   599
        = private_only ? session->sq_sql.tsk_find_by_email : session->sq_sql.tpk_find_by_email;
us@3209
   600
    sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_STATIC);
us@3209
   601
us@3209
   602
    status = key_loadn(session, stmt, tpksp, countp);
neal@3332
   603
    ERROR_OUT(NULL, status, "Searching for '%s'", pattern);
us@3209
   604
us@3209
   605
 out:
us@3209
   606
    sqlite3_reset(stmt);
vb@3621
   607
    T("(%s) -> %s (%d results)", pattern, pEp_status_to_string(status), *countp);
us@3209
   608
    return status;
us@3209
   609
}
us@3209
   610
us@3209
   611
us@3209
   612
// Saves the specified TPK.
us@3209
   613
//
us@3209
   614
// This function takes ownership of TPK.
neal@3332
   615
static PEP_STATUS tpk_save(PEP_SESSION, pgp_tpk_t, identity_list **)
us@3209
   616
    __attribute__((nonnull(1, 2)));
neal@3332
   617
static PEP_STATUS tpk_save(PEP_SESSION session, pgp_tpk_t tpk,
us@3209
   618
                           identity_list **private_idents)
neal@3191
   619
{
neal@3191
   620
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
   621
    pgp_error_t err = NULL;
neal@3332
   622
    pgp_fingerprint_t pgp_fpr = NULL;
neal@3191
   623
    char *fpr = NULL;
neal@3191
   624
    void *tsk_buffer = NULL;
neal@3191
   625
    size_t tsk_buffer_len = 0;
neal@3191
   626
    int tried_commit = 0;
neal@3332
   627
    pgp_tpk_key_iter_t key_iter = NULL;
neal@3332
   628
    pgp_user_id_binding_iter_t user_id_iter = NULL;
neal@3650
   629
    char *email = NULL;
neal@3650
   630
    char *name = NULL;
neal@3191
   631
neal@3368
   632
    sqlite3_stmt *stmt = session->sq_sql.begin_transaction;
neal@3368
   633
    int sqlite_result = sqlite3_step(stmt);
neal@3368
   634
    sqlite3_reset(stmt);
neal@3368
   635
    if (sqlite_result != SQLITE_DONE)
neal@3368
   636
        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
neal@3368
   637
                  "begin transaction failed: %s",
neal@3368
   638
                  sqlite3_errmsg(session->key_db));
neal@3368
   639
neal@3332
   640
    pgp_fpr = pgp_tpk_fingerprint(tpk);
neal@3332
   641
    fpr = pgp_fingerprint_to_hex(pgp_fpr);
us@3209
   642
    T("(%s, private_idents: %s)", fpr, private_idents ? "yes" : "no");
neal@3191
   643
us@3209
   644
    // Merge any existing data into TPK.
neal@3332
   645
    pgp_tpk_t current = NULL;
neal@3332
   646
    status = tpk_find(session, pgp_fpr, false, &current, NULL);
neal@3191
   647
    if (status == PEP_KEY_NOT_FOUND)
neal@3191
   648
        status = PEP_STATUS_OK;
neal@3191
   649
    else
neal@3332
   650
        ERROR_OUT(NULL, status, "Looking up %s", fpr);
neal@3332
   651
    if (current) {
neal@3332
   652
        tpk = pgp_tpk_merge(&err, tpk, current);
neal@3332
   653
        if (! tpk)
neal@3332
   654
            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Merging TPKs");
neal@3332
   655
    }
neal@3191
   656
neal@3332
   657
    int is_tsk = pgp_tpk_is_tsk(tpk);
neal@3191
   658
neal@3191
   659
    // Serialize it.
neal@3332
   660
    pgp_writer_t writer = pgp_writer_alloc(&tsk_buffer, &tsk_buffer_len);
neal@3191
   661
    if (! writer)
neal@3332
   662
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
neal@3191
   663
neal@3332
   664
    pgp_status_t pgp_status;
neal@3643
   665
    pgp_tsk_t tsk = pgp_tpk_as_tsk(tpk);
neal@3332
   666
    pgp_status = pgp_tsk_serialize(&err, tsk, writer);
neal@3643
   667
    pgp_tsk_free(tsk);
neal@3332
   668
    //pgp_writer_free(writer);
neal@3332
   669
    if (pgp_status != 0)
neal@3332
   670
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Serializing TPK");
neal@3191
   671
neal@3191
   672
neal@3191
   673
    // Insert the TSK into the DB.
neal@3212
   674
    stmt = session->sq_sql.tpk_save_insert_primary;
neal@3191
   675
    sqlite3_bind_text(stmt, 1, fpr, -1, SQLITE_STATIC);
us@3209
   676
    sqlite3_bind_int(stmt, 2, is_tsk);
us@3209
   677
    sqlite3_bind_blob(stmt, 3, tsk_buffer, tsk_buffer_len, SQLITE_STATIC);
neal@3191
   678
neal@3191
   679
    sqlite_result = sqlite3_step(stmt);
neal@3191
   680
    sqlite3_reset(stmt);
neal@3191
   681
    if (sqlite_result != SQLITE_DONE)
neal@3332
   682
        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
us@3209
   683
                  "Saving TPK: %s", sqlite3_errmsg(session->key_db));
neal@3191
   684
neal@3191
   685
    // Insert the "subkeys" (the primary key and the subkeys).
neal@3212
   686
    stmt = session->sq_sql.tpk_save_insert_subkeys;
neal@3353
   687
    // This inserts all of the keys in the TPK, i.e., revoked and
neal@3353
   688
    // expired keys, which is what we want.
neal@3353
   689
    key_iter = pgp_tpk_key_iter_all(tpk);
neal@3332
   690
    pgp_key_t key;
neal@3332
   691
    while ((key = pgp_tpk_key_iter_next(key_iter, NULL, NULL))) {
neal@3332
   692
        pgp_keyid_t keyid = pgp_key_keyid(key);
neal@3332
   693
        char *keyid_hex = pgp_keyid_to_hex(keyid);
neal@3191
   694
        sqlite3_bind_text(stmt, 1, keyid_hex, -1, SQLITE_STATIC);
neal@3191
   695
        sqlite3_bind_text(stmt, 2, fpr, -1, SQLITE_STATIC);
neal@3191
   696
neal@3191
   697
        sqlite_result = sqlite3_step(stmt);
neal@3191
   698
        sqlite3_reset(stmt);
neal@3191
   699
        free(keyid_hex);
neal@3332
   700
        pgp_keyid_free(keyid);
neal@3191
   701
        if (sqlite_result != SQLITE_DONE) {
neal@3332
   702
            pgp_tpk_key_iter_free(key_iter);
neal@3332
   703
            ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
neal@3191
   704
                      "Updating subkeys: %s", sqlite3_errmsg(session->key_db));
neal@3191
   705
        }
neal@3191
   706
    }
neal@3332
   707
    pgp_tpk_key_iter_free(key_iter);
neal@3191
   708
    key_iter = NULL;
neal@3191
   709
us@3209
   710
    // Insert the "userids".
neal@3212
   711
    stmt = session->sq_sql.tpk_save_insert_userids;
neal@3332
   712
    user_id_iter = pgp_tpk_user_id_binding_iter(tpk);
neal@3332
   713
    pgp_user_id_binding_t binding;
us@3209
   714
    int first = 1;
neal@3332
   715
    while ((binding = pgp_user_id_binding_iter_next(user_id_iter))) {
neal@3650
   716
        char *user_id_value = pgp_user_id_binding_user_id(binding);
neal@3650
   717
        if (!user_id_value || !*user_id_value)
us@3209
   718
            continue;
us@3209
   719
us@3209
   720
        // Ignore bindings with a self-revocation certificate, but no
us@3209
   721
        // self-signature.
neal@3332
   722
        if (!pgp_user_id_binding_selfsig(binding)) {
neal@3650
   723
            free(user_id_value);
us@3209
   724
            continue;
us@3209
   725
        }
us@3209
   726
neal@3650
   727
        free(name);
neal@3650
   728
        name = NULL;
neal@3650
   729
        free(email);
neal@3650
   730
        email = NULL;
neal@3650
   731
neal@3650
   732
        pgp_packet_t userid = pgp_user_id_new (user_id_value);
neal@3650
   733
        pgp_user_id_name(NULL, userid, &name);
neal@3650
   734
        pgp_user_id_address(NULL, userid, &email);
neal@3650
   735
        pgp_packet_free(userid);
neal@3650
   736
        free(user_id_value);
us@3209
   737
us@3209
   738
        if (email) {
us@3209
   739
            T("  userid: %s", email);
us@3209
   740
us@3209
   741
            sqlite3_bind_text(stmt, 1, email, -1, SQLITE_STATIC);
us@3209
   742
            sqlite3_bind_text(stmt, 2, fpr, -1, SQLITE_STATIC);
us@3209
   743
us@3209
   744
            sqlite_result = sqlite3_step(stmt);
us@3209
   745
            sqlite3_reset(stmt);
us@3209
   746
us@3209
   747
            if (sqlite_result != SQLITE_DONE) {
neal@3332
   748
                pgp_user_id_binding_iter_free(user_id_iter);
neal@3332
   749
                ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
us@3209
   750
                          "Updating userids: %s", sqlite3_errmsg(session->key_db));
us@3209
   751
            }
us@3209
   752
        }
us@3209
   753
us@3209
   754
        if (first && private_idents && is_tsk) {
us@3209
   755
            first = 0;
us@3209
   756
us@3209
   757
            // Create an identity for the primary user id.
us@3209
   758
            pEp_identity *ident = new_identity(email, fpr, NULL, name);
us@3209
   759
            if (ident == NULL)
neal@3332
   760
                ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "new_identity");
us@3209
   761
us@3209
   762
            *private_idents = identity_list_add(*private_idents, ident);
us@3209
   763
            if (*private_idents == NULL)
neal@3332
   764
                ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "identity_list_add");
us@3209
   765
        }
us@3209
   766
us@3209
   767
    }
neal@3332
   768
    pgp_user_id_binding_iter_free(user_id_iter);
us@3209
   769
    user_id_iter = NULL;
us@3209
   770
neal@3191
   771
 out:
neal@3191
   772
    // Prevent ERROR_OUT from causing an infinite loop.
neal@3191
   773
    if (! tried_commit) {
neal@3191
   774
        tried_commit = 1;
neal@3191
   775
        stmt = status == PEP_STATUS_OK
neal@3212
   776
            ? session->sq_sql.commit_transaction
neal@3212
   777
            : session->sq_sql.rollback_transaction;
neal@3191
   778
        int sqlite_result = sqlite3_step(stmt);
neal@3191
   779
        sqlite3_reset(stmt);
neal@3191
   780
        if (sqlite_result != SQLITE_DONE)
neal@3332
   781
            ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
neal@3191
   782
                      status == PEP_STATUS_OK
neal@3191
   783
                      ? "commit failed: %s" : "rollback failed: %s",
neal@3191
   784
                      sqlite3_errmsg(session->key_db));
neal@3191
   785
    }
neal@3191
   786
vb@3621
   787
    T("(%s) -> %s", fpr, pEp_status_to_string(status));
neal@3191
   788
neal@3650
   789
    free(email);
neal@3650
   790
    free(name);
us@3209
   791
    if (user_id_iter)
neal@3332
   792
        pgp_user_id_binding_iter_free(user_id_iter);
neal@3191
   793
    if (key_iter)
neal@3332
   794
        pgp_tpk_key_iter_free(key_iter);
neal@3191
   795
    if (stmt)
neal@3191
   796
      sqlite3_reset(stmt);
neal@3191
   797
    free(tsk_buffer);
us@3209
   798
    if (tpk)
neal@3332
   799
        pgp_tpk_free(tpk);
neal@3191
   800
    free(fpr);
neal@3332
   801
    pgp_fingerprint_free(pgp_fpr);
neal@3191
   802
neal@3191
   803
    return status;
neal@3191
   804
}
neal@3191
   805
neal@3191
   806
struct decrypt_cookie {
neal@3191
   807
    PEP_SESSION session;
neal@3191
   808
    int get_secret_keys_called;
neal@3191
   809
    stringlist_t *recipient_keylist;
neal@3191
   810
    stringlist_t *signer_keylist;
neal@3191
   811
    int good_checksums;
neal@3191
   812
    int missing_keys;
neal@3191
   813
    int bad_checksums;
neal@3191
   814
    int decrypted;
neal@3191
   815
};
neal@3191
   816
neal@3332
   817
static pgp_status_t
neal@3191
   818
get_public_keys_cb(void *cookie_raw,
neal@3332
   819
                   pgp_keyid_t *keyids, size_t keyids_len,
neal@3332
   820
                   pgp_tpk_t **tpks, size_t *tpk_len,
neal@3191
   821
                   void (**our_free)(void *))
neal@3191
   822
{
neal@3191
   823
    struct decrypt_cookie *cookie = cookie_raw;
neal@3191
   824
    PEP_SESSION session = cookie->session;
neal@3191
   825
neal@3191
   826
    *tpks = calloc(keyids_len, sizeof(*tpks));
neal@3191
   827
    if (!*tpks)
neal@3332
   828
        return PGP_STATUS_UNKNOWN_ERROR;
neal@3191
   829
    *our_free = free;
neal@3191
   830
neal@3191
   831
    int i, j;
neal@3191
   832
    j = 0;
neal@3191
   833
    for (i = 0; i < keyids_len; i ++) {
neal@3332
   834
        pgp_tpk_t tpk = NULL;
vb@3567
   835
        PEP_STATUS status
us@3209
   836
            = tpk_find_by_keyid(session, keyids[i], false, &tpk, NULL);
vb@3567
   837
        if (status == PEP_STATUS_OK)
neal@3191
   838
            (*tpks)[j ++] = tpk;
neal@3191
   839
    }
neal@3191
   840
    *tpk_len = j;
neal@3332
   841
    return PGP_STATUS_SUCCESS;
neal@3191
   842
}
neal@3191
   843
neal@3332
   844
static pgp_status_t
neal@3643
   845
decrypt_cb(void *cookie_opaque,
neal@3643
   846
           pgp_pkesk_t *pkesks, size_t pkesk_count,
neal@3643
   847
           pgp_skesk_t *skesks, size_t skesk_count,
neal@3643
   848
           pgp_decryptor_do_decrypt_cb_t *decrypt,
neal@3643
   849
           void *decrypt_cookie,
neal@3643
   850
           pgp_fingerprint_t *identity_out)
neal@3191
   851
{
neal@3332
   852
    pgp_error_t err = NULL;
neal@3191
   853
    struct decrypt_cookie *cookie = cookie_opaque;
neal@3191
   854
    PEP_SESSION session = cookie->session;
neal@3332
   855
    pgp_tpk_t *tsks = NULL;
neal@3191
   856
    int tsks_count = 0;
neal@3191
   857
    int wildcards = 0;
neal@3191
   858
neal@3191
   859
    if (cookie->get_secret_keys_called)
neal@3191
   860
        // Prevent iterations, which isn't needed since we don't
neal@3191
   861
        // support SKESKs.
neal@3332
   862
        return PGP_STATUS_UNKNOWN_ERROR;
neal@3191
   863
    cookie->get_secret_keys_called = 1;
neal@3191
   864
neal@3191
   865
    T("%zd PKESKs", pkesk_count);
neal@3191
   866
neal@3191
   867
    for (int i = 0; i < pkesk_count; i ++) {
neal@3332
   868
        pgp_pkesk_t pkesk = pkesks[i];
neal@3332
   869
        pgp_keyid_t keyid = pgp_pkesk_recipient(pkesk); /* Reference. */
neal@3332
   870
        char *keyid_str = pgp_keyid_to_hex(keyid);
neal@3332
   871
        pgp_tpk_key_iter_t key_iter = NULL;
neal@3643
   872
        pgp_session_key_t sk = NULL;
neal@3191
   873
neal@3191
   874
        T("Considering PKESK for %s", keyid_str);
neal@3191
   875
neal@3191
   876
        if (strcmp(keyid_str, "0000000000000000") == 0) {
neal@3191
   877
            // Initially ignore wildcards.
neal@3191
   878
            wildcards = 1;
neal@3191
   879
            goto eol;
neal@3191
   880
        }
neal@3191
   881
neal@3191
   882
        // Collect the recipients.  Note: we must return the primary
neal@3191
   883
        // key's fingerprint.
neal@3332
   884
        pgp_tpk_t tpk = NULL;
us@3209
   885
        int is_tsk = 0;
us@3209
   886
        if (tpk_find_by_keyid(session, keyid, false, &tpk, &is_tsk) != PEP_STATUS_OK)
us@3209
   887
            goto eol;
us@3209
   888
neal@3332
   889
        pgp_fingerprint_t fp = pgp_tpk_fingerprint(tpk);
neal@3332
   890
        char *fp_string = pgp_fingerprint_to_hex(fp);
us@3209
   891
        stringlist_add_unique(cookie->recipient_keylist, fp_string);
us@3209
   892
        free(fp_string);
neal@3332
   893
        pgp_fingerprint_free(fp);
neal@3191
   894
neal@3191
   895
        if (cookie->decrypted)
neal@3191
   896
            goto eol;
neal@3191
   897
neal@3191
   898
        // See if we have the secret key.
neal@3332
   899
        assert(is_tsk == pgp_tpk_is_tsk(tpk));
us@3209
   900
        if (! is_tsk)
neal@3191
   901
            goto eol;
neal@3191
   902
neal@3353
   903
        key_iter = pgp_tpk_key_iter_all(tpk);
neal@3332
   904
        pgp_key_t key;
neal@3332
   905
        while ((key = pgp_tpk_key_iter_next(key_iter, NULL, NULL))) {
neal@3332
   906
            pgp_keyid_t this_keyid = pgp_key_keyid(key);
neal@3332
   907
            char *this_keyid_hex = pgp_keyid_to_hex(this_keyid);
neal@3332
   908
            pgp_keyid_free(this_keyid);
neal@3191
   909
neal@3191
   910
            int match = strcmp(keyid_str, this_keyid_hex) == 0;
neal@3191
   911
            free(this_keyid_hex);
neal@3191
   912
            if (match)
neal@3191
   913
                break;
neal@3191
   914
        }
neal@3191
   915
us@3209
   916
        if (key == NULL) {
neal@3191
   917
            assert(!"Inconsistent DB: key doesn't contain a subkey with keyid!");
us@3209
   918
            goto eol;
us@3209
   919
        }
neal@3191
   920
neal@3191
   921
        uint8_t algo;
neal@3191
   922
        uint8_t session_key[1024];
neal@3191
   923
        size_t session_key_len = sizeof(session_key);
neal@3332
   924
        if (pgp_pkesk_decrypt(&err, pkesk, key, &algo,
neal@3332
   925
                              session_key, &session_key_len) != 0) {
neal@3332
   926
            DUMP_ERR(err, PEP_UNKNOWN_ERROR, "pgp_pkesk_decrypt");
neal@3191
   927
            goto eol;
neal@3191
   928
        }
neal@3191
   929
neal@3643
   930
        sk = pgp_session_key_from_bytes (session_key, session_key_len);
neal@3643
   931
        pgp_status_t status;
neal@3643
   932
        if ((status = decrypt (decrypt_cookie, algo, sk))) {
neal@3643
   933
            DUMP_STATUS(status, PEP_UNKNOWN_ERROR, "decrypt_cb");
neal@3643
   934
            goto eol;
neal@3643
   935
        }
neal@3643
   936
neal@3191
   937
        T("Decrypted PKESK for %s", keyid_str);
neal@3191
   938
neal@3643
   939
        *identity_out = pgp_tpk_fingerprint(tpk);
neal@3191
   940
        cookie->decrypted = 1;
neal@3191
   941
neal@3191
   942
    eol:
neal@3643
   943
        if (sk)
neal@3643
   944
            pgp_session_key_free (sk);
neal@3191
   945
        free(keyid_str);
neal@3191
   946
        if (key_iter)
neal@3332
   947
            pgp_tpk_key_iter_free(key_iter);
us@3209
   948
        if (tpk)
neal@3332
   949
            pgp_tpk_free(tpk);
neal@3191
   950
    }
neal@3191
   951
neal@3191
   952
    // Consider wildcard recipients.
neal@3191
   953
    if (wildcards) for (int i = 0; i < pkesk_count && !cookie->decrypted; i ++) {
neal@3332
   954
        pgp_pkesk_t pkesk = pkesks[i];
neal@3332
   955
        pgp_keyid_t keyid = pgp_pkesk_recipient(pkesk); /* Reference. */
neal@3332
   956
        char *keyid_str = pgp_keyid_to_hex(keyid);
neal@3332
   957
        pgp_tpk_key_iter_t key_iter = NULL;
neal@3643
   958
        pgp_session_key_t sk = NULL;
neal@3191
   959
neal@3191
   960
        if (strcmp(keyid_str, "0000000000000000") != 0)
neal@3191
   961
            goto eol2;
neal@3191
   962
neal@3191
   963
        if (!tsks) {
us@3209
   964
            if (tpk_all(session, true, &tsks, &tsks_count) != PEP_STATUS_OK) {
neal@3332
   965
                DUMP_ERR(NULL, PEP_UNKNOWN_ERROR, "Getting all tsks");
neal@3191
   966
            }
neal@3191
   967
        }
neal@3191
   968
neal@3191
   969
        for (int j = 0; j < tsks_count; j ++) {
neal@3332
   970
            pgp_tpk_t tsk = tsks[j];
neal@3191
   971
neal@3353
   972
            key_iter = pgp_tpk_key_iter_all(tsk);
neal@3332
   973
            pgp_key_t key;
neal@3332
   974
            pgp_signature_t selfsig;
neal@3332
   975
            while ((key = pgp_tpk_key_iter_next(key_iter, &selfsig, NULL))) {
neal@3332
   976
                if (! (pgp_signature_can_encrypt_at_rest(selfsig)
neal@3332
   977
                       || pgp_signature_can_encrypt_for_transport(selfsig)))
neal@3191
   978
                    continue;
neal@3191
   979
neal@3332
   980
                fprintf(stderr, "key: %s\n", pgp_key_debug(key));
neal@3332
   981
neal@3191
   982
                // Note: for decryption to appear to succeed, we must
neal@3191
   983
                // get a valid algorithm (8 of 256 values) and a
neal@3191
   984
                // 16-bit checksum must match.  Thus, we have about a
neal@3191
   985
                // 1 in 2**21 chance of having a false positive here.
neal@3191
   986
                uint8_t algo;
neal@3191
   987
                uint8_t session_key[1024];
neal@3191
   988
                size_t session_key_len = sizeof(session_key);
neal@3332
   989
                if (pgp_pkesk_decrypt(&err, pkesk, key,
neal@3332
   990
                                      &algo, session_key, &session_key_len)) {
neal@3332
   991
                    pgp_error_free(err);
neal@3332
   992
                    err = NULL;
neal@3191
   993
                    continue;
neal@3332
   994
                }
neal@3191
   995
neal@3191
   996
                // Add it to the recipient list.
neal@3332
   997
                pgp_fingerprint_t fp = pgp_tpk_fingerprint(tsk);
neal@3332
   998
                char *fp_string = pgp_fingerprint_to_hex(fp);
neal@3191
   999
                T("wildcard recipient appears to be %s", fp_string);
neal@3191
  1000
                stringlist_add_unique(cookie->recipient_keylist, fp_string);
neal@3191
  1001
                free(fp_string);
neal@3332
  1002
                pgp_fingerprint_free(fp);
neal@3191
  1003
neal@3643
  1004
                pgp_session_key_t sk = pgp_session_key_from_bytes (session_key,
neal@3643
  1005
                                                                   session_key_len);
neal@3643
  1006
                pgp_status_t status;
neal@3643
  1007
                if ((status = decrypt (decrypt_cookie, algo, sk))) {
neal@3643
  1008
                    DUMP_STATUS(status, PEP_UNKNOWN_ERROR, "decrypt_cb");
neal@3643
  1009
                    goto eol2;
neal@3643
  1010
                }
neal@3643
  1011
neal@3643
  1012
                *identity_out = pgp_tpk_fingerprint(tsk);
neal@3191
  1013
                cookie->decrypted = 1;
neal@3643
  1014
neal@3371
  1015
                break;
neal@3191
  1016
            }
neal@3191
  1017
neal@3332
  1018
            pgp_tpk_key_iter_free(key_iter);
neal@3191
  1019
            key_iter = NULL;
neal@3191
  1020
        }
neal@3191
  1021
    eol2:
neal@3643
  1022
        if (sk)
neal@3643
  1023
            pgp_session_key_free (sk);
neal@3191
  1024
        free(keyid_str);
neal@3191
  1025
        if (key_iter)
neal@3332
  1026
            pgp_tpk_key_iter_free(key_iter);
neal@3191
  1027
    }
neal@3191
  1028
neal@3191
  1029
    if (tsks) {
neal@3191
  1030
        for (int i = 0; i < tsks_count; i ++)
neal@3332
  1031
            pgp_tpk_free(tsks[i]);
neal@3191
  1032
        free(tsks);
neal@3191
  1033
    }
neal@3191
  1034
neal@3332
  1035
    return cookie->decrypted ? PGP_STATUS_SUCCESS : PGP_STATUS_UNKNOWN_ERROR;
neal@3191
  1036
}
neal@3191
  1037
neal@3332
  1038
static pgp_status_t
neal@3659
  1039
check_signatures_cb(void *cookie_opaque, pgp_message_structure_t structure)
neal@3191
  1040
{
neal@3191
  1041
    struct decrypt_cookie *cookie = cookie_opaque;
neal@3191
  1042
    PEP_SESSION session = cookie->session;
neal@3191
  1043
neal@3659
  1044
    pgp_message_structure_iter_t iter
neal@3659
  1045
        = pgp_message_structure_iter (structure);
neal@3659
  1046
    for (pgp_message_layer_t layer = pgp_message_structure_iter_next (iter);
neal@3659
  1047
         layer;
neal@3659
  1048
         layer = pgp_message_structure_iter_next (iter)) {
neal@3659
  1049
        pgp_verification_result_iter_t results;
neal@3191
  1050
neal@3659
  1051
        switch (pgp_message_layer_variant (layer)) {
neal@3659
  1052
        case PGP_MESSAGE_LAYER_COMPRESSION:
neal@3659
  1053
        case PGP_MESSAGE_LAYER_ENCRYPTION:
neal@3659
  1054
            break;
neal@3191
  1055
neal@3659
  1056
        case PGP_MESSAGE_LAYER_SIGNATURE_GROUP:
neal@3659
  1057
            pgp_message_layer_signature_group(layer, &results);
neal@3659
  1058
            pgp_verification_result_t result;
neal@3659
  1059
            while ((result = pgp_verification_result_iter_next (results))) {
neal@3659
  1060
                pgp_signature_t sig;
neal@3659
  1061
                pgp_keyid_t keyid = NULL;
neal@3659
  1062
                char *keyid_str = NULL;
neal@3659
  1063
neal@3659
  1064
                switch (pgp_verification_result_variant (result)) {
neal@3659
  1065
                case PGP_VERIFICATION_RESULT_GOOD_CHECKSUM:
neal@3659
  1066
                    // We need to add the fingerprint of the primary
neal@3659
  1067
                    // key to cookie->signer_keylist.
neal@3659
  1068
neal@3659
  1069
                    pgp_verification_result_good_checksum (result, &sig, NULL,
neal@3659
  1070
                                                           NULL, NULL, NULL);
neal@3659
  1071
neal@3659
  1072
                    // First try looking up by the TPK using the
neal@3659
  1073
                    // IssuerFingerprint subpacket.
neal@3659
  1074
                    pgp_fingerprint_t fpr
neal@3659
  1075
                        = pgp_signature_issuer_fingerprint(sig);
neal@3659
  1076
                    if (fpr) {
neal@3659
  1077
                        // Even though we have a fingerprint, we have
neal@3659
  1078
                        // to look the key up by keyid, because we
neal@3659
  1079
                        // want to match on subkeys and we only store
neal@3659
  1080
                        // keyids for subkeys.
neal@3659
  1081
                        keyid = pgp_fingerprint_to_keyid(fpr);
neal@3659
  1082
                        pgp_fingerprint_free(fpr);
neal@3659
  1083
                    } else {
neal@3659
  1084
                        // That is not available, try using the Issuer
neal@3659
  1085
                        // subpacket.
neal@3659
  1086
                        keyid = pgp_signature_issuer(sig);
neal@3659
  1087
                    }
neal@3659
  1088
neal@3659
  1089
                    if (! keyid) {
neal@3659
  1090
                        T("signature with no Issuer or Issuer Fingerprint subpacket!");
neal@3659
  1091
                        goto eol;
neal@3659
  1092
                    }
neal@3659
  1093
neal@3659
  1094
                    pgp_tpk_t tpk;
neal@3659
  1095
                    if (tpk_find_by_keyid(session, keyid, false,
neal@3659
  1096
                                          &tpk, NULL) != PEP_STATUS_OK)
neal@3659
  1097
                        ; // Soft error.  Ignore.
neal@3659
  1098
neal@3659
  1099
                    if (tpk) {
neal@3659
  1100
                        // Ok, we have a TPK.
neal@3659
  1101
neal@3659
  1102
                        // We need the primary key's fingerprint (not
neal@3659
  1103
                        // the issuer fingerprint).
neal@3659
  1104
                        pgp_fingerprint_t primary_fpr
neal@3659
  1105
                            = pgp_tpk_fingerprint(tpk);
neal@3659
  1106
                        char *primary_fpr_str
neal@3659
  1107
                            = pgp_fingerprint_to_hex(primary_fpr);
neal@3659
  1108
                        stringlist_add_unique(cookie->signer_keylist,
neal@3659
  1109
                                              primary_fpr_str);
neal@3659
  1110
neal@3659
  1111
                        T("Good signature from %s", primary_fpr_str);
neal@3659
  1112
neal@3659
  1113
                        // XXX: Check that the TPK and the key used to make
neal@3659
  1114
                        // the signature and the signature itself are alive
neal@3659
  1115
                        // and not revoked.  Revoked =>
neal@3659
  1116
                        // PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH; Expired key
neal@3659
  1117
                        // or sig => PEP_DECRYPTED.
neal@3659
  1118
                        cookie->good_checksums ++;
neal@3659
  1119
neal@3659
  1120
                        free(primary_fpr_str);
neal@3659
  1121
                        pgp_fingerprint_free(primary_fpr);
neal@3659
  1122
                        pgp_tpk_free(tpk);
neal@3659
  1123
                    } else {
neal@3659
  1124
                        // If we get
neal@3659
  1125
                        // PGP_VERIFICATION_RESULT_CODE_GOOD_CHECKSUM, then the
neal@3659
  1126
                        // TPK should be available.  But, another process
neal@3659
  1127
                        // could have deleted the key from the store in the
neal@3659
  1128
                        // mean time, so be tolerant.
neal@3659
  1129
                        T("Key to check signature from %s disappeared",
neal@3659
  1130
                          keyid_str);
neal@3659
  1131
                        cookie->missing_keys ++;
neal@3659
  1132
                    }
neal@3659
  1133
                    break;
neal@3659
  1134
neal@3659
  1135
                case PGP_VERIFICATION_RESULT_MISSING_KEY:
neal@3659
  1136
                    pgp_verification_result_missing_key (result, &sig);
neal@3659
  1137
                    keyid = pgp_signature_issuer (sig);
neal@3659
  1138
                    keyid_str = pgp_keyid_to_string (keyid);
neal@3659
  1139
                    T("No key to check signature from %s", keyid_str);
neal@3659
  1140
neal@3659
  1141
                    cookie->missing_keys ++;
neal@3659
  1142
                    break;
neal@3659
  1143
neal@3659
  1144
                case PGP_VERIFICATION_RESULT_BAD_CHECKSUM:
neal@3659
  1145
                    pgp_verification_result_bad_checksum (result, &sig);
neal@3659
  1146
                    keyid = pgp_signature_issuer (sig);
neal@3659
  1147
                    if (keyid) {
neal@3659
  1148
                        keyid_str = pgp_keyid_to_string (keyid);
neal@3659
  1149
                        T("Bad signature from %s", keyid_str);
neal@3659
  1150
                    } else {
neal@3659
  1151
                        T("Bad signature without issuer information");
neal@3659
  1152
                    }
neal@3659
  1153
neal@3659
  1154
                    cookie->bad_checksums ++;
neal@3659
  1155
                    break;
neal@3659
  1156
neal@3659
  1157
                default:
neal@3659
  1158
                    assert (! "reachable");
neal@3659
  1159
                }
neal@3659
  1160
neal@3659
  1161
            eol:
neal@3659
  1162
                free (keyid_str);
neal@3659
  1163
                pgp_signature_free (sig);
neal@3659
  1164
                pgp_verification_result_free (result);
neal@3191
  1165
            }
neal@3659
  1166
            pgp_verification_result_iter_free (results);
neal@3659
  1167
            break;
neal@3191
  1168
neal@3659
  1169
        default:
neal@3659
  1170
            assert (! "reachable");
neal@3659
  1171
        }
neal@3191
  1172
neal@3659
  1173
        pgp_message_layer_free (layer);
neal@3659
  1174
    }
neal@3191
  1175
neal@3659
  1176
    pgp_message_structure_iter_free (iter);
neal@3659
  1177
    pgp_message_structure_free (structure);
neal@3191
  1178
neal@3332
  1179
    return PGP_STATUS_SUCCESS;
neal@3191
  1180
}
neal@3191
  1181
neal@3191
  1182
PEP_STATUS pgp_decrypt_and_verify(
neal@3191
  1183
    PEP_SESSION session, const char *ctext, size_t csize,
neal@3191
  1184
    const char *dsigtext, size_t dsigsize,
neal@3191
  1185
    char **ptext, size_t *psize, stringlist_t **keylist,
neal@3191
  1186
    char** filename_ptr)
neal@3191
  1187
{
neal@3191
  1188
    PEP_STATUS status = PEP_STATUS_OK;
neal@3191
  1189
    struct decrypt_cookie cookie = { session, 0, NULL, NULL, 0, 0, 0, };
neal@3332
  1190
    pgp_reader_t reader = NULL;
neal@3332
  1191
    pgp_writer_t writer = NULL;
neal@3378
  1192
    pgp_reader_t decryptor = NULL;
neal@3191
  1193
    *ptext = NULL;
neal@3191
  1194
    *psize = 0;
neal@3191
  1195
neal@3191
  1196
    // XXX: We don't yet handle detached signatures over encrypted
neal@3191
  1197
    // messages.
neal@3191
  1198
    assert(!dsigtext);
neal@3191
  1199
neal@3191
  1200
    cookie.recipient_keylist = new_stringlist(NULL);
neal@3191
  1201
    if (!cookie.recipient_keylist)
neal@3332
  1202
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "recipient_keylist");
neal@3191
  1203
neal@3191
  1204
    cookie.signer_keylist = new_stringlist(NULL);
neal@3191
  1205
    if (!cookie.signer_keylist)
neal@3332
  1206
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "signer_keylist");
neal@3191
  1207
neal@3332
  1208
    reader = pgp_reader_from_bytes((const uint8_t *) ctext, csize);
neal@3191
  1209
    if (! reader)
neal@3332
  1210
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "Creating reader");
neal@3191
  1211
neal@3332
  1212
    writer = pgp_writer_alloc((void **) ptext, psize);
neal@3191
  1213
    if (! writer)
neal@3332
  1214
        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR, "Creating writer");
neal@3191
  1215
neal@3332
  1216
    pgp_error_t err = NULL;
neal@3378
  1217
    decryptor = pgp_decryptor_new(&err, reader,
neal@3643
  1218
                                  get_public_keys_cb, decrypt_cb,
neal@3643
  1219
                                  check_signatures_cb, &cookie, 0);
neal@3378
  1220
    if (! decryptor)
neal@3378
  1221
        ERROR_OUT(err, PEP_DECRYPT_NO_KEY, "pgp_decryptor_new");
neal@3378
  1222
neal@3378
  1223
    // Copy 128 MB at a time.
neal@3378
  1224
    ssize_t nread;
neal@3378
  1225
    while ((nread = pgp_reader_copy (&err, decryptor, writer,
neal@3378
  1226
                                     128 * 1024 * 1024) > 0))
neal@3378
  1227
        ;
neal@3378
  1228
    if (nread < 0)
vb@3567
  1229
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "pgp_reader_read");
neal@3378
  1230
neal@3378
  1231
    // Add a terminating NUL for naive users
neal@3378
  1232
    pgp_writer_write(&err, writer, (const uint8_t *) &""[0], 1);
neal@3191
  1233
neal@3191
  1234
    if (! cookie.decrypted)
neal@3332
  1235
        ERROR_OUT(err, PEP_DECRYPT_NO_KEY, "Decryption failed");
neal@3191
  1236
neal@3191
  1237
    if (! cookie.signer_keylist) {
neal@3191
  1238
        cookie.signer_keylist = new_stringlist("");
neal@3191
  1239
        if (! cookie.signer_keylist)
neal@3332
  1240
            ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "cookie.signer_keylist");
neal@3191
  1241
    }
neal@3191
  1242
    if (!cookie.signer_keylist->value)
neal@3191
  1243
        stringlist_add(cookie.signer_keylist, "");
neal@3191
  1244
neal@3191
  1245
    *keylist = cookie.signer_keylist;
neal@3191
  1246
    stringlist_append(*keylist, cookie.recipient_keylist);
neal@3191
  1247
neal@3191
  1248
 out:
neal@3191
  1249
    if (status == PEP_STATUS_OK) {
neal@3191
  1250
        if (cookie.bad_checksums) {
neal@3191
  1251
            // If there are any bad signatures, fail.
neal@3191
  1252
            status = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
neal@3191
  1253
        } else if (cookie.good_checksums) {
neal@3191
  1254
            // If there is at least one signature that we can verify,
neal@3191
  1255
            // succeed.
neal@3191
  1256
            status = PEP_DECRYPTED_AND_VERIFIED;
neal@3191
  1257
        } else {
neal@3191
  1258
            // We couldn't verify any signatures (possibly because we
neal@3191
  1259
            // don't have the keys).
neal@3191
  1260
            status = PEP_DECRYPTED;
neal@3191
  1261
        }
neal@3191
  1262
    } else {
neal@3191
  1263
        free_stringlist(cookie.recipient_keylist);
neal@3191
  1264
        free_stringlist(cookie.signer_keylist);
neal@3191
  1265
        free(*ptext);
neal@3191
  1266
    }
neal@3191
  1267
neal@3191
  1268
    if (reader)
neal@3332
  1269
        pgp_reader_free(reader);
neal@3378
  1270
    if (decryptor)
neal@3378
  1271
        pgp_reader_free(decryptor);
neal@3191
  1272
    if (writer)
neal@3332
  1273
        pgp_writer_free(writer);
neal@3191
  1274
vb@3621
  1275
    T("-> %s", pEp_status_to_string(status));
neal@3191
  1276
    return status;
neal@3191
  1277
}
neal@3191
  1278
neal@3191
  1279
PEP_STATUS pgp_verify_text(
neal@3191
  1280
    PEP_SESSION session, const char *text, size_t size,
neal@3191
  1281
    const char *signature, size_t sig_size, stringlist_t **keylist)
neal@3191
  1282
{
neal@3191
  1283
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  1284
    pgp_error_t err = NULL;
neal@3191
  1285
    struct decrypt_cookie cookie = { session, 0, NULL, NULL, 0, 0, 0, };
neal@3332
  1286
    pgp_reader_t reader = NULL;
neal@3332
  1287
    pgp_reader_t dsig_reader = NULL;
neal@3378
  1288
    pgp_reader_t verifier = NULL;
neal@3191
  1289
neal@3191
  1290
    if (size == 0 || sig_size == 0)
neal@3191
  1291
        return PEP_DECRYPT_WRONG_FORMAT;
neal@3191
  1292
neal@3191
  1293
    cookie.recipient_keylist = new_stringlist(NULL);
neal@3191
  1294
    if (!cookie.recipient_keylist)
neal@3332
  1295
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
neal@3191
  1296
neal@3191
  1297
    cookie.signer_keylist = new_stringlist(NULL);
neal@3191
  1298
    if (!cookie.signer_keylist)
neal@3332
  1299
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
neal@3191
  1300
neal@3332
  1301
    reader = pgp_reader_from_bytes((const uint8_t *) text, size);
neal@3191
  1302
    if (! reader)
neal@3332
  1303
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "Creating reader");
neal@3191
  1304
neal@3191
  1305
    dsig_reader = NULL;
neal@3191
  1306
    if (signature) {
neal@3332
  1307
        dsig_reader = pgp_reader_from_bytes((uint8_t *) signature, sig_size);
neal@3191
  1308
        if (! dsig_reader)
neal@3332
  1309
            ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "Creating signature reader");
neal@3191
  1310
    }
neal@3191
  1311
neal@3378
  1312
    if (dsig_reader)
neal@3378
  1313
        verifier = pgp_detached_verifier_new(&err, dsig_reader, reader,
neal@3378
  1314
                                             get_public_keys_cb,
neal@3378
  1315
                                             check_signatures_cb,
neal@3643
  1316
                                             &cookie, 0);
neal@3378
  1317
    else
neal@3378
  1318
        verifier = pgp_verifier_new(&err, reader,
neal@3378
  1319
                                    get_public_keys_cb,
neal@3378
  1320
                                    check_signatures_cb,
neal@3643
  1321
                                    &cookie, 0);
neal@3378
  1322
    if (! verifier)
neal@3378
  1323
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Creating verifier");
neal@3378
  1324
    if (pgp_reader_discard(&err, verifier) < 0)
neal@3378
  1325
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "verifier");
neal@3191
  1326
neal@3191
  1327
    if (! cookie.signer_keylist) {
neal@3191
  1328
        cookie.signer_keylist = new_stringlist("");
neal@3191
  1329
        if (! cookie.signer_keylist)
neal@3332
  1330
            ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "cookie.signer_keylist");
neal@3191
  1331
    }
neal@3191
  1332
    if (!cookie.signer_keylist->value)
neal@3191
  1333
        stringlist_add(cookie.signer_keylist, "");
neal@3191
  1334
neal@3191
  1335
    *keylist = cookie.signer_keylist;
neal@3191
  1336
    stringlist_append(*keylist, cookie.recipient_keylist);
neal@3191
  1337
neal@3191
  1338
 out:
neal@3191
  1339
    if (status == PEP_STATUS_OK) {
neal@3191
  1340
        if (cookie.bad_checksums) {
neal@3191
  1341
            // If there are any bad signatures, fail.
neal@3191
  1342
            status = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
neal@3191
  1343
        } else if (cookie.good_checksums) {
neal@3191
  1344
            // If there is at least one signature that we can verify,
neal@3191
  1345
            // succeed.
neal@3191
  1346
            status = PEP_VERIFIED;
neal@3191
  1347
        } else {
neal@3191
  1348
            // We couldn't verify any signatures (possibly because we
neal@3191
  1349
            // don't have the keys).
neal@3191
  1350
            status = PEP_UNENCRYPTED;
neal@3191
  1351
        }
neal@3191
  1352
    } else {
neal@3191
  1353
        free_stringlist(cookie.recipient_keylist);
neal@3191
  1354
        free_stringlist(cookie.signer_keylist);
neal@3191
  1355
    }
neal@3191
  1356
neal@3378
  1357
    if (verifier)
neal@3378
  1358
        pgp_reader_free(verifier);
neal@3191
  1359
    if (reader)
neal@3332
  1360
        pgp_reader_free(reader);
neal@3191
  1361
    if (dsig_reader)
neal@3332
  1362
        pgp_reader_free(dsig_reader);
neal@3191
  1363
vb@3621
  1364
    T("-> %s", pEp_status_to_string(status));
neal@3191
  1365
    return status;
neal@3191
  1366
}
neal@3191
  1367
neal@3191
  1368
neal@3191
  1369
PEP_STATUS pgp_sign_only(
neal@3191
  1370
    PEP_SESSION session, const char* fpr, const char *ptext,
neal@3191
  1371
    size_t psize, char **stext, size_t *ssize)
neal@3191
  1372
{
neal@3191
  1373
    assert(session);
neal@3191
  1374
    assert(fpr && fpr[0]);
neal@3191
  1375
    assert(ptext);
neal@3191
  1376
    assert(psize);
neal@3191
  1377
    assert(stext);
neal@3191
  1378
    assert(ssize);
neal@3354
  1379
    *stext = NULL;
neal@3354
  1380
    *ssize = 0;
neal@3191
  1381
neal@3191
  1382
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  1383
    pgp_error_t err = NULL;
neal@3356
  1384
    pgp_tpk_t signer_tpk = NULL;
neal@3356
  1385
    pgp_tpk_key_iter_t iter = NULL;
neal@3356
  1386
    pgp_key_pair_t signing_keypair = NULL;
neal@3356
  1387
    pgp_signer_t signer = NULL;
neal@3332
  1388
    pgp_writer_stack_t ws = NULL;
neal@3191
  1389
neal@3356
  1390
    status = tpk_find_by_fpr_hex(session, fpr, true, &signer_tpk, NULL);
neal@3332
  1391
    ERROR_OUT(NULL, status, "Looking up key '%s'", fpr);
neal@3191
  1392
neal@3356
  1393
    iter = pgp_tpk_key_iter_valid(signer_tpk);
neal@3356
  1394
    pgp_tpk_key_iter_signing_capable (iter);
neal@3356
  1395
    pgp_tpk_key_iter_unencrypted_secret (iter, true);
neal@3356
  1396
neal@3356
  1397
    // If there are multiple signing capable subkeys, we just take
neal@3356
  1398
    // the first one, whichever one that happens to be.
neal@3356
  1399
    pgp_key_t key = pgp_tpk_key_iter_next (iter, NULL, NULL);
neal@3356
  1400
    if (! key)
neal@3356
  1401
        ERROR_OUT (err, PEP_UNKNOWN_ERROR,
neal@3356
  1402
                   "%s has no signing capable key", fpr);
neal@3356
  1403
neal@3356
  1404
    signing_keypair = pgp_key_into_key_pair (NULL, pgp_key_clone (key));
neal@3356
  1405
    if (! signing_keypair)
neal@3356
  1406
        ERROR_OUT (err, PEP_UNKNOWN_ERROR, "Creating a keypair");
neal@3356
  1407
neal@3356
  1408
    signer = pgp_key_pair_as_signer (signing_keypair);
neal@3356
  1409
    if (! signer)
neal@3356
  1410
        ERROR_OUT (err, PEP_UNKNOWN_ERROR, "Creating a signer");
neal@3356
  1411
neal@3356
  1412
neal@3332
  1413
    pgp_writer_t writer = pgp_writer_alloc((void **) stext, ssize);
neal@3332
  1414
    writer = pgp_armor_writer_new(&err, writer,
neal@3332
  1415
                                  PGP_ARMOR_KIND_MESSAGE, NULL, 0);
neal@3191
  1416
    if (!writer)
neal@3332
  1417
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up armor writer");
neal@3191
  1418
neal@3332
  1419
    ws = pgp_writer_stack_message(writer);
neal@3191
  1420
neal@3369
  1421
    ws = pgp_signer_new_detached(&err, ws, &signer, 1, 0);
neal@3191
  1422
    if (!ws)
neal@3332
  1423
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up signer");
neal@3191
  1424
neal@3332
  1425
    pgp_status_t write_status =
neal@3332
  1426
        pgp_writer_stack_write_all (&err, ws,
neal@3332
  1427
                                    (uint8_t *) ptext, psize);
neal@3191
  1428
    if (write_status != 0)
neal@3332
  1429
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Encrypting message");
neal@3191
  1430
neal@3191
  1431
    // Add a terminating NUL for naive users
neal@3191
  1432
    void *t = realloc(*stext, *ssize + 1);
neal@3191
  1433
    if (! t)
neal@3332
  1434
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
neal@3191
  1435
    *stext = t;
neal@3191
  1436
    (*stext)[*ssize] = 0;
neal@3191
  1437
neal@3191
  1438
 out:
neal@3191
  1439
    if (ws) {
neal@3332
  1440
        pgp_status_t pgp_status = pgp_writer_stack_finalize (&err, ws);
neal@3191
  1441
        ws = NULL;
neal@3332
  1442
        if (pgp_status != 0)
neal@3332
  1443
            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Flushing writer");
neal@3191
  1444
    }
neal@3191
  1445
neal@3191
  1446
    if (signer)
neal@3356
  1447
        pgp_signer_free (signer);
neal@3356
  1448
    if (signing_keypair)
neal@3356
  1449
        pgp_key_pair_free (signing_keypair);
neal@3356
  1450
    if (iter)
neal@3356
  1451
        pgp_tpk_key_iter_free (iter);
neal@3356
  1452
    if (signer_tpk)
neal@3356
  1453
        pgp_tpk_free(signer_tpk);
neal@3191
  1454
vb@3621
  1455
    T("(%s)-> %s", fpr, pEp_status_to_string(status));
neal@3191
  1456
    return status;
neal@3191
  1457
}
neal@3191
  1458
neal@3191
  1459
static PEP_STATUS pgp_encrypt_sign_optional(
neal@3191
  1460
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
neal@3191
  1461
    size_t psize, char **ctext, size_t *csize, bool sign)
neal@3191
  1462
{
neal@3191
  1463
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  1464
    pgp_error_t err = NULL;
neal@3191
  1465
    int keys_count = 0;
neal@3332
  1466
    pgp_tpk_t *keys = NULL;
neal@3356
  1467
    pgp_tpk_t signer_tpk = NULL;
neal@3332
  1468
    pgp_writer_stack_t ws = NULL;
neal@3356
  1469
    pgp_tpk_key_iter_t iter = NULL;
neal@3356
  1470
    pgp_key_pair_t signing_keypair = NULL;
neal@3356
  1471
    pgp_signer_t signer = NULL;
neal@3191
  1472
neal@3191
  1473
    assert(session);
neal@3191
  1474
    assert(keylist);
neal@3191
  1475
    assert(ptext);
neal@3191
  1476
    assert(psize);
neal@3191
  1477
    assert(ctext);
neal@3191
  1478
    assert(csize);
neal@3191
  1479
neal@3191
  1480
    *ctext = NULL;
neal@3191
  1481
    *csize = 0;
neal@3191
  1482
neal@3191
  1483
    keys = calloc(stringlist_length(keylist), sizeof(*keys));
neal@3191
  1484
    if (keys == NULL)
neal@3332
  1485
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
neal@3191
  1486
neal@3191
  1487
    // Get the keys for the recipients.
neal@3191
  1488
    const stringlist_t *_keylist;
neal@3191
  1489
    for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
neal@3191
  1490
        assert(_keylist->value);
neal@3332
  1491
        pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(_keylist->value);
neal@3332
  1492
        status = tpk_find_by_fpr(session, pgp_fpr, false, &keys[keys_count ++], NULL);
neal@3332
  1493
        pgp_fingerprint_free(pgp_fpr);
neal@3332
  1494
        ERROR_OUT(NULL, status, "Looking up key for recipient '%s'", _keylist->value);
neal@3191
  1495
    }
neal@3191
  1496
neal@3191
  1497
    if (sign) {
neal@3191
  1498
        // The first key in the keylist is the signer.
neal@3356
  1499
        status = tpk_find_by_fpr_hex(session, keylist->value, true, &signer_tpk, NULL);
neal@3332
  1500
        ERROR_OUT(NULL, status, "Looking up key for signing '%s'", keylist->value);
neal@3191
  1501
    }
neal@3191
  1502
neal@3332
  1503
    pgp_writer_t writer = pgp_writer_alloc((void **) ctext, csize);
neal@3332
  1504
    writer = pgp_armor_writer_new(&err, writer,
neal@3332
  1505
                                  PGP_ARMOR_KIND_MESSAGE, NULL, 0);
neal@3191
  1506
    if (!writer)
neal@3332
  1507
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up armor writer");
neal@3191
  1508
neal@3332
  1509
    ws = pgp_writer_stack_message(writer);
neal@3332
  1510
    ws = pgp_encryptor_new (&err, ws,
neal@3369
  1511
                            NULL, 0, keys, keys_count,
neal@3369
  1512
                            PGP_ENCRYPTION_MODE_FOR_TRANSPORT, 0);
neal@3370
  1513
    if (!ws)
neal@3332
  1514
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up encryptor");
neal@3191
  1515
neal@3191
  1516
    if (sign) {
neal@3356
  1517
        iter = pgp_tpk_key_iter_valid(signer_tpk);
neal@3356
  1518
        pgp_tpk_key_iter_signing_capable (iter);
neal@3356
  1519
        pgp_tpk_key_iter_unencrypted_secret (iter, true);
neal@3356
  1520
neal@3356
  1521
        // If there are multiple signing capable subkeys, we just take
neal@3356
  1522
        // the first one, whichever one that happens to be.
neal@3356
  1523
        pgp_key_t key = pgp_tpk_key_iter_next (iter, NULL, NULL);
neal@3356
  1524
        if (! key)
neal@3356
  1525
            ERROR_OUT (err, PEP_UNKNOWN_ERROR,
neal@3356
  1526
                       "%s has no signing capable key", keylist->value);
neal@3356
  1527
neal@3356
  1528
        signing_keypair = pgp_key_into_key_pair (NULL, pgp_key_clone (key));
neal@3356
  1529
        if (! signing_keypair)
neal@3356
  1530
            ERROR_OUT (err, PEP_UNKNOWN_ERROR, "Creating a keypair");
neal@3356
  1531
neal@3356
  1532
        signer = pgp_key_pair_as_signer (signing_keypair);
neal@3356
  1533
        if (! signer)
neal@3356
  1534
            ERROR_OUT (err, PEP_UNKNOWN_ERROR, "Creating a signer");
neal@3332
  1535
neal@3369
  1536
        ws = pgp_signer_new(&err, ws, &signer, 1, 0);
neal@3191
  1537
        if (!ws)
neal@3332
  1538
            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up signer");
neal@3191
  1539
    }
neal@3191
  1540
neal@3332
  1541
    ws = pgp_literal_writer_new (&err, ws);
neal@3191
  1542
    if (!ws)
neal@3332
  1543
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Setting up literal writer");
neal@3191
  1544
neal@3332
  1545
    pgp_status_t write_status =
neal@3332
  1546
        pgp_writer_stack_write_all (&err, ws,
neal@3332
  1547
                                    (uint8_t *) ptext, psize);
neal@3191
  1548
    if (write_status != 0)
neal@3332
  1549
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Encrypting message");
neal@3191
  1550
neal@3191
  1551
    // Add a terminating NUL for naive users
neal@3191
  1552
    void *t = realloc(*ctext, *csize + 1);
neal@3191
  1553
    if (! t)
neal@3332
  1554
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
neal@3191
  1555
    *ctext = t;
neal@3191
  1556
    (*ctext)[*csize] = 0;
neal@3191
  1557
neal@3191
  1558
 out:
neal@3191
  1559
    if (ws) {
neal@3332
  1560
        pgp_status_t pgp_status = pgp_writer_stack_finalize (&err, ws);
neal@3191
  1561
        ws = NULL;
neal@3332
  1562
        if (pgp_status != 0)
neal@3332
  1563
            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Flushing writer");
neal@3191
  1564
    }
neal@3191
  1565
neal@3191
  1566
    if (signer)
neal@3356
  1567
        pgp_signer_free (signer);
neal@3356
  1568
    if (signing_keypair)
neal@3356
  1569
        pgp_key_pair_free (signing_keypair);
neal@3356
  1570
    if (iter)
neal@3356
  1571
        pgp_tpk_key_iter_free (iter);
neal@3356
  1572
    if (signer_tpk)
neal@3356
  1573
        pgp_tpk_free(signer_tpk);
neal@3356
  1574
neal@3191
  1575
    for (int i = 0; i < keys_count; i ++)
neal@3332
  1576
        pgp_tpk_free(keys[i]);
neal@3191
  1577
    free(keys);
neal@3191
  1578
vb@3621
  1579
    T("-> %s", pEp_status_to_string(status));
neal@3191
  1580
    return status;
neal@3191
  1581
}
neal@3191
  1582
neal@3191
  1583
PEP_STATUS pgp_encrypt_only(
neal@3191
  1584
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
neal@3191
  1585
    size_t psize, char **ctext, size_t *csize)
neal@3191
  1586
{
neal@3191
  1587
    return pgp_encrypt_sign_optional(session, keylist, ptext,
neal@3191
  1588
        psize, ctext, csize, false);
neal@3191
  1589
}
neal@3191
  1590
neal@3191
  1591
PEP_STATUS pgp_encrypt_and_sign(
neal@3191
  1592
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
neal@3191
  1593
    size_t psize, char **ctext, size_t *csize)
neal@3191
  1594
{
neal@3191
  1595
    return pgp_encrypt_sign_optional(session, keylist, ptext,
neal@3191
  1596
        psize, ctext, csize, true);
neal@3191
  1597
}
neal@3191
  1598
neal@3191
  1599
neal@3191
  1600
PEP_STATUS pgp_generate_keypair(PEP_SESSION session, pEp_identity *identity)
neal@3191
  1601
{
neal@3191
  1602
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  1603
    pgp_error_t err = NULL;
neal@3191
  1604
    char *userid = NULL;
neal@3332
  1605
    pgp_tpk_t tpk = NULL;
neal@3332
  1606
    pgp_fingerprint_t pgp_fpr = NULL;
neal@3191
  1607
    char *fpr = NULL;
neal@3191
  1608
neal@3191
  1609
    assert(session);
neal@3191
  1610
    assert(identity);
neal@3191
  1611
    assert(identity->address);
neal@3191
  1612
    assert(identity->fpr == NULL || identity->fpr[0] == 0);
neal@3191
  1613
    assert(identity->username);
neal@3191
  1614
huss@3546
  1615
    size_t userid_size = strlen(identity->username)+strlen(identity->address)+3+1;
huss@3546
  1616
    userid = (char *) calloc(1, userid_size);
huss@3546
  1617
    assert(userid);
huss@3546
  1618
    if (!userid)
huss@3546
  1619
        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
huss@3546
  1620
huss@3546
  1621
    int r = snprintf(userid, userid_size, "%s <%s>", identity->username, identity->address);
huss@3546
  1622
    assert(r >= 0 && r < userid_size);
huss@3546
  1623
    if (r < 0)
huss@3546
  1624
        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR, "snprintf");
neal@3191
  1625
us@3209
  1626
    T("(%s)", userid);
us@3209
  1627
neal@3191
  1628
    // Generate a key.
neal@3643
  1629
    pgp_tpk_builder_t tpkb = pgp_tpk_builder_general_purpose
neal@3643
  1630
        (PGP_TPK_CIPHER_SUITE_RSA3K, userid);
neal@3332
  1631
    pgp_signature_t rev;
neal@3643
  1632
    if (pgp_tpk_builder_generate(&err, tpkb, &tpk, &rev))
neal@3332
  1633
        ERROR_OUT(err, PEP_CANNOT_CREATE_KEY, "Generating a key pair");
neal@3191
  1634
neal@3191
  1635
    // XXX: We should return this.
neal@3358
  1636
    pgp_signature_free(rev);
neal@3191
  1637
neal@3191
  1638
    // Get the fingerprint.
neal@3332
  1639
    pgp_fpr = pgp_tpk_fingerprint(tpk);
neal@3332
  1640
    fpr = pgp_fingerprint_to_hex(pgp_fpr);
neal@3191
  1641
us@3209
  1642
    status = tpk_save(session, tpk, NULL);
neal@3191
  1643
    tpk = NULL;
neal@3191
  1644
    if (status != 0)
neal@3332
  1645
        ERROR_OUT(NULL, PEP_CANNOT_CREATE_KEY, "saving TSK");
neal@3191
  1646
neal@3191
  1647
    free(identity->fpr);
neal@3191
  1648
    identity->fpr = fpr;
neal@3191
  1649
    fpr = NULL;
neal@3191
  1650
neal@3191
  1651
 out:
neal@3332
  1652
    if (pgp_fpr)
neal@3332
  1653
        pgp_fingerprint_free(pgp_fpr);
neal@3191
  1654
    free(fpr);
neal@3191
  1655
    if (tpk)
neal@3332
  1656
        pgp_tpk_free(tpk);
neal@3191
  1657
    free(userid);
neal@3191
  1658
vb@3621
  1659
    T("-> %s", pEp_status_to_string(status));
neal@3191
  1660
    return status;
neal@3191
  1661
}
neal@3191
  1662
vb@3548
  1663
#define SQL_DELETE "DELETE FROM keys WHERE primary_key = '%s' ;"
vb@3548
  1664
static const char *sql_delete = SQL_DELETE;
vb@3548
  1665
static const size_t sql_delete_size = sizeof(SQL_DELETE);
vb@3548
  1666
vb@3549
  1667
// FIXME: this is deleting the key from the index but not the key data
vb@3548
  1668
vb@3548
  1669
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
neal@3191
  1670
{
vb@3548
  1671
    assert(session && fpr && fpr[0]);
vb@3548
  1672
    if (!(session && fpr && fpr[0]))
vb@3548
  1673
        return PEP_ILLEGAL_VALUE;
krista@3535
  1674
vb@3548
  1675
    size_t sql_size = sql_delete_size + strlen(fpr);
vb@3548
  1676
    char *sql = calloc(1, sql_size);
vb@3548
  1677
    assert(sql);
vb@3548
  1678
    if (!sql)
vb@3548
  1679
        return PEP_OUT_OF_MEMORY;
neal@3191
  1680
vb@3548
  1681
    int r = snprintf(sql, sql_size, sql_delete, fpr);
vb@3548
  1682
    assert(r > 0 && r < sql_size);
vb@3548
  1683
    if (r < 0)
vb@3548
  1684
        return PEP_UNKNOWN_ERROR;
neal@3191
  1685
vb@3548
  1686
    int sqlite_result = sqlite3_exec(session->key_db, sql, NULL, NULL, NULL);
vb@3548
  1687
    assert(sqlite_result == SQLITE_OK);
vb@3548
  1688
    if (sqlite_result != SQLITE_OK)
vb@3548
  1689
        return PEP_CANNOT_DELETE_KEY;
neal@3191
  1690
vb@3572
  1691
    sqlite_result = sqlite3_changes(session->key_db);
vb@3573
  1692
    assert(sqlite_result >= 0 && sqlite_result < 2);
vb@3572
  1693
    if (sqlite_result < 1)
vb@3572
  1694
        return PEP_KEY_NOT_FOUND;
vb@3572
  1695
vb@3548
  1696
    return PEP_STATUS_OK;
neal@3191
  1697
}
neal@3191
  1698
neal@3654
  1699
// XXX: This also needs to handle revocation certificates.
neal@3191
  1700
PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
neal@3191
  1701
                              size_t size, identity_list **private_idents)
neal@3191
  1702
{
neal@3658
  1703
    PEP_STATUS status = PEP_NO_KEY_IMPORTED;
neal@3332
  1704
    pgp_error_t err;
neal@3654
  1705
    pgp_tpk_parser_t parser = NULL;
neal@3191
  1706
neal@3191
  1707
    if (private_idents)
neal@3191
  1708
        *private_idents = NULL;
neal@3191
  1709
neal@3191
  1710
    T("parsing %zd bytes", size);
neal@3191
  1711
neal@3332
  1712
    pgp_packet_parser_result_t ppr
neal@3332
  1713
        = pgp_packet_parser_from_bytes(&err, (uint8_t *) key_data, size);
neal@3191
  1714
    if (! ppr)
neal@3332
  1715
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Creating packet parser");
neal@3191
  1716
neal@3332
  1717
    pgp_tag_t tag = pgp_packet_parser_result_tag(ppr);
neal@3191
  1718
    switch (tag) {
neal@3657
  1719
    case PGP_TAG_SIGNATURE: {
neal@3657
  1720
        // The following asserts can't fail, because
neal@3657
  1721
        // pgp_packet_parser_result_tag succeeded and the tag is
neal@3657
  1722
        // right.
neal@3657
  1723
        pgp_packet_parser_t pp = pgp_packet_parser_result_packet_parser (ppr);
neal@3657
  1724
        assert(pp);
neal@3657
  1725
neal@3657
  1726
        pgp_packet_t packet = NULL;
neal@3657
  1727
        if (pgp_packet_parser_next(&err, pp, &packet, &ppr))
neal@3657
  1728
            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Getting signature packet");
neal@3657
  1729
neal@3657
  1730
        pgp_signature_t sig = pgp_packet_ref_signature (packet);
neal@3657
  1731
        assert(sig);
neal@3657
  1732
neal@3657
  1733
        pgp_tpk_t tpk = NULL;
neal@3657
  1734
neal@3657
  1735
        pgp_fingerprint_t issuer_fpr = pgp_signature_issuer_fingerprint(sig);
neal@3657
  1736
        if (issuer_fpr) {
neal@3657
  1737
            char *issuer_fpr_hex = pgp_fingerprint_to_hex(issuer_fpr);
neal@3657
  1738
            T("Importing a signature issued by %s", issuer_fpr_hex);
neal@3657
  1739
neal@3657
  1740
            status = tpk_find_by_fpr_hex(session, issuer_fpr_hex,
neal@3657
  1741
                                         false, &tpk, NULL);
neal@3657
  1742
            if (status && status != PEP_KEY_NOT_FOUND)
neal@3657
  1743
                DUMP_ERR(NULL, status, "Looking up %s", issuer_fpr_hex);
neal@3657
  1744
neal@3657
  1745
            free(issuer_fpr_hex);
neal@3657
  1746
            pgp_fingerprint_free(issuer_fpr);
neal@3657
  1747
        }
neal@3657
  1748
neal@3657
  1749
        if (! tpk) {
neal@3657
  1750
            pgp_keyid_t issuer = pgp_signature_issuer(sig);
neal@3657
  1751
            if (issuer) {
neal@3657
  1752
                char *issuer_hex = pgp_keyid_to_hex(issuer);
neal@3657
  1753
                T("Importing a signature issued by %s", issuer_hex);
neal@3657
  1754
neal@3657
  1755
                status = tpk_find_by_keyid_hex(session, issuer_hex,
neal@3657
  1756
                                               false, &tpk, NULL);
neal@3657
  1757
                if (status && status != PEP_KEY_NOT_FOUND)
neal@3657
  1758
                    DUMP_ERR(NULL, status, "Looking up %s", issuer_hex);
neal@3657
  1759
neal@3657
  1760
                free(issuer_hex);
neal@3657
  1761
                pgp_keyid_free(issuer);
neal@3657
  1762
            }
neal@3657
  1763
        }
neal@3657
  1764
neal@3657
  1765
        // We need a packet.  sig is only a reference, so we just need
neal@3657
  1766
        // to free it.
neal@3657
  1767
        pgp_signature_free(sig);
neal@3657
  1768
neal@3657
  1769
        if (tpk) {
neal@3657
  1770
            T("Merging packet: %s", pgp_packet_debug(packet));
neal@3657
  1771
neal@3657
  1772
            tpk = pgp_tpk_merge_packets (&err, tpk, &packet, 1);
neal@3657
  1773
            if (! tpk)
neal@3657
  1774
                ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Merging signature");
neal@3657
  1775
neal@3657
  1776
            status = tpk_save(session, tpk, NULL);
neal@3657
  1777
            if (status)
neal@3657
  1778
                ERROR_OUT(NULL, status, "saving merged TPK");
neal@3657
  1779
            status = PEP_KEY_IMPORTED;
neal@3657
  1780
        }
neal@3191
  1781
        break;
neal@3657
  1782
    }
neal@3332
  1783
    case PGP_TAG_PUBLIC_KEY:
neal@3332
  1784
    case PGP_TAG_SECRET_KEY: {
neal@3654
  1785
        parser = pgp_tpk_parser_from_packet_parser(ppr);
neal@3654
  1786
        pgp_tpk_t tpk;
neal@3654
  1787
        int count = 0;
neal@3654
  1788
        err = NULL;
neal@3654
  1789
        while ((tpk = pgp_tpk_parser_next(&err, parser))) {
neal@3654
  1790
            count ++;
neal@3654
  1791
neal@3654
  1792
            T("#%d. TPK for %s, %s",
neal@3654
  1793
              count, pgp_tpk_primary_user_id(tpk),
neal@3654
  1794
              pgp_fingerprint_to_hex(pgp_tpk_fingerprint(tpk)));
neal@3654
  1795
neal@3654
  1796
            // If private_idents is not NULL and there is any private key
neal@3654
  1797
            // material, it will be saved.
neal@3654
  1798
            status = tpk_save(session, tpk, private_idents);
neal@3654
  1799
            if (status == PEP_STATUS_OK)
neal@3654
  1800
                status = PEP_KEY_IMPORTED;
neal@3654
  1801
            else
neal@3654
  1802
                ERROR_OUT(NULL, status, "saving TPK");
neal@3654
  1803
        }
neal@3654
  1804
        if (err || count == 0)
neal@3332
  1805
            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "parsing key data");
neal@3191
  1806
        break;
neal@3191
  1807
    }
neal@3191
  1808
    default:
neal@3332
  1809
        ERROR_OUT(NULL, PEP_NO_KEY_IMPORTED,
neal@3332
  1810
                  "Can't import %s", pgp_tag_to_string(tag));
neal@3191
  1811
        break;
neal@3191
  1812
    }
neal@3191
  1813
neal@3191
  1814
 out:
neal@3654
  1815
    if (parser)
neal@3654
  1816
        pgp_tpk_parser_free(parser);
neal@3654
  1817
vb@3621
  1818
    T("-> %s", pEp_status_to_string(status));
neal@3191
  1819
    return status;
neal@3191
  1820
}
neal@3191
  1821
neal@3191
  1822
PEP_STATUS pgp_export_keydata(
neal@3191
  1823
        PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
neal@3191
  1824
        bool secret)
neal@3191
  1825
{
neal@3191
  1826
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  1827
    pgp_error_t err = NULL;
neal@3332
  1828
    pgp_tpk_t tpk = NULL;
neal@3357
  1829
    pgp_writer_t armor_writer = NULL;
neal@3191
  1830
neal@3191
  1831
    assert(session);
neal@3191
  1832
    assert(fpr);
neal@3191
  1833
    assert(key_data);
neal@3191
  1834
    assert(*key_data == NULL);
neal@3191
  1835
    assert(size);
neal@3191
  1836
neal@3191
  1837
    *size = 0;
neal@3191
  1838
neal@3191
  1839
    T("(%s, %s)", fpr, secret ? "secret" : "public");
neal@3191
  1840
neal@3357
  1841
    // If the caller asks for a secret key and we only have a
neal@3357
  1842
    // public key, then we return an error.
krista@3603
  1843
    status = tpk_find_by_fpr_hex(session, fpr, secret, &tpk, NULL);
neal@3357
  1844
    ERROR_OUT(NULL, status, "Looking up TSK for %s", fpr);
neal@3191
  1845
neal@3332
  1846
    pgp_writer_t memory_writer = pgp_writer_alloc((void **) key_data, size);
neal@3191
  1847
    if (! memory_writer)
neal@3332
  1848
        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR, "creating memory writer");
neal@3357
  1849
    armor_writer = pgp_armor_writer_new(&err, memory_writer,
neal@3357
  1850
                                        PGP_ARMOR_KIND_PUBLICKEY, NULL, 0);
neal@3191
  1851
    if (! armor_writer) {
neal@3332
  1852
        pgp_writer_free(memory_writer);
neal@3332
  1853
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "creating armored writer");
neal@3191
  1854
    }
neal@3191
  1855
neal@3191
  1856
    if (secret) {
neal@3643
  1857
        pgp_tsk_t tsk = pgp_tpk_as_tsk(tpk);
neal@3332
  1858
        if (pgp_tsk_serialize(&err, tsk, armor_writer))
neal@3332
  1859
            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "serializing TSK");
neal@3643
  1860
        pgp_tsk_free(tsk);
neal@3191
  1861
    } else {
neal@3332
  1862
        if (pgp_tpk_serialize(&err, tpk, armor_writer))
neal@3332
  1863
            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "serializing TPK");
neal@3191
  1864
    }
neal@3191
  1865
neal@3191
  1866
 out:
neal@3191
  1867
    if (armor_writer)
neal@3332
  1868
        pgp_writer_free(armor_writer);
neal@3191
  1869
neal@3357
  1870
    if (tpk)
neal@3357
  1871
        pgp_tpk_free(tpk);
neal@3191
  1872
vb@3621
  1873
    T("(%s) -> %s", fpr, pEp_status_to_string(status));
neal@3191
  1874
    return status;
neal@3191
  1875
}
neal@3191
  1876
neal@3191
  1877
char* _undot_address(const char* address) {
neal@3191
  1878
    if (!address)
neal@3191
  1879
        return NULL;
neal@3191
  1880
neal@3191
  1881
    int addr_len = strlen(address);
neal@3191
  1882
    const char* at = strstr(address, "@");
neal@3191
  1883
neal@3191
  1884
    if (!at)
neal@3191
  1885
        at = address + addr_len;
neal@3191
  1886
neal@3191
  1887
    char* retval = calloc(1, addr_len + 1);
neal@3191
  1888
neal@3191
  1889
    const char* addr_curr = address;
neal@3191
  1890
    char* retval_curr = retval;
neal@3191
  1891
neal@3191
  1892
    while (addr_curr < at) {
neal@3191
  1893
        if (*addr_curr == '.') {
neal@3191
  1894
            addr_curr++;
neal@3191
  1895
            continue;
neal@3191
  1896
        }
neal@3191
  1897
        *retval_curr = *addr_curr;
neal@3191
  1898
        retval_curr++;
neal@3191
  1899
        addr_curr++;
neal@3191
  1900
    }
neal@3191
  1901
    if (*addr_curr == '@')
neal@3191
  1902
        strcat(retval_curr, addr_curr);
neal@3191
  1903
neal@3191
  1904
    return retval;
neal@3191
  1905
}
neal@3191
  1906
us@3209
  1907
static stringpair_list_t *add_key(PEP_SESSION session,
us@3209
  1908
                                  stringpair_list_t *keyinfo_list,
us@3209
  1909
                                  stringlist_t* keylist,
neal@3332
  1910
                                  pgp_tpk_t tpk, pgp_fingerprint_t fpr) {
us@3209
  1911
    bool revoked = false;
us@3209
  1912
    // Don't add revoked keys to the keyinfo_list.
us@3209
  1913
    if (keyinfo_list) {
neal@3332
  1914
        pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
neal@3332
  1915
        pgp_revocation_status_variant_t rsv = pgp_revocation_status_variant(rs);
neal@3332
  1916
        pgp_revocation_status_free(rs);
neal@3332
  1917
        if (rsv == PGP_REVOCATION_STATUS_REVOKED)
us@3209
  1918
            revoked = true;
us@3209
  1919
    }
us@3209
  1920
us@3209
  1921
    if (revoked && ! keylist)
us@3209
  1922
        return keyinfo_list;
us@3209
  1923
us@3209
  1924
    int dealloc_fpr = 0;
us@3209
  1925
    if (!fpr) {
us@3209
  1926
        dealloc_fpr = 1;
neal@3332
  1927
        fpr = pgp_tpk_fingerprint(tpk);
us@3209
  1928
    }
neal@3332
  1929
    char *fpr_str = pgp_fingerprint_to_hex(fpr);
us@3209
  1930
us@3209
  1931
    if (!revoked && keyinfo_list) {
neal@3332
  1932
        char *user_id = pgp_tpk_primary_user_id(tpk);
us@3209
  1933
        if (user_id)
us@3209
  1934
            keyinfo_list = stringpair_list_add(keyinfo_list,
us@3209
  1935
                                               new_stringpair(fpr_str, user_id));
us@3209
  1936
        free(user_id);
us@3209
  1937
    }
us@3209
  1938
us@3209
  1939
    if (keylist)
us@3209
  1940
        keylist = stringlist_add(keylist, fpr_str);
us@3209
  1941
us@3209
  1942
    free(fpr_str);
us@3209
  1943
    if (dealloc_fpr)
neal@3332
  1944
        pgp_fingerprint_free(fpr);
us@3209
  1945
us@3209
  1946
    return keyinfo_list;
us@3209
  1947
}
us@3209
  1948
us@3209
  1949
static PEP_STATUS list_keys(PEP_SESSION session,
us@3209
  1950
                            const char* pattern, int private_only,
us@3209
  1951
                            stringpair_list_t** keyinfo_list, stringlist_t** keylist)
us@3209
  1952
{
neal@3191
  1953
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  1954
    pgp_tpk_t tpk = NULL;
neal@3332
  1955
    pgp_fingerprint_t fpr = NULL;
neal@3191
  1956
us@3209
  1957
    T("('%s', private: %d)", pattern, private_only);
neal@3191
  1958
us@3209
  1959
    stringpair_list_t* _keyinfo_list = NULL;
us@3209
  1960
    if (keyinfo_list) {
us@3209
  1961
        _keyinfo_list = new_stringpair_list(NULL);
us@3209
  1962
        if (!_keyinfo_list)
neal@3332
  1963
            ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "new_stringpair_list");
us@3209
  1964
    }
us@3209
  1965
    stringlist_t* _keylist = NULL;
us@3209
  1966
    if (keylist) {
us@3209
  1967
        _keylist = new_stringlist(NULL);
us@3209
  1968
        if (!_keylist)
neal@3332
  1969
            ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "new_string_list");
us@3209
  1970
    }
neal@3191
  1971
us@3209
  1972
    // Trim any leading space.  This also makes it easier to recognize
us@3209
  1973
    // a string that is only whitespace.
us@3209
  1974
    while (*pattern == ' ')
us@3209
  1975
        pattern ++;
us@3209
  1976
us@3209
  1977
    if (strchr(pattern, '@')) {
us@3209
  1978
        // Looks like a mailbox.
neal@3332
  1979
        pgp_tpk_t *tpks = NULL;
us@3209
  1980
        int count = 0;
us@3209
  1981
        status = tpk_find_by_email(session, pattern, private_only, &tpks, &count);
neal@3332
  1982
        ERROR_OUT(NULL, status, "Looking up '%s'", pattern);
us@3209
  1983
        for (int i = 0; i < count; i ++) {
us@3209
  1984
            add_key(session, _keyinfo_list, _keylist, tpks[i], NULL);
neal@3332
  1985
            pgp_tpk_free(tpks[i]);
us@3209
  1986
        }
us@3209
  1987
        free(tpks);
us@3209
  1988
us@3209
  1989
        if (count == 0) {
neal@3191
  1990
            // If match failed, check to see if we've got a dotted
neal@3191
  1991
            // address in the pattern.  If so, try again without dots.
neal@3191
  1992
            const char* dotpos = strstr(pattern, ".");
neal@3191
  1993
            const char* atpos = strstr(pattern, "@");
neal@3191
  1994
            if (dotpos && atpos && (dotpos < atpos)) {
neal@3191
  1995
                char* undotted = _undot_address(pattern);
neal@3191
  1996
                if (undotted) {
us@3209
  1997
                    PEP_STATUS status = list_keys(session, undotted, private_only,
us@3209
  1998
                                                  keyinfo_list, keylist);
neal@3191
  1999
                    free(undotted);
neal@3191
  2000
                    return status;
neal@3191
  2001
                }
neal@3191
  2002
            }
neal@3191
  2003
        }
us@3209
  2004
    } else if (// Only hex characters and spaces
us@3209
  2005
               pattern[strspn(pattern, "0123456789aAbBcCdDeEfF ")] == 0
us@3209
  2006
               // And a fair amount of them.
us@3209
  2007
               && strlen(pattern) >= 16) {
neal@3359
  2008
        // Fingerprint.  Note: the pep engine never looks keys up by
neal@3359
  2009
        // keyid, so we don't handle them.
neal@3332
  2010
        fpr = pgp_fingerprint_from_hex(pattern);
us@3209
  2011
        status = tpk_find_by_fpr(session, fpr, false, &tpk, NULL);
neal@3332
  2012
        ERROR_OUT(NULL, status, "Looking up key");
us@3209
  2013
        add_key(session, _keyinfo_list, _keylist, tpk, fpr);
us@3209
  2014
    } else if (pattern[0] == 0) {
us@3209
  2015
        // Empty string.
us@3209
  2016
neal@3332
  2017
        pgp_tpk_t *tpks = NULL;
us@3209
  2018
        int count = 0;
us@3209
  2019
        status = tpk_all(session, private_only, &tpks, &count);
neal@3332
  2020
        ERROR_OUT(NULL, status, "Looking up '%s'", pattern);
us@3209
  2021
        for (int i = 0; i < count; i ++) {
us@3209
  2022
            add_key(session, _keyinfo_list, _keylist, tpks[i], NULL);
neal@3332
  2023
            pgp_tpk_free(tpks[i]);
us@3209
  2024
        }
us@3209
  2025
        free(tpks);
us@3209
  2026
    } else {
us@3209
  2027
        T("unsupported pattern '%s'", pattern);
neal@3191
  2028
    }
neal@3191
  2029
neal@3191
  2030
 out:
neal@3191
  2031
    if (tpk)
neal@3332
  2032
        pgp_tpk_free(tpk);
us@3209
  2033
    if (fpr)
neal@3332
  2034
        pgp_fingerprint_free(fpr);
neal@3191
  2035
us@3209
  2036
    if (status == PEP_KEY_NOT_FOUND)
us@3209
  2037
        status = PEP_STATUS_OK;
us@3209
  2038
us@3209
  2039
    if (status != PEP_STATUS_OK || (_keyinfo_list && !_keyinfo_list->value)) {
us@3209
  2040
        free_stringpair_list(_keyinfo_list);
us@3209
  2041
        _keyinfo_list = NULL;
us@3209
  2042
    }
us@3209
  2043
    if (keyinfo_list)
us@3209
  2044
        *keyinfo_list = _keyinfo_list;
us@3209
  2045
us@3209
  2046
    if (status != PEP_STATUS_OK || (_keylist && !_keylist->value)) {
us@3209
  2047
        free_stringlist(_keylist);
us@3209
  2048
        _keylist = NULL;
us@3209
  2049
    }
us@3209
  2050
    if (keylist)
us@3209
  2051
        *keylist = _keylist;
us@3209
  2052
us@3209
  2053
    int len = -1;
us@3209
  2054
    if (keylist)
us@3209
  2055
        len = stringlist_length(*keylist);
us@3209
  2056
    else if (keyinfo_list)
us@3209
  2057
        len = stringpair_list_length(*keyinfo_list);
vb@3621
  2058
    T("(%s) -> %s (%d keys)", pattern, pEp_status_to_string(status), len);
neal@3191
  2059
    return status;
neal@3191
  2060
}
neal@3191
  2061
us@3209
  2062
// pattern could be empty, an fpr, or a mailbox.
us@3209
  2063
//
us@3209
  2064
// keyinfo_list is a list of <fpr, openpgp userid> tuples for the
us@3209
  2065
// matching keys.
us@3209
  2066
//
us@3209
  2067
// This function filters out revoked key, but not expired keys.
us@3209
  2068
PEP_STATUS pgp_list_keyinfo(PEP_SESSION session,
us@3209
  2069
                            const char* pattern,
us@3209
  2070
                            stringpair_list_t** keyinfo_list)
us@3209
  2071
{
us@3209
  2072
    return list_keys(session, pattern, false, keyinfo_list, NULL);
us@3209
  2073
}
us@3209
  2074
us@3209
  2075
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
us@3209
  2076
{
us@3209
  2077
    assert(!"pgp_recv_key not implemented");
us@3209
  2078
    return PEP_UNKNOWN_ERROR;
us@3209
  2079
}
us@3209
  2080
us@3209
  2081
// Unlike pgp_list_keyinfo, this function returns revoked keys.
neal@3191
  2082
PEP_STATUS pgp_find_keys(
neal@3191
  2083
    PEP_SESSION session, const char *pattern, stringlist_t **keylist)
neal@3191
  2084
{
us@3209
  2085
    return list_keys(session, pattern, false, NULL, keylist);
neal@3191
  2086
}
neal@3191
  2087
us@3209
  2088
// Unlike pgp_list_keyinfo, this function returns revoked keys.
neal@3191
  2089
PEP_STATUS pgp_find_private_keys(
neal@3191
  2090
    PEP_SESSION session, const char *pattern, stringlist_t **keylist)
neal@3191
  2091
{
us@3209
  2092
    return list_keys(session, pattern, true, NULL, keylist);
neal@3191
  2093
}
neal@3191
  2094
neal@3191
  2095
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
neal@3191
  2096
{
neal@3191
  2097
    assert(!"pgp_send_key not implemented");
neal@3191
  2098
    return PEP_UNKNOWN_ERROR;
neal@3191
  2099
}
neal@3191
  2100
neal@3191
  2101
PEP_STATUS pgp_get_key_rating(
neal@3191
  2102
    PEP_SESSION session, const char *fpr, PEP_comm_type *comm_type)
neal@3191
  2103
{
neal@3191
  2104
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  2105
    pgp_tpk_t tpk = NULL;
neal@3191
  2106
neal@3191
  2107
    assert(session);
neal@3191
  2108
    assert(fpr);
neal@3191
  2109
    assert(comm_type);
neal@3191
  2110
neal@3191
  2111
    *comm_type = PEP_ct_unknown;
neal@3191
  2112
neal@3332
  2113
    pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(fpr);
neal@3332
  2114
    status = tpk_find_by_fpr(session, pgp_fpr, false, &tpk, NULL);
neal@3332
  2115
    pgp_fingerprint_free(pgp_fpr);
neal@3332
  2116
    ERROR_OUT(NULL, status, "Looking up key: %s", fpr);
neal@3191
  2117
neal@3191
  2118
    *comm_type = PEP_ct_OpenPGP_unconfirmed;
neal@3191
  2119
neal@3332
  2120
    if (pgp_tpk_expired(tpk)) {
neal@3191
  2121
        *comm_type = PEP_ct_key_expired;
neal@3191
  2122
        goto out;
neal@3191
  2123
    }
neal@3191
  2124
neal@3332
  2125
    pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
neal@3332
  2126
    pgp_revocation_status_variant_t rsv = pgp_revocation_status_variant(rs);
neal@3332
  2127
    pgp_revocation_status_free(rs);
neal@3332
  2128
    if (rsv == PGP_REVOCATION_STATUS_REVOKED) {
neal@3191
  2129
        *comm_type = PEP_ct_key_revoked;
neal@3191
  2130
        goto out;
neal@3191
  2131
    }
neal@3191
  2132
neal@3191
  2133
    PEP_comm_type best_enc = PEP_ct_no_encryption, best_sign = PEP_ct_no_encryption;
neal@3353
  2134
    pgp_tpk_key_iter_t key_iter = pgp_tpk_key_iter_valid(tpk);
neal@3332
  2135
    pgp_key_t key;
neal@3332
  2136
    pgp_signature_t sig;
neal@3332
  2137
    pgp_revocation_status_t rev;
neal@3332
  2138
    while ((key = pgp_tpk_key_iter_next(key_iter, &sig, &rev))) {
neal@3191
  2139
        if (! sig)
neal@3191
  2140
            continue;
neal@3191
  2141
neal@3191
  2142
        PEP_comm_type curr = PEP_ct_no_encryption;
neal@3191
  2143
neal@3332
  2144
        int can_enc = pgp_signature_can_encrypt_for_transport(sig)
neal@3332
  2145
            || pgp_signature_can_encrypt_at_rest(sig);
neal@3332
  2146
        int can_sign = pgp_signature_can_sign(sig);
neal@3191
  2147
neal@3332
  2148
        pgp_public_key_algo_t pk_algo = pgp_key_public_key_algo(key);
neal@3332
  2149
        if (pk_algo == PGP_PUBLIC_KEY_ALGO_RSA_ENCRYPT_SIGN
neal@3332
  2150
            || pk_algo == PGP_PUBLIC_KEY_ALGO_RSA_ENCRYPT
neal@3332
  2151
            || pk_algo == PGP_PUBLIC_KEY_ALGO_RSA_SIGN) {
neal@3332
  2152
            int bits = pgp_key_public_key_bits(key);
neal@3191
  2153
            if (bits < 1024)
neal@3191
  2154
                curr = PEP_ct_key_too_short;
neal@3191
  2155
            else if (bits == 1024)
neal@3191
  2156
                curr = PEP_ct_OpenPGP_weak_unconfirmed;
neal@3191
  2157
            else
neal@3191
  2158
                curr = PEP_ct_OpenPGP_unconfirmed;
neal@3191
  2159
        } else {
neal@3191
  2160
            curr = PEP_ct_OpenPGP_unconfirmed;
neal@3191
  2161
        }
neal@3191
  2162
neal@3191
  2163
        if (can_enc)
neal@3191
  2164
            best_enc = _MAX(best_enc, curr);
neal@3191
  2165
neal@3191
  2166
        if (can_sign)
neal@3191
  2167
            best_sign = _MAX(best_sign, curr);
neal@3191
  2168
    }
neal@3332
  2169
    pgp_tpk_key_iter_free(key_iter);
neal@3191
  2170
neal@3191
  2171
    if (best_enc == PEP_ct_no_encryption || best_sign == PEP_ct_no_encryption) {
neal@3191
  2172
        *comm_type = PEP_ct_key_b0rken;
neal@3191
  2173
        goto out;
neal@3191
  2174
    } else {
neal@3191
  2175
        *comm_type = _MIN(best_enc, best_sign);
neal@3191
  2176
    }
neal@3191
  2177
neal@3191
  2178
 out:
neal@3191
  2179
    if (tpk)
neal@3332
  2180
        pgp_tpk_free(tpk);
neal@3191
  2181
neal@3191
  2182
    T("(%s) -> %s", fpr, pep_comm_type_to_string(*comm_type));
neal@3191
  2183
    return status;
neal@3191
  2184
}
neal@3191
  2185
neal@3191
  2186
neal@3191
  2187
PEP_STATUS pgp_renew_key(
neal@3191
  2188
    PEP_SESSION session, const char *fpr, const timestamp *ts)
neal@3191
  2189
{
neal@3191
  2190
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  2191
    pgp_error_t err = NULL;
neal@3332
  2192
    pgp_tpk_t tpk = NULL;
neal@3356
  2193
    pgp_tpk_key_iter_t iter = NULL;
neal@3356
  2194
    pgp_key_pair_t keypair = NULL;
neal@3356
  2195
    pgp_signer_t signer = NULL;
neal@3191
  2196
    time_t t = mktime((struct tm *) ts);
neal@3191
  2197
us@3209
  2198
    T("(%s)", fpr);
us@3209
  2199
us@3209
  2200
    status = tpk_find_by_fpr_hex(session, fpr, true, &tpk, NULL);
neal@3332
  2201
    ERROR_OUT(NULL, status, "Looking up '%s'", fpr);
neal@3191
  2202
neal@3332
  2203
    uint32_t creation_time = pgp_key_creation_time(pgp_tpk_primary(tpk));
neal@3191
  2204
    if (creation_time > t)
neal@3191
  2205
        // The creation time is after the expiration time!
neal@3332
  2206
        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
neal@3191
  2207
                  "creation time can't be after expiration time");
neal@3191
  2208
neal@3191
  2209
    uint32_t delta = t - creation_time;
neal@3356
  2210
neal@3356
  2211
neal@3356
  2212
    iter = pgp_tpk_key_iter_valid(tpk);
neal@3356
  2213
    pgp_tpk_key_iter_certification_capable (iter);
neal@3356
  2214
    pgp_tpk_key_iter_unencrypted_secret (iter, true);
neal@3356
  2215
neal@3356
  2216
    // If there are multiple certification capable subkeys, we just
neal@3356
  2217
    // take the first one, whichever one that happens to be.
neal@3356
  2218
    pgp_key_t key = pgp_tpk_key_iter_next (iter, NULL, NULL);
neal@3356
  2219
    if (! key)
neal@3356
  2220
        ERROR_OUT (err, PEP_UNKNOWN_ERROR,
neal@3356
  2221
                   "%s has no usable certification capable key", fpr);
neal@3356
  2222
neal@3356
  2223
    keypair = pgp_key_into_key_pair (NULL, pgp_key_clone (key));
neal@3356
  2224
    if (! keypair)
neal@3356
  2225
        ERROR_OUT (err, PEP_UNKNOWN_ERROR, "Creating a keypair");
neal@3356
  2226
neal@3356
  2227
    signer = pgp_key_pair_as_signer (keypair);
neal@3356
  2228
    if (! signer)
neal@3356
  2229
        ERROR_OUT (err, PEP_UNKNOWN_ERROR, "Creating a signer");
neal@3356
  2230
neal@3356
  2231
    tpk = pgp_tpk_set_expiry(&err, tpk, signer, delta);
neal@3191
  2232
    if (! tpk)
neal@3332
  2233
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "setting expiration");
neal@3191
  2234
us@3209
  2235
    status = tpk_save(session, tpk, NULL);
neal@3191
  2236
    tpk = NULL;
neal@3332
  2237
    ERROR_OUT(NULL, status, "Saving %s", fpr);
neal@3191
  2238
neal@3191
  2239
 out:
neal@3356
  2240
    if (signer)
neal@3356
  2241
        pgp_signer_free (signer);
neal@3356
  2242
    if (keypair)
neal@3356
  2243
        pgp_key_pair_free (keypair);
neal@3356
  2244
    if (iter)
neal@3356
  2245
        pgp_tpk_key_iter_free (iter);
neal@3191
  2246
    if (tpk)
neal@3332
  2247
        pgp_tpk_free(tpk);
neal@3191
  2248
vb@3621
  2249
    T("(%s) -> %s", fpr, pEp_status_to_string(status));
neal@3191
  2250
    return status;
neal@3191
  2251
}
neal@3191
  2252
neal@3191
  2253
PEP_STATUS pgp_revoke_key(
neal@3191
  2254
    PEP_SESSION session, const char *fpr, const char *reason)
neal@3191
  2255
{
neal@3191
  2256
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  2257
    pgp_error_t err = NULL;
neal@3332
  2258
    pgp_tpk_t tpk = NULL;
neal@3356
  2259
    pgp_tpk_key_iter_t iter = NULL;
neal@3356
  2260
    pgp_key_pair_t keypair = NULL;
neal@3356
  2261
    pgp_signer_t signer = NULL;
neal@3191
  2262
us@3209
  2263
    T("(%s)", fpr);
us@3209
  2264
us@3209
  2265
    status = tpk_find_by_fpr_hex(session, fpr, true, &tpk, NULL);
neal@3332
  2266
    ERROR_OUT(NULL, status, "Looking up %s", fpr);
neal@3191
  2267
neal@3356
  2268
    iter = pgp_tpk_key_iter_valid(tpk);
neal@3356
  2269
    pgp_tpk_key_iter_certification_capable (iter);
neal@3356
  2270
    pgp_tpk_key_iter_unencrypted_secret (iter, true);
neal@3332
  2271
neal@3356
  2272
    // If there are multiple certification capable subkeys, we just
neal@3356
  2273
    // take the first one, whichever one that happens to be.
neal@3356
  2274
    pgp_key_t key = pgp_tpk_key_iter_next (iter, NULL, NULL);
neal@3356
  2275
    if (! key)
neal@3356
  2276
        ERROR_OUT (err, PEP_UNKNOWN_ERROR,
neal@3356
  2277
                   "%s has no usable certification capable key", fpr);
neal@3356
  2278
neal@3356
  2279
    keypair = pgp_key_into_key_pair (NULL, pgp_key_clone (key));
neal@3356
  2280
    if (! keypair)
neal@3356
  2281
        ERROR_OUT (err, PEP_UNKNOWN_ERROR, "Creating a keypair");
neal@3356
  2282
neal@3356
  2283
    signer = pgp_key_pair_as_signer (keypair);
neal@3356
  2284
    if (! signer)
neal@3356
  2285
        ERROR_OUT (err, PEP_UNKNOWN_ERROR, "Creating a signer");
neal@3356
  2286
neal@3356
  2287
    tpk = pgp_tpk_revoke_in_place(&err, tpk, signer,
neal@3332
  2288
                                  PGP_REASON_FOR_REVOCATION_UNSPECIFIED,
neal@3332
  2289
                                  reason);
neal@3191
  2290
    if (! tpk)
neal@3332
  2291
        ERROR_OUT(err, PEP_UNKNOWN_ERROR, "setting expiration");
neal@3191
  2292
neal@3332
  2293
    assert(pgp_revocation_status_variant(pgp_tpk_revocation_status(tpk))
neal@3332
  2294
           == PGP_REVOCATION_STATUS_REVOKED);
neal@3191
  2295
us@3209
  2296
    status = tpk_save(session, tpk, NULL);
neal@3191
  2297
    tpk = NULL;
neal@3332
  2298
    ERROR_OUT(NULL, status, "Saving %s", fpr);
neal@3191
  2299
neal@3191
  2300
 out:
neal@3356
  2301
    if (signer)
neal@3356
  2302
        pgp_signer_free (signer);
neal@3356
  2303
    if (keypair)
neal@3356
  2304
        pgp_key_pair_free (keypair);
neal@3356
  2305
    if (iter)
neal@3356
  2306
        pgp_tpk_key_iter_free (iter);
neal@3191
  2307
    if (tpk)
neal@3332
  2308
        pgp_tpk_free(tpk);
neal@3191
  2309
vb@3621
  2310
    T("(%s) -> %s", fpr, pEp_status_to_string(status));
neal@3191
  2311
    return status;
neal@3191
  2312
}
neal@3191
  2313
neal@3191
  2314
PEP_STATUS pgp_key_expired(PEP_SESSION session, const char *fpr,
neal@3191
  2315
                           const time_t when, bool *expired)
neal@3191
  2316
{
neal@3191
  2317
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  2318
    pgp_tpk_t tpk = NULL;
us@3209
  2319
    T("(%s)", fpr);
neal@3191
  2320
neal@3191
  2321
    assert(session);
neal@3191
  2322
    assert(fpr);
neal@3191
  2323
    assert(expired);
neal@3191
  2324
neal@3191
  2325
    *expired = false;
neal@3191
  2326
neal@3332
  2327
    pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(fpr);
neal@3332
  2328
    status = tpk_find_by_fpr(session, pgp_fpr, false, &tpk, NULL);
neal@3332
  2329
    pgp_fingerprint_free(pgp_fpr);
neal@3332
  2330
    ERROR_OUT(NULL, status, "Looking up %s", fpr);
neal@3191
  2331
neal@3191
  2332
    // Is the TPK live?
neal@3332
  2333
    *expired = !pgp_tpk_alive_at(tpk, when);
neal@3191
  2334
    if (*expired)
neal@3191
  2335
        goto out;
neal@3191
  2336
neal@3191
  2337
    // Are there at least one certification subkey, one signing subkey
neal@3191
  2338
    // and one encryption subkey that are live?
neal@3191
  2339
    int can_certify = 0, can_encrypt = 0, can_sign = 0;
neal@3191
  2340
neal@3353
  2341
    pgp_tpk_key_iter_t key_iter = pgp_tpk_key_iter_valid(tpk);
neal@3332
  2342
    pgp_key_t key;
neal@3332
  2343
    pgp_signature_t sig;
neal@3332
  2344
    pgp_revocation_status_t rev;
neal@3332
  2345
    while ((key = pgp_tpk_key_iter_next(key_iter, &sig, &rev))) {
neal@3191
  2346
        if (! sig)
neal@3191
  2347
            continue;
neal@3191
  2348
neal@3332
  2349
        if (pgp_signature_can_encrypt_for_transport(sig)
neal@3332
  2350
            || pgp_signature_can_encrypt_at_rest(sig))
neal@3191
  2351
            can_encrypt = 1;
neal@3332
  2352
        if (pgp_signature_can_sign(sig))
neal@3191
  2353
            can_sign = 1;
neal@3332
  2354
        if (pgp_signature_can_certify(sig))
neal@3191
  2355
            can_certify = 1;
neal@3191
  2356
neal@3191
  2357
        if (can_encrypt && can_sign && can_certify)
neal@3191
  2358
            break;
neal@3191
  2359
    }
neal@3332
  2360
    pgp_tpk_key_iter_free(key_iter);
neal@3191
  2361
neal@3191
  2362
    *expired = !(can_encrypt && can_sign && can_certify);
neal@3191
  2363
neal@3191
  2364
 out:
neal@3191
  2365
    if (tpk)
neal@3332
  2366
        pgp_tpk_free(tpk);
vb@3621
  2367
    T("(%s) -> %s", fpr, pEp_status_to_string(status));
neal@3191
  2368
    return status;
neal@3191
  2369
}
neal@3191
  2370
neal@3191
  2371
PEP_STATUS pgp_key_revoked(PEP_SESSION session, const char *fpr, bool *revoked)
neal@3191
  2372
{
neal@3191
  2373
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  2374
    pgp_tpk_t tpk;
neal@3191
  2375
us@3209
  2376
    T("(%s)", fpr);
us@3209
  2377
neal@3191
  2378
    assert(session);
neal@3191
  2379
    assert(fpr);
neal@3191
  2380
    assert(revoked);
neal@3191
  2381
neal@3191
  2382
    *revoked = false;
neal@3191
  2383
neal@3332
  2384
    pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(fpr);
neal@3332
  2385
    status = tpk_find_by_fpr(session, pgp_fpr, false, &tpk, NULL);
neal@3332
  2386
    pgp_fingerprint_free(pgp_fpr);
neal@3332
  2387
    ERROR_OUT(NULL, status, "Looking up %s", fpr);
neal@3191
  2388
neal@3332
  2389
    pgp_revocation_status_t rs = pgp_tpk_revocation_status(tpk);
neal@3332
  2390
    *revoked = pgp_revocation_status_variant(rs) == PGP_REVOCATION_STATUS_REVOKED;
neal@3332
  2391
    pgp_revocation_status_free (rs);
neal@3332
  2392
    pgp_tpk_free(tpk);
neal@3191
  2393
neal@3191
  2394
 out:
vb@3621
  2395
    T("(%s) -> %s", fpr, pEp_status_to_string(status));
neal@3191
  2396
    return status;
neal@3191
  2397
}
neal@3191
  2398
neal@3191
  2399
PEP_STATUS pgp_key_created(PEP_SESSION session, const char *fpr, time_t *created)
neal@3191
  2400
{
neal@3191
  2401
    PEP_STATUS status = PEP_STATUS_OK;
neal@3332
  2402
    pgp_tpk_t tpk = NULL;
us@3209
  2403
    T("(%s)", fpr);
neal@3191
  2404
neal@3191
  2405
    *created = 0;
neal@3191
  2406
neal@3332
  2407
    pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(fpr);
neal@3332
  2408
    status = tpk_find_by_fpr(session, pgp_fpr, false, &tpk, NULL);
neal@3332
  2409
    pgp_fingerprint_free(pgp_fpr);
neal@3332
  2410
    ERROR_OUT(NULL, status, "Looking up %s", fpr);
neal@3191
  2411
neal@3332
  2412
    pgp_key_t k = pgp_tpk_primary(tpk);
neal@3332
  2413
    *created = pgp_key_creation_time(k);
neal@3332
  2414
    pgp_tpk_free(tpk);
neal@3191
  2415
neal@3191
  2416
 out:
vb@3621
  2417
    T("(%s) -> %s", fpr, pEp_status_to_string(status));
neal@3191
  2418
    return status;
neal@3191
  2419
}
neal@3191
  2420
neal@3191
  2421
PEP_STATUS pgp_binary(const char **path)
neal@3191
  2422
{
neal@3361
  2423
    *path = NULL;
neal@3191
  2424
    return PEP_STATUS_OK;
neal@3191
  2425
}
neal@3191
  2426
neal@3191
  2427
PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
neal@3191
  2428
                                 bool *has_private)
neal@3191
  2429
{
us@3209
  2430
    T("(%s)", fpr);
neal@3332
  2431
    pgp_fingerprint_t pgp_fpr = pgp_fingerprint_from_hex(fpr);
neal@3332
  2432
    PEP_STATUS status = tpk_find_by_fpr(session, pgp_fpr, true, NULL, NULL);
neal@3332
  2433
    pgp_fingerprint_free(pgp_fpr);
neal@3191
  2434
    if (status == PEP_STATUS_OK) {
neal@3191
  2435
        *has_private = 1;
neal@3191
  2436
    } else if (status == PEP_KEY_NOT_FOUND) {
neal@3191
  2437
        *has_private = 0;
us@3209
  2438
        status = PEP_STATUS_OK;
neal@3191
  2439
    }
neal@3332
  2440
    T("(%s) -> %s, %s",
vb@3621
  2441
      fpr, *has_private ? "priv" : "pub", pEp_status_to_string(status));
us@3209
  2442
    return status;
neal@3191
  2443
}