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