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