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