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