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