src/pgp_gpg.c
author us@chu.huenfield.org
Tue, 25 Dec 2018 14:46:45 +0100
branchsync
changeset 3209 c15b4ca2b52a
parent 3140 00a9ab97c594
child 3234 538a03bab6b8
permissions -rw-r--r--
Replace use of Sequoia's backend with a custom key store.

- Sequoia's key store doesn't meet pep's needs (in particular, the
ability to search on a key's user id) and trying to shoehorn pep's
needs onto Sequoia's key store abstractions is just introducing
overhead with no appreciable gain in functionality.

- This patch changes the Sequoia backend to use a local sqlite
database to store the public keys.
krista@3133
     1
// This file is under GNU General Public License 3.0
vb@1517
     2
// see LICENSE.txt
vb@1517
     3
vb@219
     4
#include "platform.h"
vb@130
     5
#include "pEp_internal.h"
vb@24
     6
#include "pgp_gpg.h"
vb@24
     7
vb@78
     8
#include <limits.h>
vb@78
     9
vb@62
    10
#include "wrappers.h"
vb@62
    11
vb@45
    12
#define _GPGERR(X) ((X) & 0xffffL)
vb@45
    13
vb@3045
    14
#ifdef NODLSYM
vb@3046
    15
#define DLOAD(X) gpg.X = X
vb@3045
    16
#else
vb@3045
    17
#define DLOAD(X) gpg.X = (X ## _t) (intptr_t) dlsym(gpgme, #X); assert(gpg.X)
vb@3045
    18
#endif
vb@3045
    19
vb@76
    20
static void *gpgme;
vb@76
    21
static struct gpg_s gpg;
vb@74
    22
krista@763
    23
static bool ensure_config_values(stringlist_t *keys, stringlist_t *values, const char* config_file_path)
vb@24
    24
{
vb@78
    25
    int r;
vb@78
    26
    stringlist_t *_k;
vb@78
    27
    stringlist_t *_v;
vb@79
    28
    unsigned int i;
vb@78
    29
    unsigned int found = 0;
krista@2690
    30
    bool eof_nl = 0;
vb@3075
    31
    char * rest = NULL;
krista@2690
    32
    const char* line_end;
krista@2690
    33
krista@2690
    34
#ifdef WIN32
krista@2690
    35
    line_end = "\r\n";
krista@2690
    36
#else
krista@2690
    37
    line_end = "\n";
krista@2690
    38
#endif    
vb@62
    39
roker@1559
    40
    FILE *f = Fopen(config_file_path, "r");
vb@63
    41
    if (f == NULL && errno == ENOMEM)
vb@62
    42
        return false;
vb@24
    43
vb@24
    44
    if (f != NULL) {
vb@3091
    45
        static char buf[MAX_LINELENGTH];
vb@78
    46
        int length = stringlist_length(keys);
vb@3091
    47
        char * s;
vb@78
    48
krista@846
    49
        // make sure we 1) have the same number of keys and values
krista@846
    50
        // and 2) we don't have more key/value pairs than
krista@846
    51
        // the size of the bitfield used to hold the indices
krista@846
    52
        // of key/value pairs matching keys in the config file.
vb@78
    53
        assert(length <= sizeof(unsigned int) * CHAR_BIT);
vb@78
    54
        assert(length == stringlist_length(values));
krista@846
    55
        if (!(length == stringlist_length(values) &&
krista@846
    56
              length <= sizeof(unsigned int) * CHAR_BIT)) {
edouard@1803
    57
            Fclose(f);
krista@1426
    58
krista@846
    59
            return false;
krista@846
    60
        }
krista@1426
    61
krista@2690
    62
        while ((s = Fgets(buf, MAX_LINELENGTH, f))) {
vb@3091
    63
            char *token = strtok_r(s, " \t\r\n", &rest);
krista@2690
    64
            for (_k = keys, _v = values, i = 1;
krista@2690
    65
                 _k != NULL;
krista@2690
    66
                 _k = _k->next, _v = _v->next, i <<= 1) {
krista@2690
    67
krista@2690
    68
                if (((found & i) != i) && token &&
krista@2690
    69
                    (strncmp(token, _k->value, strlen(_k->value)) == 0)) {
krista@2690
    70
                    found |= i;
krista@2690
    71
                    break;
vb@24
    72
                }
vb@24
    73
            }
krista@2690
    74
            if (feof(f)) {
krista@2690
    75
                eof_nl = 1;
krista@2690
    76
                break;
krista@2690
    77
            }
krista@2690
    78
        }
krista@2690
    79
krista@2690
    80
        if (!s && ferror(f))
krista@2690
    81
            return false;
krista@763
    82
        f = Freopen(config_file_path, "a", f);
vb@24
    83
    }
vb@24
    84
    else {
krista@763
    85
        f = Fopen(config_file_path, "w");
vb@24
    86
    }
vb@24
    87
vb@24
    88
    assert(f);
vb@24
    89
    if (f == NULL)
vb@24
    90
        return false;
krista@2690
    91
    
krista@2690
    92
    if (eof_nl)
krista@2690
    93
        r = Fprintf(f, line_end);
vb@24
    94
vb@78
    95
    for (i = 1, _k = keys, _v = values; _k != NULL; _k = _k->next,
vb@78
    96
            _v = _v->next, i <<= 1) {
vb@78
    97
        if ((found & i) == 0) {
krista@2690
    98
            r = Fprintf(f, "%s %s%s", _k->value, _v->value, line_end);
vb@79
    99
            assert(r >= 0);
krista@2690
   100
            if (r < 0)
edouard@1803
   101
                return false;
vb@78
   102
        }
vb@78
   103
    }
vb@62
   104
vb@63
   105
    r = Fclose(f);
vb@62
   106
    assert(r == 0);
edouard@1803
   107
    if (r != 0)
edouard@1803
   108
        return false;
vb@24
   109
vb@24
   110
    return true;
vb@24
   111
}
vb@24
   112
krista@2057
   113
char* _undot_address(const char* address) {
krista@2057
   114
    if (!address)
krista@2057
   115
        return NULL;
krista@2057
   116
    
krista@2057
   117
    int addr_len = strlen(address);
krista@2057
   118
    const char* at = strstr(address, "@");
krista@2057
   119
    
krista@2057
   120
    if (!at)
krista@2057
   121
        at = address + addr_len;
krista@2057
   122
        
krista@2066
   123
    char* retval = calloc(1, addr_len + 1);
vb@3083
   124
    assert(retval);
vb@3083
   125
    if (!retval)
vb@3083
   126
        return NULL;
krista@2057
   127
krista@2057
   128
    const char* addr_curr = address;
krista@2057
   129
    char* retval_curr = retval;
krista@2057
   130
    
krista@2057
   131
    while (addr_curr < at) {
krista@2057
   132
        if (*addr_curr == '.') {
krista@2057
   133
            addr_curr++;
krista@2057
   134
            continue;
krista@2057
   135
        }
krista@2057
   136
        *retval_curr = *addr_curr;
krista@2057
   137
        retval_curr++;
krista@2057
   138
        addr_curr++;
krista@2057
   139
    }
krista@2057
   140
    if (*addr_curr == '@')
krista@2057
   141
        strcat(retval_curr, addr_curr);
krista@2057
   142
    
krista@2057
   143
    return retval;
krista@2057
   144
}
krista@2057
   145
krista@2057
   146
static bool _email_heuristic_match(const char* str1, const char* str2) {
krista@2057
   147
    if (!str1 || !str2)
krista@2057
   148
        return false;
krista@2057
   149
        
krista@2057
   150
    if (strcasecmp(str1, str2) == 0)
krista@2057
   151
        return true;
krista@2057
   152
    
krista@2057
   153
    int len1 = strlen(str1);
krista@2057
   154
    int len2 = strlen(str2);
krista@2057
   155
    
krista@2057
   156
    // otherwise, we work against dotted usernames
krista@2057
   157
    const char* at1 = strstr(str1, "@");
krista@2057
   158
    const char* at2 = strstr(str2, "@");
krista@2057
   159
    
krista@2057
   160
    if (!at1)
krista@2057
   161
        at1 = str1 + len1;
krista@2057
   162
    
krista@2057
   163
    if (!at2)
krista@2057
   164
        at2 = str2 + len2;
krista@2057
   165
        
krista@2057
   166
    // This sucks. And is expensive. Here we go.
krista@2057
   167
    const char* str1_curr = str1;
krista@2057
   168
    const char* str2_curr = str2;
krista@2057
   169
    
krista@2057
   170
    while (str1_curr > at1 && str2_curr > at2) {
krista@2057
   171
        if (*str1_curr == '.') {
krista@2057
   172
            str1_curr++;
krista@2057
   173
            continue;
krista@2057
   174
        }
krista@2057
   175
krista@2057
   176
        if (*str2_curr == '.') {
krista@2057
   177
            str2_curr++;
krista@2057
   178
            continue;
krista@2057
   179
        }
krista@2057
   180
        
krista@2057
   181
        if (tolower(*str1_curr) != tolower(*str2_curr))
krista@2057
   182
            return false;
krista@2057
   183
        
krista@2057
   184
        str1_curr++;
krista@2057
   185
        str2_curr++;
krista@2057
   186
    }
krista@2057
   187
    if (str1_curr == at1 && str2_curr == at2)
krista@2057
   188
        return true;
krista@2057
   189
    
krista@2057
   190
    return false;
krista@2057
   191
}
krista@763
   192
krista@2461
   193
static PEP_STATUS _version_test(const char *s)
krista@2461
   194
{
krista@2461
   195
    char *_s = strdup(s);
krista@2461
   196
    if (!_s)
krista@2461
   197
        return PEP_OUT_OF_MEMORY;
krista@2461
   198
krista@2461
   199
    int major;
krista@2461
   200
    int minor;
krista@2461
   201
    int revision;
krista@2461
   202
krista@2461
   203
    char *lasts = NULL;
krista@2461
   204
    char *p = strtok_r(_s, ".", &lasts);
krista@2461
   205
    if (!p)
krista@2461
   206
        goto unsupported;
krista@2461
   207
    else
krista@2461
   208
        major = atoi(p);
krista@2461
   209
krista@2461
   210
    p = strtok_r(NULL, ".", &lasts);
krista@2461
   211
    if (!p)
krista@2461
   212
        goto unsupported;
krista@2461
   213
    else
krista@2461
   214
        minor = atoi(p);
krista@2461
   215
krista@2461
   216
    p = strtok_r(NULL, ".", &lasts);
krista@2461
   217
    if (!p)
krista@2461
   218
        goto unsupported;
krista@2461
   219
    else
krista@2461
   220
        revision = atoi(p);
krista@2461
   221
krista@2461
   222
    free(_s);
krista@2461
   223
    _s = NULL;
krista@2461
   224
krista@2461
   225
    if (major > 2)
krista@2461
   226
        return PEP_STATUS_OK;
krista@2461
   227
krista@2461
   228
    if (major == 2 && minor > 1)
krista@2461
   229
        return PEP_STATUS_OK;
krista@2461
   230
krista@2461
   231
    if (major == 2 && minor == 0 && revision == 30)
krista@2461
   232
        return PEP_STATUS_OK;
krista@2461
   233
krista@2461
   234
    if (major == 2 && minor == 1 && revision >= 17)
krista@2461
   235
        return PEP_STATUS_OK;
krista@2461
   236
krista@2461
   237
unsupported:
krista@2461
   238
    free(_s);
krista@2461
   239
    return PEP_INIT_UNSUPPORTED_GPG_VERSION;
krista@2461
   240
}
krista@2461
   241
vb@62
   242
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
vb@24
   243
{
vb@66
   244
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
   245
    gpgme_error_t gpgme_error;
vb@62
   246
    bool bResult;
krista@1426
   247
vb@62
   248
    if (in_first) {
vb@78
   249
        stringlist_t *conf_keys   = new_stringlist("keyserver");
vb@78
   250
        stringlist_t *conf_values = new_stringlist("hkp://keys.gnupg.net");
vb@79
   251
vb@78
   252
        stringlist_add(conf_keys, "cert-digest-algo");
vb@78
   253
        stringlist_add(conf_values, "SHA256");
vb@78
   254
vb@80
   255
        stringlist_add(conf_keys, "no-emit-version");
vb@80
   256
        stringlist_add(conf_values, "");
vb@80
   257
vb@80
   258
        stringlist_add(conf_keys, "no-comments");
vb@80
   259
        stringlist_add(conf_values, "");
vb@80
   260
vb@80
   261
        stringlist_add(conf_keys, "personal-cipher-preferences");
vb@80
   262
        stringlist_add(conf_values, "AES AES256 AES192 CAST5");
vb@80
   263
vb@80
   264
        stringlist_add(conf_keys, "personal-digest-preferences");
vb@312
   265
        stringlist_add(conf_values, "SHA256 SHA512 SHA384 SHA224");
krista@763
   266
krista@1569
   267
        stringlist_add(conf_keys, "ignore-time-conflict");
krista@1569
   268
        stringlist_add(conf_values, "");
krista@1569
   269
krista@2461
   270
        stringlist_add(conf_keys, "allow-freeform-uid");
krista@2461
   271
        stringlist_add(conf_values, "");
krista@2461
   272
krista@2703
   273
#if defined(WIN32) || defined(NDEBUG)
krista@2788
   274
        bResult = ensure_config_values(conf_keys, conf_values, gpg_conf());
krista@2703
   275
#else
krista@2788
   276
        bResult = ensure_config_values(conf_keys, conf_values, gpg_conf(false));
krista@2703
   277
#endif
vb@78
   278
        free_stringlist(conf_keys);
vb@78
   279
        free_stringlist(conf_values);
vb@78
   280
Edouard@175
   281
        assert(bResult);
krista@2461
   282
        if (!bResult) {
Edouard@175
   283
            status = PEP_INIT_NO_GPG_HOME;
vb@2834
   284
            goto pEp_error;
Edouard@175
   285
        }
Edouard@175
   286
krista@763
   287
        conf_keys = new_stringlist("default-cache-ttl");
krista@763
   288
        conf_values = new_stringlist("300");
krista@763
   289
krista@763
   290
        stringlist_add(conf_keys, "max-cache-ttl");
krista@763
   291
        stringlist_add(conf_values, "1200");
krista@763
   292
krista@2703
   293
#if defined(WIN32) || defined(NDEBUG)
krista@2788
   294
        bResult = ensure_config_values(conf_keys, conf_values, gpg_agent_conf());
krista@2703
   295
#else        
krista@2788
   296
        bResult = ensure_config_values(conf_keys, conf_values, gpg_agent_conf(false));
krista@2703
   297
#endif
krista@763
   298
        free_stringlist(conf_keys);
krista@763
   299
        free_stringlist(conf_values);
krista@763
   300
krista@763
   301
        assert(bResult);
krista@2461
   302
        if (!bResult) {
krista@2461
   303
            status = PEP_INIT_CANNOT_CONFIG_GPG_AGENT;
vb@2834
   304
            goto pEp_error;
krista@763
   305
        }
Edouard@175
   306
vb@3045
   307
#ifndef NODLSYM
vb@62
   308
        gpgme = dlopen(LIBGPGME, RTLD_LAZY);
vb@62
   309
        if (gpgme == NULL) {
vb@66
   310
            status = PEP_INIT_CANNOT_LOAD_GPGME;
vb@2834
   311
            goto pEp_error;
vb@62
   312
        }
vb@3045
   313
#endif
vb@62
   314
vb@62
   315
        memset(&gpg, 0, sizeof(struct gpg_s));
vb@62
   316
vb@3048
   317
        DLOAD(gpgme_get_engine_info);
krista@2461
   318
krista@2461
   319
        gpgme_engine_info_t info;
krista@2461
   320
        int err = gpg.gpgme_get_engine_info(&info);
krista@2461
   321
        assert(err == GPG_ERR_NO_ERROR);
krista@2461
   322
        if (err != GPG_ERR_NO_ERROR)
krista@2461
   323
            return PEP_OUT_OF_MEMORY;
krista@2461
   324
krista@2461
   325
        assert(info->version);
krista@2461
   326
        if (!info->version)
krista@2461
   327
            return PEP_INIT_CANNOT_DETERMINE_GPG_VERSION;
krista@2461
   328
krista@2461
   329
        status = _version_test(info->version);
krista@2461
   330
        if (status != PEP_STATUS_OK)
krista@2461
   331
            return status;
krista@2461
   332
vb@3045
   333
#ifdef NODLSYM
vb@3045
   334
        gpg.gpgme_check = gpgme_check_version;
vb@3045
   335
#else
vb@3045
   336
        gpg.gpgme_check = (gpgme_check_t) (intptr_t) dlsym(gpgme, "gpgme_check_version");
vb@62
   337
        assert(gpg.gpgme_check);
vb@3045
   338
#endif
vb@62
   339
vb@3045
   340
        DLOAD(gpgme_set_locale);
vb@3045
   341
        DLOAD(gpgme_new);
vb@3045
   342
        DLOAD(gpgme_release);
vb@3045
   343
        DLOAD(gpgme_set_protocol);
vb@3045
   344
        DLOAD(gpgme_set_armor);
vb@3045
   345
        DLOAD(gpgme_data_new);
vb@3045
   346
        DLOAD(gpgme_data_new_from_mem);
vb@3045
   347
        DLOAD(gpgme_data_new_from_cbs);
vb@3045
   348
        DLOAD(gpgme_data_release);
vb@3045
   349
        DLOAD(gpgme_data_identify);
vb@3045
   350
        DLOAD(gpgme_data_seek);
vb@3045
   351
        DLOAD(gpgme_data_read);
vb@3045
   352
        DLOAD(gpgme_op_decrypt);
vb@3045
   353
        DLOAD(gpgme_op_verify);
vb@3045
   354
        DLOAD(gpgme_op_decrypt_verify);
vb@3045
   355
        DLOAD(gpgme_op_decrypt_result);
vb@3045
   356
        DLOAD(gpgme_op_encrypt_sign);
vb@3045
   357
        DLOAD(gpgme_op_encrypt);
krista@3140
   358
        DLOAD(gpgme_op_sign);
vb@3045
   359
        DLOAD(gpgme_op_verify_result);
vb@3045
   360
        DLOAD(gpgme_signers_clear);
vb@3045
   361
        DLOAD(gpgme_signers_add);
vb@3045
   362
        DLOAD(gpgme_set_passphrase_cb);
vb@3045
   363
        DLOAD(gpgme_get_key);
krista@1920
   364
        
vb@3045
   365
#ifdef GPGME_VERSION_NUMBER
vb@3045
   366
#if (GPGME_VERSION_NUMBER >= 0x010700)
vb@3045
   367
        DLOAD(gpgme_op_createkey);
vb@3045
   368
        DLOAD(gpgme_op_createsubkey);
vb@3045
   369
#endif
vb@3045
   370
#endif
vb@62
   371
vb@3045
   372
        DLOAD(gpgme_op_genkey);
vb@3045
   373
        DLOAD(gpgme_op_genkey_result);
vb@3045
   374
        DLOAD(gpgme_op_delete);
vb@3045
   375
        DLOAD(gpgme_op_import);
vb@3045
   376
        DLOAD(gpgme_op_import_result);
vb@3045
   377
        DLOAD(gpgme_op_export);
vb@3045
   378
        DLOAD(gpgme_set_keylist_mode);
vb@3045
   379
        DLOAD(gpgme_get_keylist_mode);
vb@3045
   380
        DLOAD(gpgme_op_keylist_start);
vb@3045
   381
        DLOAD(gpgme_op_keylist_next);
vb@3045
   382
        DLOAD(gpgme_op_keylist_end);
vb@3045
   383
        DLOAD(gpgme_op_import_keys);
vb@3045
   384
        DLOAD(gpgme_key_ref);
vb@3045
   385
        DLOAD(gpgme_key_unref);
vb@3045
   386
		DLOAD(gpgme_key_release);
vb@3045
   387
        DLOAD(gpgme_op_edit);
vb@3045
   388
        DLOAD(gpgme_io_write);
vb@223
   389
vb@62
   390
        gpg.version = gpg.gpgme_check(NULL);
krista@1426
   391
roker@879
   392
        const char * const cLocal = setlocale(LC_ALL, NULL);
Edouard@348
   393
        if (!cLocal || (strcmp(cLocal, "C") == 0))
vb@62
   394
            setlocale(LC_ALL, "");
vb@62
   395
vb@62
   396
        gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
vb@62
   397
#ifdef LC_MESSAGES // Windoze
vb@62
   398
        gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
vb@62
   399
#endif
vb@24
   400
    }
vb@24
   401
krista@1426
   402
    gpg.gpgme_check(NULL);
vb@62
   403
    gpgme_error = gpg.gpgme_new(&session->ctx);
vb@45
   404
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   405
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@66
   406
        status = PEP_INIT_GPGME_INIT_FAILED;
vb@2834
   407
        goto pEp_error;
vb@24
   408
    }
vb@46
   409
    assert(session->ctx);
vb@24
   410
vb@62
   411
    gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
vb@45
   412
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   413
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   414
vb@62
   415
    gpg.gpgme_set_armor(session->ctx, 1);
vb@24
   416
vb@24
   417
    return PEP_STATUS_OK;
vb@66
   418
vb@2834
   419
pEp_error:
vb@66
   420
    pgp_release(session, in_first);
vb@66
   421
    return status;
vb@24
   422
}
vb@24
   423
vb@62
   424
void pgp_release(PEP_SESSION session, bool out_last)
vb@24
   425
{
vb@62
   426
    if (session->ctx) {
vb@74
   427
        gpg.gpgme_release(session->ctx);
vb@62
   428
        session->ctx = NULL;
vb@62
   429
    }
vb@62
   430
vb@74
   431
    if (out_last)
vb@74
   432
        if (gpgme)
vb@74
   433
            dlclose(gpgme);
vb@24
   434
}
vb@24
   435
vb@24
   436
PEP_STATUS pgp_decrypt_and_verify(
vb@24
   437
    PEP_SESSION session, const char *ctext, size_t csize,
krista@1397
   438
    const char *dsigtext, size_t dsigsize,
krista@2978
   439
    char **ptext, size_t *psize, stringlist_t **keylist,
krista@2978
   440
    char** filename_ptr
vb@24
   441
    )
vb@24
   442
{
vb@24
   443
    PEP_STATUS result;
vb@24
   444
    gpgme_error_t gpgme_error;
vb@24
   445
    gpgme_data_t cipher, plain;
vb@24
   446
    gpgme_data_type_t dt;
krista@1579
   447
    gpgme_decrypt_result_t gpgme_decrypt_result = NULL;
vb@24
   448
vb@24
   449
    stringlist_t *_keylist = NULL;
roker@723
   450
    //int i_key = 0;
vb@24
   451
vb@46
   452
    assert(session);
vb@24
   453
    assert(ctext);
vb@24
   454
    assert(csize);
vb@24
   455
    assert(ptext);
vb@24
   456
    assert(psize);
vb@24
   457
    assert(keylist);
vb@24
   458
vb@24
   459
    *ptext = NULL;
vb@24
   460
    *psize = 0;
vb@24
   461
    *keylist = NULL;
vb@24
   462
vb@74
   463
    gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
vb@45
   464
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   465
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   466
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   467
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   468
            return PEP_OUT_OF_MEMORY;
vb@24
   469
        else
vb@24
   470
            return PEP_UNKNOWN_ERROR;
vb@24
   471
    }
vb@24
   472
vb@74
   473
    gpgme_error = gpg.gpgme_data_new(&plain);
vb@45
   474
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   475
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   476
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   477
        gpg.gpgme_data_release(cipher);
vb@24
   478
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   479
            return PEP_OUT_OF_MEMORY;
vb@24
   480
        else
vb@24
   481
            return PEP_UNKNOWN_ERROR;
vb@24
   482
    }
vb@24
   483
krista@1579
   484
vb@74
   485
    dt = gpg.gpgme_data_identify(cipher);
vb@24
   486
    switch (dt) {
edouard@1421
   487
#if GPGME_VERSION_NUMBER > 0x010600
vb@1419
   488
    case GPGME_DATA_TYPE_PGP_ENCRYPTED:
edouard@1420
   489
#endif
vb@24
   490
    case GPGME_DATA_TYPE_PGP_SIGNED:
vb@24
   491
    case GPGME_DATA_TYPE_PGP_OTHER:
krista@1426
   492
        if (dsigtext) {
krista@1426
   493
            gpgme_error = gpg.gpgme_op_decrypt(session->ctx, cipher, plain);
krista@1426
   494
        }
krista@1426
   495
        else {
krista@1426
   496
            gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
krista@1426
   497
                plain);
krista@1426
   498
        }
vb@45
   499
        gpgme_error = _GPGERR(gpgme_error);
vb@24
   500
        assert(gpgme_error != GPG_ERR_INV_VALUE);
krista@2681
   501
//        assert(gpgme_error != GPG_ERR_NO_DATA);
vb@24
   502
vb@24
   503
        switch (gpgme_error) {
vb@344
   504
            case GPG_ERR_NO_ERROR:
vb@344
   505
            {
krista@2681
   506
                // EFail: We should get an MDC warning if there were modifications
krista@2681
   507
                //        and never make it here. So the decrypted text is not
krista@2681
   508
                //        returned regardless.
krista@1579
   509
                gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
krista@1591
   510
                /* NOW is when we have to process the decrypt_result, period.
krista@1591
   511
                   it is only valid until the next call on the context. */
krista@1591
   512
                   
krista@1591
   513
                gpgme_key_t key;
krista@1591
   514
                memset(&key,0,sizeof(key));
krista@1591
   515
                stringlist_t* recipient_keylist = new_stringlist(NULL);
krista@1592
   516
                if (!recipient_keylist) {
krista@1592
   517
                    gpg.gpgme_data_release(plain);
krista@1592
   518
                    gpg.gpgme_data_release(cipher);
krista@1591
   519
                    return PEP_OUT_OF_MEMORY;
krista@1592
   520
                }
krista@1591
   521
               
krista@1591
   522
                if (gpgme_decrypt_result != NULL) {
krista@1591
   523
                    stringlist_t* _keylist = recipient_keylist;
krista@1591
   524
                    for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
krista@1591
   525
                        // GPGME may give subkey's fpr instead of primary key's fpr.
krista@1591
   526
                        // Therefore we ask for the primary fingerprint instead
krista@1591
   527
                        // we assume that gpgme_get_key can find key by subkey's fpr
krista@1591
   528
                        gpgme_error = gpg.gpgme_get_key(session->ctx,
krista@1591
   529
                            r->keyid, &key, 0);
krista@1591
   530
                        gpgme_error = _GPGERR(gpgme_error);
krista@1591
   531
                        assert(gpgme_error != GPG_ERR_ENOMEM);
krista@1591
   532
                        if (gpgme_error == GPG_ERR_ENOMEM) {
krista@1591
   533
                            free_stringlist(_keylist);
krista@1591
   534
                            result = PEP_OUT_OF_MEMORY;
krista@1591
   535
                        }
krista@1591
   536
                        // Primary key is given as the first subkey
krista@1591
   537
                        if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1591
   538
                            key && key->subkeys && key->subkeys->fpr
krista@1591
   539
                            && key->subkeys->fpr[0]) {
krista@1591
   540
                            _keylist = stringlist_add(_keylist, key->subkeys->fpr);
krista@1591
   541
 
krista@1591
   542
                            gpg.gpgme_key_unref(key);
krista@1591
   543
 
krista@1591
   544
                        }
krista@1591
   545
                    }
krista@1591
   546
                    assert(_keylist);
krista@1591
   547
                    if (_keylist == NULL) {
krista@1591
   548
                        free_stringlist(recipient_keylist);
krista@1591
   549
                        if (*keylist)
krista@1591
   550
                            free_stringlist(*keylist);
krista@1591
   551
                        *keylist = NULL;
krista@1591
   552
                        result = PEP_OUT_OF_MEMORY;
krista@1591
   553
                    }
krista@2978
   554
                    // Get filename, if desired
krista@2978
   555
                    if (filename_ptr) {
krista@2978
   556
                        const char* fname = gpgme_decrypt_result->file_name;
krista@2978
   557
                        if (fname) {
krista@2978
   558
                            *filename_ptr = strdup(fname);
krista@2978
   559
                            if (!(*filename_ptr))
krista@2978
   560
                                result = PEP_OUT_OF_MEMORY;
krista@2978
   561
                        }
krista@3120
   562
                    }                    
krista@1591
   563
                } /* Ok, so now we have any recipients it was encrypted for
krista@1591
   564
                     in recipient_keylist */
krista@1591
   565
            
krista@1591
   566
                   
vb@344
   567
                gpgme_verify_result_t gpgme_verify_result;
vb@344
   568
                char *_buffer = NULL;
vb@344
   569
                size_t reading;
vb@344
   570
                size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
vb@344
   571
                gpgme_signature_t gpgme_signature;
vb@24
   572
vb@344
   573
                assert(length != -1);
vb@344
   574
                gpg.gpgme_data_seek(plain, 0, SEEK_SET);
vb@24
   575
vb@344
   576
                // TODO: make things less memory consuming
vb@344
   577
                // the following algorithm allocates memory for the complete
vb@344
   578
                // text
vb@24
   579
vb@344
   580
                _buffer = malloc(length + 1);
vb@344
   581
                assert(_buffer);
vb@344
   582
                if (_buffer == NULL) {
vb@74
   583
                    gpg.gpgme_data_release(plain);
vb@74
   584
                    gpg.gpgme_data_release(cipher);
krista@1591
   585
                    if (recipient_keylist)
krista@1591
   586
                        free_stringlist(recipient_keylist);
vb@24
   587
                    return PEP_OUT_OF_MEMORY;
vb@24
   588
                }
vb@24
   589
vb@344
   590
                reading = gpg.gpgme_data_read(plain, _buffer, length);
vb@344
   591
                assert(length == reading);
vb@24
   592
krista@1427
   593
                if (dsigtext) {  // Is this safe to do?
krista@1427
   594
                    gpgme_data_t sigdata;
krista@1427
   595
                    gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
krista@1427
   596
                                                dsigsize, 0);
vb@1434
   597
                    gpg.gpgme_op_verify(session->ctx, sigdata, plain, NULL);
krista@1431
   598
                    gpg.gpgme_data_release(sigdata);
krista@1427
   599
                }
krista@1426
   600
vb@344
   601
                gpgme_verify_result =
vb@344
   602
                    gpg.gpgme_op_verify_result(session->ctx);
vb@344
   603
                assert(gpgme_verify_result);
vb@344
   604
                gpgme_signature = gpgme_verify_result->signatures;
krista@1426
   605
krista@1584
   606
                if (!gpgme_signature) {
krista@1584
   607
                    // try cleartext sig verification
krista@1584
   608
                    gpg.gpgme_op_verify(session->ctx, plain, NULL, plain);
krista@1584
   609
                    gpgme_verify_result =
krista@1584
   610
                        gpg.gpgme_op_verify_result(session->ctx);
krista@1584
   611
                            assert(gpgme_verify_result);
roker@2055
   612
                    gpgme_signature = gpgme_verify_result->signatures;
krista@1584
   613
                }
krista@1584
   614
vb@344
   615
                if (gpgme_signature) {
vb@344
   616
                    stringlist_t *k;
vb@344
   617
                    _keylist = new_stringlist(NULL);
vb@24
   618
                    assert(_keylist);
vb@24
   619
                    if (_keylist == NULL) {
vb@344
   620
                        gpg.gpgme_data_release(plain);
vb@344
   621
                        gpg.gpgme_data_release(cipher);
vb@344
   622
                        free(_buffer);
vb@344
   623
                        return PEP_OUT_OF_MEMORY;
vb@344
   624
                    }
vb@344
   625
                    k = _keylist;
vb@344
   626
vb@344
   627
                    result = PEP_DECRYPTED_AND_VERIFIED;
krista@1427
   628
                    gpg.gpgme_check(NULL);
krista@1591
   629
                    do { /* get all signers and put them at the front off
krista@1591
   630
                            the keylist (likely only one) */
vb@344
   631
                        switch (_GPGERR(gpgme_signature->status)) {
vb@344
   632
                        case GPG_ERR_NO_ERROR:
Edouard@505
   633
                        {
krista@1426
   634
                            // Some versions of gpg returns signer's
Edouard@674
   635
                            // signing subkey fingerprint instead of
Edouard@674
   636
                            // signer's primary key fingerprint.
krista@1426
   637
                            // This is meant to get signer's primary
Edouard@674
   638
                            // key fingerprint, using subkey's.
Edouard@674
   639
Edouard@728
   640
                            gpgme_key_t key = NULL;
Edouard@505
   641
Edouard@505
   642
                            gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@505
   643
                                gpgme_signature->fpr, &key, 0);
Edouard@505
   644
                            gpgme_error = _GPGERR(gpgme_error);
Edouard@505
   645
                            assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@505
   646
                            if (gpgme_error == GPG_ERR_ENOMEM) {
Edouard@505
   647
                                free_stringlist(_keylist);
Edouard@505
   648
                                gpg.gpgme_data_release(plain);
Edouard@505
   649
                                gpg.gpgme_data_release(cipher);
Edouard@505
   650
                                free(_buffer);
Edouard@505
   651
                                return PEP_OUT_OF_MEMORY;
Edouard@505
   652
                            }
Edouard@505
   653
                            // Primary key is given as the first subkey
krista@1426
   654
                            if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1426
   655
                                key && key->subkeys && key->subkeys->fpr
Edouard@674
   656
                                && key->subkeys->fpr[0])
Edouard@674
   657
                            {
Edouard@505
   658
                                k = stringlist_add(k, key->subkeys->fpr);
Edouard@677
   659
Edouard@674
   660
                                gpg.gpgme_key_unref(key);
Edouard@677
   661
Edouard@677
   662
                                if (k == NULL) {
Edouard@677
   663
                                    free_stringlist(_keylist);
krista@1591
   664
                                    if (recipient_keylist)
krista@1591
   665
                                        free (recipient_keylist);
Edouard@677
   666
                                    gpg.gpgme_data_release(plain);
Edouard@677
   667
                                    gpg.gpgme_data_release(cipher);
Edouard@677
   668
                                    free(_buffer);
Edouard@677
   669
                                    return PEP_OUT_OF_MEMORY;
Edouard@677
   670
                                }
Edouard@674
   671
                            }
krista@1426
   672
                            else
Edouard@674
   673
                            {
Edouard@505
   674
                                result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@505
   675
                                break;
Edouard@505
   676
                            }
vb@344
   677
                            break;
Edouard@505
   678
                        }
vb@344
   679
                        case GPG_ERR_CERT_REVOKED:
vb@344
   680
                        case GPG_ERR_BAD_SIGNATURE:
krista@2978
   681
                            result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
krista@2703
   682
                            //result = PEP_DECRYPT_BAD_SIGNATURE;
vb@344
   683
                            break;
vb@344
   684
                        case GPG_ERR_SIG_EXPIRED:
vb@344
   685
                        case GPG_ERR_KEY_EXPIRED:
vb@344
   686
                        case GPG_ERR_NO_PUBKEY:
vb@344
   687
                            k = stringlist_add(k, gpgme_signature->fpr);
Edouard@674
   688
                            if (k == NULL) {
Edouard@674
   689
                                free_stringlist(_keylist);
krista@1591
   690
                                if (recipient_keylist)
krista@1591
   691
                                    free_stringlist(recipient_keylist);
Edouard@674
   692
                                gpg.gpgme_data_release(plain);
Edouard@674
   693
                                gpg.gpgme_data_release(cipher);
Edouard@674
   694
                                free(_buffer);
Edouard@674
   695
                                return PEP_OUT_OF_MEMORY;
Edouard@674
   696
                            }
vb@344
   697
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@344
   698
                                result = PEP_DECRYPTED;
vb@344
   699
                            break;
vb@344
   700
                        case GPG_ERR_GENERAL:
vb@344
   701
                            break;
vb@344
   702
                        default:
vb@344
   703
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@344
   704
                                result = PEP_DECRYPTED;
vb@344
   705
                            break;
vb@344
   706
                        }
vb@344
   707
                    } while ((gpgme_signature = gpgme_signature->next));
vb@344
   708
                }
vb@344
   709
                else {
vb@344
   710
                    result = PEP_DECRYPTED;
vb@344
   711
                }
vb@344
   712
vb@344
   713
                if (result == PEP_DECRYPTED_AND_VERIFIED
vb@344
   714
                    || result == PEP_DECRYPTED) {
vb@344
   715
                    *ptext = _buffer;
vb@344
   716
                    *psize = reading;
vb@344
   717
                    (*ptext)[*psize] = 0; // safeguard for naive users
vb@344
   718
                    *keylist = _keylist;
edouard@1933
   719
                    if (recipient_keylist) {
krista@1591
   720
                        if (!_keylist)
roker@2055
   721
                            *keylist = new_stringlist(""); // no sig
krista@1591
   722
                        if (!(*keylist)) {
krista@1591
   723
                            free_stringlist(_keylist);
krista@1591
   724
                            if (recipient_keylist)
krista@1591
   725
                                free_stringlist(recipient_keylist);
krista@1591
   726
                            gpg.gpgme_data_release(plain);
krista@1591
   727
                            gpg.gpgme_data_release(cipher);
krista@1591
   728
                            free(_buffer);
krista@1591
   729
                            return PEP_OUT_OF_MEMORY;
roker@2055
   730
                        }
krista@1591
   731
                        stringlist_append(*keylist, recipient_keylist);
edouard@1933
   732
                    }
vb@344
   733
                }
vb@344
   734
                else {
vb@344
   735
                    free_stringlist(_keylist);
krista@1591
   736
                    if (recipient_keylist)
krista@1591
   737
                        free_stringlist(recipient_keylist);
vb@344
   738
                    free(_buffer);
vb@344
   739
                }
vb@344
   740
                break;
vb@344
   741
            }
vb@344
   742
            case GPG_ERR_BAD_PASSPHRASE:
krista@2681
   743
            case GPG_ERR_NO_DATA:
Edouard@725
   744
                result = PEP_DECRYPT_NO_KEY;
Edouard@725
   745
                break;
vb@344
   746
            case GPG_ERR_DECRYPT_FAILED:
vb@344
   747
            default:
vb@344
   748
            {
krista@1579
   749
                gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
vb@344
   750
                result = PEP_DECRYPT_NO_KEY;
vb@344
   751
vb@344
   752
                if (gpgme_decrypt_result != NULL) {
vb@344
   753
                    if (gpgme_decrypt_result->unsupported_algorithm)
vb@344
   754
                        *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
vb@344
   755
                    else
vb@344
   756
                        *keylist = new_stringlist("");
vb@344
   757
                    assert(*keylist);
vb@344
   758
                    if (*keylist == NULL) {
vb@24
   759
                        result = PEP_OUT_OF_MEMORY;
vb@24
   760
                        break;
vb@24
   761
                    }
vb@24
   762
                }
vb@24
   763
            }
vb@24
   764
        }
vb@24
   765
        break;
vb@24
   766
vb@24
   767
    default:
vb@24
   768
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   769
    }
vb@24
   770
vb@74
   771
    gpg.gpgme_data_release(plain);
vb@74
   772
    gpg.gpgme_data_release(cipher);
vb@24
   773
    return result;
vb@24
   774
}
vb@24
   775
vb@24
   776
PEP_STATUS pgp_verify_text(
vb@24
   777
    PEP_SESSION session, const char *text, size_t size,
vb@24
   778
    const char *signature, size_t sig_size, stringlist_t **keylist
vb@24
   779
    )
vb@24
   780
{
vb@24
   781
    PEP_STATUS result;
vb@24
   782
    gpgme_error_t gpgme_error;
vb@24
   783
    gpgme_data_t d_text, d_sig;
vb@24
   784
    stringlist_t *_keylist;
vb@24
   785
vb@24
   786
    assert(session);
vb@24
   787
    assert(text);
vb@24
   788
    assert(size);
vb@24
   789
    assert(signature);
vb@24
   790
    assert(sig_size);
vb@24
   791
    assert(keylist);
vb@24
   792
vb@24
   793
    *keylist = NULL;
vb@24
   794
vb@74
   795
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
vb@45
   796
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   797
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   798
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   799
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   800
            return PEP_OUT_OF_MEMORY;
vb@24
   801
        else
vb@24
   802
            return PEP_UNKNOWN_ERROR;
vb@24
   803
    }
vb@24
   804
vb@74
   805
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
vb@45
   806
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   807
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   808
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   809
        gpg.gpgme_data_release(d_text);
vb@24
   810
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   811
            return PEP_OUT_OF_MEMORY;
vb@24
   812
        else
vb@24
   813
            return PEP_UNKNOWN_ERROR;
vb@24
   814
    }
vb@24
   815
vb@74
   816
    gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
vb@45
   817
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   818
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
   819
vb@24
   820
    switch (gpgme_error) {
vb@24
   821
    case GPG_ERR_NO_ERROR:
vb@24
   822
    {
vb@24
   823
        gpgme_verify_result_t gpgme_verify_result;
vb@24
   824
        gpgme_signature_t gpgme_signature;
vb@24
   825
vb@24
   826
        gpgme_verify_result =
vb@74
   827
            gpg.gpgme_op_verify_result(session->ctx);
vb@24
   828
        assert(gpgme_verify_result);
vb@24
   829
        gpgme_signature = gpgme_verify_result->signatures;
vb@24
   830
vb@24
   831
        if (gpgme_signature) {
vb@24
   832
            stringlist_t *k;
vb@24
   833
            _keylist = new_stringlist(NULL);
vb@24
   834
            assert(_keylist);
vb@24
   835
            if (_keylist == NULL) {
vb@74
   836
                gpg.gpgme_data_release(d_text);
vb@74
   837
                gpg.gpgme_data_release(d_sig);
vb@24
   838
                return PEP_OUT_OF_MEMORY;
vb@24
   839
            }
vb@24
   840
            k = _keylist;
vb@24
   841
vb@24
   842
            result = PEP_VERIFIED;
vb@24
   843
            do {
Edouard@502
   844
                gpgme_key_t key;
Edouard@502
   845
                memset(&key,0,sizeof(key));
Edouard@502
   846
krista@1426
   847
                // GPGME may give subkey's fpr instead of primary key's fpr.
Edouard@502
   848
                // Therefore we ask for the primary fingerprint instead
Edouard@502
   849
                // we assume that gpgme_get_key can find key by subkey's fpr
Edouard@502
   850
                gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@502
   851
                    gpgme_signature->fpr, &key, 0);
Edouard@502
   852
                gpgme_error = _GPGERR(gpgme_error);
Edouard@502
   853
                assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@502
   854
                if (gpgme_error == GPG_ERR_ENOMEM) {
vb@24
   855
                    free_stringlist(_keylist);
Edouard@505
   856
                    gpg.gpgme_data_release(d_text);
Edouard@505
   857
                    gpg.gpgme_data_release(d_sig);
vb@24
   858
                    return PEP_OUT_OF_MEMORY;
vb@24
   859
                }
Edouard@502
   860
                // Primary key is given as the first subkey
krista@1426
   861
                if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1426
   862
                    key && key->subkeys && key->subkeys->fpr
Edouard@674
   863
                    && key->subkeys->fpr[0])
Edouard@674
   864
                {
Edouard@504
   865
                    k = stringlist_add(k, key->subkeys->fpr);
Edouard@677
   866
Edouard@674
   867
                    gpg.gpgme_key_unref(key);
Edouard@677
   868
Edouard@677
   869
                    if (k == NULL) {
Edouard@677
   870
                        free_stringlist(_keylist);
Edouard@677
   871
                        gpg.gpgme_data_release(d_text);
Edouard@677
   872
                        gpg.gpgme_data_release(d_sig);
Edouard@677
   873
                        return PEP_OUT_OF_MEMORY;
Edouard@677
   874
                    }
Edouard@502
   875
                }
Edouard@502
   876
                else {
Edouard@502
   877
                    result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@502
   878
                    break;
Edouard@502
   879
                }
Edouard@502
   880
vb@24
   881
                if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
vb@24
   882
                    if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
vb@24
   883
                        || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
vb@24
   884
                        if (result == PEP_VERIFIED
vb@24
   885
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
   886
                            result = PEP_UNENCRYPTED;
vb@24
   887
                    }
vb@24
   888
                    else {
vb@24
   889
                        result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@24
   890
                        break;
vb@24
   891
                    }
vb@24
   892
                }
vb@24
   893
                else {
vb@24
   894
                    if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
vb@24
   895
                        if (result == PEP_VERIFIED)
vb@24
   896
                            result = PEP_VERIFIED_AND_TRUSTED;
vb@24
   897
                    }
vb@24
   898
                    if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
vb@24
   899
                        // good
vb@24
   900
                    }
vb@24
   901
                    else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
vb@24
   902
                        result = PEP_VERIFY_NO_KEY;
vb@24
   903
                    }
vb@24
   904
                    else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
vb@24
   905
                        if (result == PEP_VERIFIED
vb@24
   906
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
   907
                            result = PEP_UNENCRYPTED;
vb@24
   908
                    }
vb@24
   909
                    else {
vb@24
   910
                        // do nothing
vb@24
   911
                    }
vb@24
   912
                }
vb@24
   913
            } while ((gpgme_signature = gpgme_signature->next));
vb@24
   914
            *keylist = _keylist;
vb@24
   915
        }
vb@24
   916
        else {
vb@24
   917
            result = PEP_UNENCRYPTED;
vb@24
   918
        }
vb@24
   919
        break;
vb@24
   920
    }
vb@24
   921
        break;
vb@24
   922
    case GPG_ERR_NO_DATA:
vb@24
   923
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   924
        break;
vb@24
   925
    case GPG_ERR_INV_VALUE:
vb@24
   926
    default:
vb@24
   927
        result = PEP_UNKNOWN_ERROR;
vb@24
   928
        break;
vb@24
   929
    }
vb@24
   930
vb@74
   931
    gpg.gpgme_data_release(d_text);
vb@74
   932
    gpg.gpgme_data_release(d_sig);
vb@24
   933
vb@24
   934
    return result;
vb@24
   935
}
vb@24
   936
krista@3131
   937
PEP_STATUS pgp_sign_only(    
krista@3131
   938
    PEP_SESSION session, const char* fpr, const char *ptext,
krista@3131
   939
    size_t psize, char **stext, size_t *ssize
krista@3131
   940
)
krista@3131
   941
{
krista@3131
   942
    assert(session);
krista@3131
   943
    assert(fpr && fpr[0]);
krista@3131
   944
    assert(ptext);
krista@3131
   945
    assert(psize);
krista@3131
   946
    assert(stext);
krista@3131
   947
    assert(ssize);
krista@3131
   948
krista@3131
   949
    PEP_STATUS result;
krista@3131
   950
    gpgme_error_t gpgme_error;
krista@3131
   951
    gpgme_data_t plain, signed_text;
krista@3131
   952
    gpgme_key_t* signer_key_ptr;
krista@3131
   953
krista@3135
   954
    gpgme_sig_mode_t sign_mode = GPGME_SIG_MODE_DETACH;
krista@3131
   955
       
krista@3131
   956
    *stext = NULL;
krista@3131
   957
    *ssize = 0;
krista@3131
   958
krista@3131
   959
    gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
krista@3131
   960
    gpgme_error = _GPGERR(gpgme_error);
krista@3131
   961
    assert(gpgme_error == GPG_ERR_NO_ERROR);
krista@3131
   962
    if (gpgme_error != GPG_ERR_NO_ERROR) {
krista@3131
   963
        if (gpgme_error == GPG_ERR_ENOMEM)
krista@3131
   964
            return PEP_OUT_OF_MEMORY;
krista@3131
   965
        else
krista@3131
   966
            return PEP_UNKNOWN_ERROR;
krista@3131
   967
    }
krista@3131
   968
krista@3131
   969
    gpgme_error = gpg.gpgme_data_new(&signed_text);
krista@3131
   970
    gpgme_error = _GPGERR(gpgme_error);
krista@3131
   971
    assert(gpgme_error == GPG_ERR_NO_ERROR);
krista@3131
   972
    if (gpgme_error != GPG_ERR_NO_ERROR) {
krista@3131
   973
        gpg.gpgme_data_release(plain);
krista@3131
   974
        if (gpgme_error == GPG_ERR_ENOMEM)
krista@3131
   975
            return PEP_OUT_OF_MEMORY;
krista@3131
   976
        else
krista@3131
   977
            return PEP_UNKNOWN_ERROR;
krista@3131
   978
    }
krista@3131
   979
krista@3131
   980
    signer_key_ptr = calloc(1, sizeof(gpgme_key_t));   
krista@3131
   981
    assert(signer_key_ptr);
krista@3131
   982
    if (signer_key_ptr == NULL) {
krista@3131
   983
        gpg.gpgme_data_release(plain);
krista@3131
   984
        gpg.gpgme_data_release(signed_text);
krista@3131
   985
        return PEP_OUT_OF_MEMORY;
krista@3131
   986
    }
krista@3131
   987
krista@3131
   988
    gpg.gpgme_signers_clear(session->ctx);
krista@3131
   989
krista@3131
   990
    // Get signing key
krista@3131
   991
    gpgme_error = gpg.gpgme_get_key(session->ctx, fpr,
krista@3131
   992
                                    signer_key_ptr, 0);
krista@3131
   993
    gpgme_error = _GPGERR(gpgme_error);
krista@3131
   994
    assert(gpgme_error != GPG_ERR_ENOMEM);
krista@3133
   995
    gpgme_error_t _gpgme_error;
krista@3133
   996
    
krista@3131
   997
    switch (gpgme_error) {
krista@3131
   998
    case GPG_ERR_ENOMEM:
krista@3131
   999
        gpg.gpgme_key_unref(*signer_key_ptr);
krista@3131
  1000
        free(signer_key_ptr);
krista@3131
  1001
        gpg.gpgme_data_release(plain);
krista@3131
  1002
        gpg.gpgme_data_release(signed_text);
krista@3131
  1003
        return PEP_OUT_OF_MEMORY;
krista@3131
  1004
    case GPG_ERR_NO_ERROR:
krista@3133
  1005
        _gpgme_error = gpg.gpgme_signers_add(session->ctx, *signer_key_ptr);
krista@3131
  1006
        _gpgme_error = _GPGERR(_gpgme_error);
krista@3131
  1007
        assert(_gpgme_error == GPG_ERR_NO_ERROR);
krista@3131
  1008
        break;
krista@3131
  1009
    case GPG_ERR_EOF:
krista@3131
  1010
        gpg.gpgme_key_unref(*signer_key_ptr);
krista@3131
  1011
        free(signer_key_ptr);
krista@3131
  1012
        gpg.gpgme_data_release(plain);
krista@3131
  1013
        gpg.gpgme_data_release(signed_text);
krista@3131
  1014
        return PEP_KEY_NOT_FOUND;
krista@3131
  1015
    case GPG_ERR_AMBIGUOUS_NAME:
krista@3131
  1016
        gpg.gpgme_key_unref(*signer_key_ptr);
krista@3131
  1017
        free(signer_key_ptr);
krista@3131
  1018
        gpg.gpgme_data_release(plain);
krista@3131
  1019
        gpg.gpgme_data_release(signed_text);
krista@3131
  1020
        return PEP_KEY_HAS_AMBIG_NAME;
krista@3131
  1021
    default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
krista@3131
  1022
        // FPR is not a fingerprint or key ID
krista@3131
  1023
        gpg.gpgme_key_unref(*signer_key_ptr);
krista@3131
  1024
        free(signer_key_ptr);
krista@3131
  1025
        gpg.gpgme_data_release(plain);
krista@3131
  1026
        gpg.gpgme_data_release(signed_text);
krista@3131
  1027
        return PEP_GET_KEY_FAILED;
krista@3131
  1028
    }
krista@3131
  1029
 
krista@3131
  1030
    gpgme_error = gpg.gpgme_op_sign(session->ctx, plain, signed_text, sign_mode);
krista@3131
  1031
krista@3131
  1032
    gpgme_error = _GPGERR(gpgme_error);
krista@3131
  1033
    switch (gpgme_error) {
krista@3131
  1034
    case GPG_ERR_NO_ERROR:
krista@3131
  1035
    {
krista@3131
  1036
        char *_buffer = NULL;
krista@3131
  1037
        size_t reading;
krista@3131
  1038
        size_t length = gpg.gpgme_data_seek(signed_text, 0, SEEK_END);
krista@3131
  1039
        assert(length != -1);
krista@3131
  1040
        gpg.gpgme_data_seek(signed_text, 0, SEEK_SET);
krista@3131
  1041
krista@3131
  1042
        // TODO: make things less memory consuming
krista@3131
  1043
        // the following algorithm allocates a buffer for the complete text
krista@3131
  1044
krista@3131
  1045
        _buffer = malloc(length + 1);
krista@3131
  1046
        assert(_buffer);
krista@3131
  1047
        if (_buffer == NULL) {
krista@3131
  1048
            gpg.gpgme_key_unref(*signer_key_ptr);
krista@3131
  1049
            free(signer_key_ptr);
krista@3131
  1050
            gpg.gpgme_data_release(plain);
krista@3131
  1051
            gpg.gpgme_data_release(signed_text);
krista@3131
  1052
            return PEP_OUT_OF_MEMORY;
krista@3131
  1053
        }
krista@3131
  1054
krista@3131
  1055
        reading = gpg.gpgme_data_read(signed_text, _buffer, length);
krista@3131
  1056
        assert(length == reading);
krista@3131
  1057
krista@3131
  1058
        *stext = _buffer;
krista@3131
  1059
        *ssize = reading;
krista@3131
  1060
        (*stext)[*ssize] = 0; // safeguard for naive users
krista@3131
  1061
        result = PEP_STATUS_OK;
krista@3131
  1062
        break;
krista@3131
  1063
    }
krista@3131
  1064
    default:
krista@3131
  1065
        result = PEP_UNKNOWN_ERROR;
krista@3131
  1066
    }
krista@3131
  1067
krista@3131
  1068
    gpg.gpgme_key_unref(*signer_key_ptr);
krista@3131
  1069
    free(signer_key_ptr);
krista@3131
  1070
    gpg.gpgme_data_release(plain);
krista@3131
  1071
    gpg.gpgme_data_release(signed_text);
krista@3131
  1072
    return result;   
krista@3131
  1073
}
krista@1639
  1074
krista@1639
  1075
static PEP_STATUS pgp_encrypt_sign_optional(    
vb@24
  1076
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1639
  1077
    size_t psize, char **ctext, size_t *csize, bool sign
krista@1639
  1078
)
roker@2055
  1079
{
vb@24
  1080
    PEP_STATUS result;
vb@24
  1081
    gpgme_error_t gpgme_error;
vb@24
  1082
    gpgme_data_t plain, cipher;
vb@24
  1083
    gpgme_key_t *rcpt;
vb@24
  1084
    gpgme_encrypt_flags_t flags;
vb@24
  1085
    const stringlist_t *_keylist;
vb@24
  1086
    int i, j;
vb@24
  1087
vb@46
  1088
    assert(session);
vb@24
  1089
    assert(keylist);
vb@24
  1090
    assert(ptext);
vb@24
  1091
    assert(psize);
vb@24
  1092
    assert(ctext);
vb@24
  1093
    assert(csize);
vb@24
  1094
vb@24
  1095
    *ctext = NULL;
vb@24
  1096
    *csize = 0;
vb@24
  1097
vb@74
  1098
    gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
vb@45
  1099
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1100
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1101
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
  1102
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
  1103
            return PEP_OUT_OF_MEMORY;
vb@24
  1104
        else
vb@24
  1105
            return PEP_UNKNOWN_ERROR;
vb@24
  1106
    }
vb@24
  1107
vb@74
  1108
    gpgme_error = gpg.gpgme_data_new(&cipher);
vb@45
  1109
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1110
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1111
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
  1112
        gpg.gpgme_data_release(plain);
vb@24
  1113
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
  1114
            return PEP_OUT_OF_MEMORY;
vb@24
  1115
        else
vb@24
  1116
            return PEP_UNKNOWN_ERROR;
vb@24
  1117
    }
vb@24
  1118
vb@109
  1119
    rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
vb@24
  1120
    assert(rcpt);
vb@24
  1121
    if (rcpt == NULL) {
vb@74
  1122
        gpg.gpgme_data_release(plain);
vb@74
  1123
        gpg.gpgme_data_release(cipher);
vb@24
  1124
        return PEP_OUT_OF_MEMORY;
vb@24
  1125
    }
vb@24
  1126
vb@74
  1127
    gpg.gpgme_signers_clear(session->ctx);
vb@24
  1128
vb@24
  1129
    for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
vb@24
  1130
        assert(_keylist->value);
vb@74
  1131
        gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
vb@24
  1132
            &rcpt[i], 0);
vb@45
  1133
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1134
        assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1135
vb@24
  1136
        switch (gpgme_error) {
vb@24
  1137
        case GPG_ERR_ENOMEM:
vb@24
  1138
            for (j = 0; j<i; j++)
vb@74
  1139
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1140
            free(rcpt);
vb@74
  1141
            gpg.gpgme_data_release(plain);
vb@74
  1142
            gpg.gpgme_data_release(cipher);
vb@24
  1143
            return PEP_OUT_OF_MEMORY;
vb@24
  1144
        case GPG_ERR_NO_ERROR:
krista@1639
  1145
            if (i == 0 && sign) {
vb@74
  1146
                gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
vb@45
  1147
                _gpgme_error = _GPGERR(_gpgme_error);
vb@24
  1148
                assert(_gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1149
            }
vb@24
  1150
            break;
vb@24
  1151
        case GPG_ERR_EOF:
vb@24
  1152
            for (j = 0; j<i; j++)
vb@74
  1153
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1154
            free(rcpt);
vb@74
  1155
            gpg.gpgme_data_release(plain);
vb@74
  1156
            gpg.gpgme_data_release(cipher);
vb@24
  1157
            return PEP_KEY_NOT_FOUND;
vb@24
  1158
        case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1159
            for (j = 0; j<i; j++)
vb@74
  1160
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1161
            free(rcpt);
vb@74
  1162
            gpg.gpgme_data_release(plain);
vb@74
  1163
            gpg.gpgme_data_release(cipher);
vb@24
  1164
            return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1165
        default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
vb@24
  1166
            // FPR is not a fingerprint or key ID
vb@24
  1167
            for (j = 0; j<i; j++)
vb@74
  1168
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1169
            free(rcpt);
vb@74
  1170
            gpg.gpgme_data_release(plain);
vb@74
  1171
            gpg.gpgme_data_release(cipher);
vb@24
  1172
            return PEP_GET_KEY_FAILED;
vb@24
  1173
        }
vb@24
  1174
    }
vb@24
  1175
vb@24
  1176
    // TODO: remove that and replace with proper key management
vb@24
  1177
    flags = GPGME_ENCRYPT_ALWAYS_TRUST;
krista@1639
  1178
    
krista@1639
  1179
    if (sign) {
krista@1639
  1180
        gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
krista@1639
  1181
            plain, cipher);
krista@1639
  1182
    }
krista@1639
  1183
    else {
krista@1639
  1184
        gpgme_error = gpg.gpgme_op_encrypt(session->ctx, rcpt, flags,
krista@1639
  1185
            plain, cipher);
krista@1639
  1186
    }
krista@1639
  1187
    
vb@45
  1188
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1189
    switch (gpgme_error) {
vb@24
  1190
    case GPG_ERR_NO_ERROR:
vb@24
  1191
    {
vb@24
  1192
        char *_buffer = NULL;
vb@24
  1193
        size_t reading;
vb@74
  1194
        size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
vb@24
  1195
        assert(length != -1);
vb@74
  1196
        gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
vb@24
  1197
vb@24
  1198
        // TODO: make things less memory consuming
vb@24
  1199
        // the following algorithm allocates a buffer for the complete text
vb@24
  1200
vb@112
  1201
        _buffer = malloc(length + 1);
vb@24
  1202
        assert(_buffer);
vb@24
  1203
        if (_buffer == NULL) {
vb@24
  1204
            for (j = 0; j<stringlist_length(keylist); j++)
vb@74
  1205
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1206
            free(rcpt);
vb@74
  1207
            gpg.gpgme_data_release(plain);
vb@74
  1208
            gpg.gpgme_data_release(cipher);
vb@24
  1209
            return PEP_OUT_OF_MEMORY;
vb@24
  1210
        }
vb@24
  1211
vb@74
  1212
        reading = gpg.gpgme_data_read(cipher, _buffer, length);
vb@24
  1213
        assert(length == reading);
vb@24
  1214
vb@24
  1215
        *ctext = _buffer;
vb@24
  1216
        *csize = reading;
vb@24
  1217
        (*ctext)[*csize] = 0; // safeguard for naive users
vb@24
  1218
        result = PEP_STATUS_OK;
vb@24
  1219
        break;
vb@24
  1220
    }
vb@24
  1221
    default:
vb@24
  1222
        result = PEP_UNKNOWN_ERROR;
vb@24
  1223
    }
vb@24
  1224
vb@24
  1225
    for (j = 0; j<stringlist_length(keylist); j++)
vb@74
  1226
        gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1227
    free(rcpt);
vb@74
  1228
    gpg.gpgme_data_release(plain);
vb@74
  1229
    gpg.gpgme_data_release(cipher);
vb@24
  1230
    return result;
vb@24
  1231
}
vb@24
  1232
krista@1639
  1233
PEP_STATUS pgp_encrypt_only(
krista@1639
  1234
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1639
  1235
    size_t psize, char **ctext, size_t *csize
krista@1639
  1236
    )
krista@1639
  1237
{
krista@1639
  1238
    return pgp_encrypt_sign_optional(session, keylist, ptext,
krista@1639
  1239
        psize, ctext, csize, false);
krista@1639
  1240
}
krista@1639
  1241
krista@1639
  1242
PEP_STATUS pgp_encrypt_and_sign(
krista@1639
  1243
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1639
  1244
    size_t psize, char **ctext, size_t *csize
krista@1639
  1245
    )
krista@1639
  1246
{
krista@1639
  1247
    return pgp_encrypt_sign_optional(session, keylist, ptext,
krista@1639
  1248
        psize, ctext, csize, true);
krista@1639
  1249
}
krista@1639
  1250
krista@1925
  1251
krista@1925
  1252
static PEP_STATUS find_single_key(
krista@1925
  1253
        PEP_SESSION session,
krista@1925
  1254
        const char *fpr,
krista@1925
  1255
        gpgme_key_t *key
krista@1925
  1256
    )
krista@1925
  1257
{
krista@1925
  1258
    gpgme_error_t gpgme_error;
krista@1925
  1259
krista@1925
  1260
    *key = NULL;
krista@1925
  1261
kgrothoff@1926
  1262
//    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
kgrothoff@1926
  1263
kgrothoff@1926
  1264
    gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, key, 0);
kgrothoff@1926
  1265
krista@1925
  1266
    gpgme_error = _GPGERR(gpgme_error);
krista@1925
  1267
    switch (gpgme_error) {
krista@1925
  1268
    case GPG_ERR_NO_ERROR:
krista@1925
  1269
        break;
krista@1925
  1270
    case GPG_ERR_INV_VALUE:
krista@1925
  1271
        assert(0);
krista@1925
  1272
        return PEP_UNKNOWN_ERROR;
krista@1925
  1273
    default:
krista@1925
  1274
        return PEP_GET_KEY_FAILED;
krista@1925
  1275
    };
krista@1925
  1276
kgrothoff@1926
  1277
//    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
kgrothoff@1926
  1278
//    gpgme_error = _GPGERR(gpgme_error);
kgrothoff@1926
  1279
//    assert(gpgme_error != GPG_ERR_INV_VALUE);
krista@1925
  1280
kgrothoff@1926
  1281
//    gpg.gpgme_op_keylist_end(session->ctx);
krista@1925
  1282
krista@1925
  1283
    return PEP_STATUS_OK;
krista@1925
  1284
}
krista@1925
  1285
krista@1925
  1286
krista@1914
  1287
static PEP_STATUS _pgp_createkey(PEP_SESSION session, pEp_identity *identity) {
krista@1914
  1288
    PEP_STATUS status = PEP_VERSION_MISMATCH;
krista@1914
  1289
roker@2055
  1290
    if (identity && identity->address) {
krista@1914
  1291
#ifdef GPGME_VERSION_NUMBER 
krista@1914
  1292
#if (GPGME_VERSION_NUMBER >= 0x010700)
krista@1920
  1293
        gpgme_error_t gpgme_error;
kgrothoff@1926
  1294
        int userid_size = strlen(identity->address) + 1;
krista@1921
  1295
        char* userid = (char*)(calloc(1, userid_size));
krista@1921
  1296
        if (!userid)
krista@1921
  1297
            return PEP_OUT_OF_MEMORY;
kgrothoff@1926
  1298
        strlcpy(userid, identity->address, userid_size);
krista@1921
  1299
        gpgme_error = gpg.gpgme_op_createkey(session->ctx, userid, "RSA", 
krista@1924
  1300
                                             0, 31536000, NULL, 
krista@1927
  1301
                                             GPGME_CREATE_NOPASSWD | GPGME_CREATE_FORCE);
krista@1920
  1302
        gpgme_error = _GPGERR(gpgme_error);
krista@1921
  1303
krista@1921
  1304
        free(userid);
krista@1921
  1305
krista@1920
  1306
        if (gpgme_error != GPG_ERR_NOT_SUPPORTED) {
krista@1920
  1307
            switch (gpgme_error) {
krista@1924
  1308
                case GPG_ERR_NO_ERROR:
roker@2055
  1309
                    break;
krista@1924
  1310
                case GPG_ERR_INV_VALUE:
krista@1924
  1311
                    return PEP_ILLEGAL_VALUE;
vb@2801
  1312
                default:
krista@1924
  1313
                    return PEP_CANNOT_CREATE_KEY;
roker@2055
  1314
            }
krista@1924
  1315
krista@1924
  1316
            /* This is the same regardless of whether we got it from genkey or createkey */
krista@1924
  1317
            gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
krista@1924
  1318
            assert(gpgme_genkey_result);
krista@1924
  1319
            assert(gpgme_genkey_result->fpr);
krista@1924
  1320
kgrothoff@1926
  1321
            char* fpr = strdup(gpgme_genkey_result->fpr);
krista@1925
  1322
            gpgme_key_t key;
krista@1925
  1323
            PEP_STATUS key_status = find_single_key(session, fpr, &key);
krista@1925
  1324
            if (!key || key_status != PEP_STATUS_OK)
krista@1925
  1325
                return PEP_CANNOT_CREATE_KEY;
roker@2055
  1326
            
krista@1925
  1327
            gpgme_error = gpg.gpgme_op_createsubkey(session->ctx, key, 
krista@1925
  1328
                                                    "RSA", 0, 
krista@1925
  1329
                                                    31536000, GPGME_CREATE_NOPASSWD 
krista@1925
  1330
                                                    | GPGME_CREATE_ENCR);
krista@1925
  1331
krista@1925
  1332
            switch (gpgme_error) {
krista@1925
  1333
                case GPG_ERR_NO_ERROR:
roker@2055
  1334
                    break;
krista@1925
  1335
                case GPG_ERR_INV_VALUE:
krista@1925
  1336
                    return PEP_ILLEGAL_VALUE;
krista@1925
  1337
                case GPG_ERR_GENERAL:
krista@1925
  1338
                    return PEP_CANNOT_CREATE_KEY;
krista@1925
  1339
                default:
krista@1925
  1340
                    assert(0);
krista@1925
  1341
                    return PEP_UNKNOWN_ERROR;
roker@2055
  1342
            }
krista@1925
  1343
            
krista@1924
  1344
            free(identity->fpr);
kgrothoff@1926
  1345
            identity->fpr = fpr;
krista@1924
  1346
            if (identity->fpr == NULL)
krista@1924
  1347
                return PEP_OUT_OF_MEMORY;
krista@1924
  1348
kgrothoff@1926
  1349
//            gpg.gpgme_key_unref(key);
krista@1925
  1350
            
kgrothoff@1926
  1351
            status = pgp_replace_only_uid(session, fpr,
roker@2055
  1352
                        identity->username, identity->address);
krista@1920
  1353
        }
krista@1914
  1354
#endif
krista@1914
  1355
#endif
krista@1914
  1356
    }
krista@1914
  1357
    
krista@1914
  1358
    return status;
krista@1914
  1359
}
krista@1914
  1360
vb@24
  1361
PEP_STATUS pgp_generate_keypair(
vb@24
  1362
    PEP_SESSION session, pEp_identity *identity
vb@24
  1363
    )
vb@24
  1364
{
vb@24
  1365
    assert(session);
vb@24
  1366
    assert(identity);
vb@24
  1367
    assert(identity->address);
vb@298
  1368
    assert(identity->fpr == NULL || identity->fpr[0] == 0);
vb@24
  1369
    assert(identity->username);
vb@24
  1370
krista@1914
  1371
    PEP_STATUS status = _pgp_createkey(session, identity);
krista@1914
  1372
    
krista@1924
  1373
    if (status != PEP_VERSION_MISMATCH)
krista@1914
  1374
        return status;
krista@1924
  1375
        
krista@1924
  1376
    gpgme_error_t gpgme_error;
krista@1924
  1377
    char *parms;
krista@1924
  1378
    const char *template =
krista@1924
  1379
        "<GnupgKeyParms format=\"internal\">\n"
krista@1924
  1380
        "Key-Type: RSA\n"
krista@1924
  1381
        "Key-Length: 4096\n"
krista@1924
  1382
        "Subkey-Type: RSA\n"
krista@1924
  1383
        "Subkey-Length: 4096\n"
krista@1924
  1384
        "Name-Real: %s\n"
krista@1924
  1385
        "Name-Email: %s\n"
krista@1924
  1386
        /* "Passphrase: %s\n" */
krista@1924
  1387
        "Expire-Date: 1y\n"
krista@1924
  1388
        "</GnupgKeyParms>\n";
krista@1924
  1389
    int result;
vb@24
  1390
krista@1924
  1391
    parms = calloc(1, PARMS_MAX);
krista@1924
  1392
    assert(parms);
krista@1924
  1393
    if (parms == NULL)
krista@1924
  1394
        return PEP_OUT_OF_MEMORY;
krista@1914
  1395
krista@1924
  1396
    result = snprintf(parms, PARMS_MAX, template, identity->username,
krista@1924
  1397
        identity->address); // , session->passphrase);
krista@1924
  1398
    assert(result < PARMS_MAX);
krista@1924
  1399
    if (result >= PARMS_MAX) {
vb@24
  1400
        free(parms);
krista@1924
  1401
        return PEP_BUFFER_TOO_SMALL;
vb@24
  1402
    }
vb@24
  1403
krista@1924
  1404
    gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
krista@1924
  1405
    gpgme_error = _GPGERR(gpgme_error);
krista@1924
  1406
    free(parms);
krista@1924
  1407
krista@1924
  1408
    switch (gpgme_error) {
krista@1924
  1409
    case GPG_ERR_NO_ERROR:
krista@1924
  1410
        break;
krista@1924
  1411
    case GPG_ERR_INV_VALUE:
krista@1924
  1412
        return PEP_ILLEGAL_VALUE;
krista@1924
  1413
    case GPG_ERR_GENERAL:
krista@1924
  1414
        return PEP_CANNOT_CREATE_KEY;
krista@1924
  1415
    default:
krista@1924
  1416
        assert(0);
krista@1924
  1417
        return PEP_UNKNOWN_ERROR;
krista@1924
  1418
    }
krista@1924
  1419
krista@1914
  1420
    gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
vb@24
  1421
    assert(gpgme_genkey_result);
vb@24
  1422
    assert(gpgme_genkey_result->fpr);
vb@24
  1423
vb@298
  1424
    free(identity->fpr);
vb@24
  1425
    identity->fpr = strdup(gpgme_genkey_result->fpr);
vb@298
  1426
    if (identity->fpr == NULL)
vb@298
  1427
        return PEP_OUT_OF_MEMORY;
vb@24
  1428
vb@24
  1429
    return PEP_STATUS_OK;
vb@24
  1430
}
vb@24
  1431
vb@24
  1432
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
vb@24
  1433
{
vb@24
  1434
    gpgme_error_t gpgme_error;
vb@24
  1435
    gpgme_key_t key;
vb@24
  1436
vb@24
  1437
    assert(session);
vb@24
  1438
    assert(fpr);
vb@24
  1439
vb@74
  1440
    gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
vb@45
  1441
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1442
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1443
    switch (gpgme_error) {
vb@24
  1444
    case GPG_ERR_NO_ERROR:
vb@24
  1445
        break;
vb@24
  1446
    case GPG_ERR_EOF:
vb@24
  1447
        return PEP_KEY_NOT_FOUND;
vb@24
  1448
    case GPG_ERR_INV_VALUE:
vb@24
  1449
        return PEP_ILLEGAL_VALUE;
vb@24
  1450
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1451
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1452
    case GPG_ERR_ENOMEM:
vb@24
  1453
        return PEP_OUT_OF_MEMORY;
vb@24
  1454
    default:
vb@24
  1455
        assert(0);
vb@24
  1456
        return PEP_UNKNOWN_ERROR;
vb@24
  1457
    }
vb@24
  1458
vb@74
  1459
    gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
vb@45
  1460
    gpgme_error = _GPGERR(gpgme_error);
vb@74
  1461
    gpg.gpgme_key_unref(key);
vb@24
  1462
    switch (gpgme_error) {
vb@24
  1463
    case GPG_ERR_NO_ERROR:
vb@24
  1464
        break;
vb@24
  1465
    case GPG_ERR_INV_VALUE:
vb@24
  1466
        assert(0);
vb@24
  1467
        return PEP_UNKNOWN_ERROR;
vb@24
  1468
    case GPG_ERR_NO_PUBKEY:
vb@24
  1469
        assert(0);
vb@24
  1470
        return PEP_KEY_NOT_FOUND;
vb@24
  1471
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1472
        assert(0);
vb@24
  1473
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1474
    default:
vb@24
  1475
        assert(0);
vb@24
  1476
        return PEP_UNKNOWN_ERROR;
vb@24
  1477
    }
vb@24
  1478
vb@24
  1479
    return PEP_STATUS_OK;
vb@24
  1480
}
vb@24
  1481
Edouard@728
  1482
PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
Edouard@728
  1483
                              size_t size, identity_list **private_idents)
vb@24
  1484
{
vb@24
  1485
    gpgme_error_t gpgme_error;
vb@24
  1486
    gpgme_data_t dh;
vb@24
  1487
vb@24
  1488
    assert(session);
vb@24
  1489
    assert(key_data);
krista@1426
  1490
krista@1426
  1491
    if(private_idents)
Edouard@728
  1492
        *private_idents = NULL;
vb@24
  1493
vb@74
  1494
    gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
vb@45
  1495
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1496
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1497
    switch (gpgme_error) {
vb@24
  1498
    case GPG_ERR_NO_ERROR:
vb@24
  1499
        break;
vb@24
  1500
    case GPG_ERR_ENOMEM:
vb@24
  1501
        return PEP_OUT_OF_MEMORY;
vb@24
  1502
    case GPG_ERR_INV_VALUE:
vb@24
  1503
        assert(0);
vb@24
  1504
        return PEP_UNKNOWN_ERROR;
vb@24
  1505
    default:
vb@24
  1506
        assert(0);
vb@24
  1507
        return PEP_UNKNOWN_ERROR;
vb@24
  1508
    }
vb@24
  1509
Edouard@728
  1510
    gpgme_import_result_t gpgme_import_result;
Edouard@728
  1511
vb@74
  1512
    gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
vb@45
  1513
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1514
    switch (gpgme_error) {
vb@24
  1515
    case GPG_ERR_NO_ERROR:
krista@1426
  1516
        if(private_idents)
Edouard@728
  1517
        {
Edouard@728
  1518
            gpgme_import_result =
Edouard@728
  1519
                gpg.gpgme_op_import_result(session->ctx);
Edouard@728
  1520
            assert(gpgme_import_result);
vb@1302
  1521
            if (!gpgme_import_result) {
vb@1302
  1522
                gpg.gpgme_data_release(dh);
vb@1302
  1523
                return PEP_UNKNOWN_ERROR;
vb@1302
  1524
            }
vb@1302
  1525
Edouard@728
  1526
            gpgme_import_status_t import;
krista@1426
  1527
            for (import = gpgme_import_result->imports;
krista@1426
  1528
                 import;
Edouard@728
  1529
                 import = import->next)
Edouard@728
  1530
             {
Edouard@728
  1531
                if (import &&
Edouard@728
  1532
                    import->result == GPG_ERR_NO_ERROR &&
Edouard@728
  1533
                    import->status & GPGME_IMPORT_SECRET )
Edouard@728
  1534
                {
Edouard@728
  1535
                    gpgme_key_t key = NULL;
Edouard@728
  1536
Edouard@728
  1537
                    gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@728
  1538
                        import->fpr, &key, 0);
Edouard@728
  1539
                    gpgme_error = _GPGERR(gpgme_error);
Edouard@728
  1540
                    assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@728
  1541
                    if (gpgme_error == GPG_ERR_ENOMEM) {
Edouard@728
  1542
                        gpg.gpgme_data_release(dh);
Edouard@728
  1543
                        return PEP_OUT_OF_MEMORY;
Edouard@728
  1544
                    }
krista@1426
  1545
krista@1426
  1546
                    if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1426
  1547
                        key && key->uids &&
Edouard@728
  1548
                        key->uids->email && key->uids->name)
Edouard@728
  1549
                    {
Edouard@728
  1550
                        pEp_identity *ident = new_identity(
Edouard@728
  1551
                             key->uids->email, import->fpr, NULL, key->uids->name);
Edouard@728
  1552
Edouard@728
  1553
                        gpg.gpgme_key_unref(key);
Edouard@728
  1554
Edouard@728
  1555
                        if (ident == NULL) {
Edouard@728
  1556
                            gpg.gpgme_data_release(dh);
Edouard@728
  1557
                            return PEP_OUT_OF_MEMORY;
Edouard@728
  1558
                        }
Edouard@728
  1559
Edouard@728
  1560
                        *private_idents = identity_list_add(*private_idents, ident);
Edouard@728
  1561
Edouard@728
  1562
                        if (*private_idents == NULL) {
Edouard@728
  1563
                            gpg.gpgme_data_release(dh);
Edouard@728
  1564
                            return PEP_OUT_OF_MEMORY;
Edouard@728
  1565
                        }
Edouard@728
  1566
                    }
krista@1426
  1567
                    else
Edouard@728
  1568
                    {
Edouard@728
  1569
                        gpg.gpgme_key_unref(key);
Edouard@728
  1570
                        gpg.gpgme_data_release(dh);
Edouard@728
  1571
                        return PEP_UNKNOWN_ERROR;
Edouard@728
  1572
                    }
Edouard@728
  1573
                }
Edouard@728
  1574
            }
Edouard@728
  1575
        }
vb@24
  1576
        break;
vb@24
  1577
    case GPG_ERR_INV_VALUE:
vb@24
  1578
        assert(0);
vb@74
  1579
        gpg.gpgme_data_release(dh);
vb@24
  1580
        return PEP_UNKNOWN_ERROR;
vb@24
  1581
    case GPG_ERR_NO_DATA:
vb@74
  1582
        gpg.gpgme_data_release(dh);
vb@24
  1583
        return PEP_ILLEGAL_VALUE;
vb@24
  1584
    default:
vb@24
  1585
        assert(0);
vb@74
  1586
        gpg.gpgme_data_release(dh);
vb@24
  1587
        return PEP_UNKNOWN_ERROR;
vb@24
  1588
    }
vb@24
  1589
vb@74
  1590
    gpg.gpgme_data_release(dh);
vb@24
  1591
    return PEP_STATUS_OK;
vb@24
  1592
}
vb@24
  1593
Edouard@170
  1594
PEP_STATUS pgp_export_keydata(
vb@1103
  1595
        PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
vb@1103
  1596
        bool secret
vb@24
  1597
    )
vb@24
  1598
{
vb@24
  1599
    gpgme_error_t gpgme_error;
vb@24
  1600
    gpgme_data_t dh;
vb@24
  1601
    size_t _size;
vb@24
  1602
    char *buffer;
vb@24
  1603
    int reading;
vb@24
  1604
vb@24
  1605
    assert(session);
vb@24
  1606
    assert(fpr);
vb@24
  1607
    assert(key_data);
vb@24
  1608
    assert(size);
vb@24
  1609
vb@74
  1610
    gpgme_error = gpg.gpgme_data_new(&dh);
vb@45
  1611
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1612
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1613
    switch (gpgme_error) {
vb@24
  1614
    case GPG_ERR_NO_ERROR:
vb@24
  1615
        break;
vb@24
  1616
    case GPG_ERR_ENOMEM:
vb@24
  1617
        return PEP_OUT_OF_MEMORY;
vb@24
  1618
    case GPG_ERR_INV_VALUE:
vb@24
  1619
        assert(0);
vb@24
  1620
        return PEP_UNKNOWN_ERROR;
vb@24
  1621
    default:
vb@24
  1622
        assert(0);
vb@24
  1623
        return PEP_UNKNOWN_ERROR;
vb@24
  1624
    }
vb@24
  1625
vb@1103
  1626
    if (secret)
vb@1103
  1627
        gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
edouard@1163
  1628
            GPGME_EXPORT_MODE_SECRET, dh);
vb@1103
  1629
    else
vb@1103
  1630
        gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
vb@1103
  1631
            GPGME_EXPORT_MODE_MINIMAL, dh);
vb@45
  1632
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1633
    switch (gpgme_error) {
vb@24
  1634
    case GPG_ERR_NO_ERROR:
vb@24
  1635
        break;
vb@24
  1636
    case GPG_ERR_EOF:
vb@74
  1637
        gpg.gpgme_data_release(dh);
vb@24
  1638
        return PEP_KEY_NOT_FOUND;
vb@24
  1639
    case GPG_ERR_INV_VALUE:
vb@24
  1640
        assert(0);
vb@74
  1641
        gpg.gpgme_data_release(dh);
vb@24
  1642
        return PEP_UNKNOWN_ERROR;
vb@24
  1643
    default:
vb@24
  1644
        assert(0);
vb@74
  1645
        gpg.gpgme_data_release(dh);
vb@24
  1646
        return PEP_UNKNOWN_ERROR;
vb@24
  1647
    };
vb@24
  1648
vb@74
  1649
    _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
vb@24
  1650
    assert(_size != -1);
vb@74
  1651
    gpg.gpgme_data_seek(dh, 0, SEEK_SET);
vb@24
  1652
vb@24
  1653
    buffer = malloc(_size + 1);
vb@24
  1654
    assert(buffer);
vb@24
  1655
    if (buffer == NULL) {
vb@74
  1656
        gpg.gpgme_data_release(dh);
vb@24
  1657
        return PEP_OUT_OF_MEMORY;
vb@24
  1658
    }
vb@24
  1659
vb@74
  1660
    reading = gpg.gpgme_data_read(dh, buffer, _size);
vb@24
  1661
    assert(_size == reading);
edouard@1803
  1662
    if(_size != reading)
edouard@1803
  1663
        return PEP_CANNOT_EXPORT_KEY;
vb@24
  1664
vb@24
  1665
    // safeguard for the naive user
vb@24
  1666
    buffer[_size] = 0;
vb@24
  1667
vb@24
  1668
    *key_data = buffer;
vb@24
  1669
    *size = _size;
vb@24
  1670
vb@74
  1671
    gpg.gpgme_data_release(dh);
vb@24
  1672
    return PEP_STATUS_OK;
vb@24
  1673
}
vb@24
  1674
krista@1426
  1675
PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern,
krista@1031
  1676
                            stringpair_list_t** keyinfo_list)
krista@1426
  1677
{
krista@1005
  1678
    gpgme_error_t gpgme_error;
krista@1005
  1679
    assert(session);
krista@1031
  1680
    assert(keyinfo_list);
krista@1426
  1681
krista@1031
  1682
    if (!session || !keyinfo_list)
krista@1005
  1683
        return PEP_ILLEGAL_VALUE;
krista@1426
  1684
krista@1031
  1685
    *keyinfo_list = NULL;
krista@1426
  1686
krista@1031
  1687
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
krista@1005
  1688
    gpgme_error = _GPGERR(gpgme_error);
krista@1426
  1689
krista@1005
  1690
    switch(gpgme_error) {
krista@1005
  1691
        case GPG_ERR_NO_ERROR:
krista@1005
  1692
            break;
krista@1005
  1693
        case GPG_ERR_INV_VALUE:
krista@1005
  1694
            assert(0);
krista@1005
  1695
            return PEP_UNKNOWN_ERROR;
krista@1005
  1696
        default:
krista@1005
  1697
            gpg.gpgme_op_keylist_end(session->ctx);
krista@1426
  1698
            return PEP_GET_KEY_FAILED;
krista@1005
  1699
    };
krista@1426
  1700
krista@1005
  1701
    gpgme_key_t key;
krista@1031
  1702
    stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
krista@1031
  1703
    stringpair_list_t* list_curr = _keyinfo_list;
krista@1031
  1704
    stringpair_t* pair = NULL;
krista@1426
  1705
krista@1426
  1706
    do {
krista@1005
  1707
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
krista@1005
  1708
        gpgme_error = _GPGERR(gpgme_error);
krista@1426
  1709
krista@1005
  1710
        switch(gpgme_error) {
krista@1005
  1711
            case GPG_ERR_EOF:
krista@1005
  1712
                break;
krista@1005
  1713
            case GPG_ERR_NO_ERROR:
krista@1005
  1714
                assert(key);
krista@1005
  1715
                assert(key->subkeys);
krista@1005
  1716
                if (!key || !key->subkeys)
krista@1005
  1717
                    return PEP_GET_KEY_FAILED;
krista@1040
  1718
krista@1005
  1719
                // first subkey is primary key
krista@1005
  1720
                char* fpr = key->subkeys->fpr;
roker@1199
  1721
                char* uid = key->uids->uid;
krista@1187
  1722
krista@1005
  1723
                assert(fpr);
roker@1199
  1724
                assert(uid);
krista@1031
  1725
                if (!fpr)
krista@1005
  1726
                    return PEP_GET_KEY_FAILED;
krista@1426
  1727
krista@1050
  1728
                if (key->subkeys->revoked)
krista@1040
  1729
                    continue;
krista@1426
  1730
krista@1031
  1731
                pair = new_stringpair(fpr, uid);
krista@1019
  1732
krista@1031
  1733
                assert(pair);
krista@1426
  1734
krista@1031
  1735
                if (pair) {
krista@1031
  1736
                    list_curr = stringpair_list_add(list_curr, pair);
krista@1031
  1737
                    pair = NULL;
krista@1426
  1738
krista@1005
  1739
                    assert(list_curr);
krista@1005
  1740
                    if (list_curr != NULL)
krista@1005
  1741
                        break;
krista@1005
  1742
                    else
krista@1031
  1743
                        free_stringpair(pair);
krista@1005
  1744
                }
krista@1031
  1745
                // else fallthrough (list_curr or pair wasn't allocateable)
krista@1005
  1746
            case GPG_ERR_ENOMEM:
krista@1031
  1747
                free_stringpair_list(_keyinfo_list);
krista@1005
  1748
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1005
  1749
                return PEP_OUT_OF_MEMORY;
krista@1005
  1750
            default:
krista@1005
  1751
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1005
  1752
                return PEP_UNKNOWN_ERROR;
krista@1005
  1753
        }
krista@1005
  1754
    } while (gpgme_error != GPG_ERR_EOF);
krista@1426
  1755
krista@1032
  1756
    if (_keyinfo_list->value == NULL) {
krista@1031
  1757
        free_stringpair_list(_keyinfo_list);
krista@1031
  1758
        _keyinfo_list = NULL;
krista@1005
  1759
    }
krista@1426
  1760
krista@1031
  1761
    *keyinfo_list = _keyinfo_list;
krista@1426
  1762
krista@1005
  1763
    return PEP_STATUS_OK;
krista@1005
  1764
}
krista@1005
  1765
vb@46
  1766
static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
vb@24
  1767
    gpgme_keylist_mode_t add_mode)
vb@24
  1768
{
vb@24
  1769
    gpgme_error_t gpgme_error;
vb@24
  1770
    gpgme_keylist_mode_t mode;
vb@24
  1771
vb@74
  1772
    mode = gpg.gpgme_get_keylist_mode(session->ctx);
vb@24
  1773
vb@24
  1774
    mode &= ~remove_mode;
vb@24
  1775
    mode |= add_mode;
vb@24
  1776
vb@74
  1777
    gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
vb@45
  1778
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1779
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1780
}
vb@24
  1781
vb@24
  1782
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
vb@24
  1783
{
vb@24
  1784
    gpgme_error_t gpgme_error;
vb@24
  1785
    gpgme_key_t key;
vb@24
  1786
vb@24
  1787
    assert(session);
vb@24
  1788
    assert(pattern);
vb@24
  1789
vb@46
  1790
    _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
vb@24
  1791
vb@74
  1792
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
vb@45
  1793
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1794
    switch (gpgme_error) {
vb@24
  1795
    case GPG_ERR_NO_ERROR:
vb@24
  1796
        break;
vb@24
  1797
    case GPG_ERR_INV_VALUE:
vb@24
  1798
        assert(0);
vb@47
  1799
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1800
        return PEP_UNKNOWN_ERROR;
vb@24
  1801
    default:
vb@47
  1802
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1803
        return PEP_GET_KEY_FAILED;
vb@24
  1804
    };
vb@24
  1805
vb@47
  1806
    gpgme_ctx_t import_ctx;
vb@74
  1807
    gpgme_error = gpg.gpgme_new(&import_ctx);
vb@47
  1808
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@47
  1809
vb@24
  1810
    do {
vb@74
  1811
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1812
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1813
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1814
        switch (gpgme_error) {
vb@24
  1815
        case GPG_ERR_EOF:
vb@24
  1816
            break;
vb@24
  1817
        case GPG_ERR_NO_ERROR:
vb@24
  1818
        {
vb@24
  1819
            gpgme_error_t gpgme_error;
vb@24
  1820
            gpgme_key_t keys[2];
vb@24
  1821
vb@24
  1822
            keys[0] = key;
vb@24
  1823
            keys[1] = NULL;
vb@24
  1824
vb@74
  1825
            gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
vb@45
  1826
            gpgme_error = _GPGERR(gpgme_error);
vb@74
  1827
            gpg.gpgme_key_unref(key);
vb@24
  1828
            assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1829
            assert(gpgme_error != GPG_ERR_CONFLICT);
vb@24
  1830
        }
vb@24
  1831
            break;
vb@24
  1832
        case GPG_ERR_ENOMEM:
vb@74
  1833
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1834
            gpg.gpgme_release(import_ctx);
vb@47
  1835
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1836
            return PEP_OUT_OF_MEMORY;
vb@24
  1837
        default:
vb@74
  1838
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1839
            gpg.gpgme_release(import_ctx);
vb@47
  1840
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@46
  1841
            return PEP_UNKNOWN_ERROR;
vb@24
  1842
        };
vb@24
  1843
    } while (gpgme_error != GPG_ERR_EOF);
vb@24
  1844
vb@74
  1845
    gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1846
    gpg.gpgme_release(import_ctx);
vb@47
  1847
    _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1848
    return PEP_STATUS_OK;
vb@24
  1849
}
vb@24
  1850
krista@1357
  1851
static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
krista@1357
  1852
                            stringlist_t** keylist,
krista@1357
  1853
                            int private_only) {
vb@24
  1854
    gpgme_error_t gpgme_error;
vb@24
  1855
    gpgme_key_t key;
krista@1426
  1856
vb@24
  1857
    assert(session);
vb@24
  1858
    assert(keylist);
krista@1426
  1859
vb@24
  1860
    *keylist = NULL;
krista@1426
  1861
krista@1357
  1862
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
vb@45
  1863
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1864
    switch (gpgme_error) {
krista@1357
  1865
        case GPG_ERR_NO_ERROR:
krista@1357
  1866
            break;
krista@1357
  1867
        case GPG_ERR_INV_VALUE:
krista@1357
  1868
            assert(0);
krista@1357
  1869
            return PEP_UNKNOWN_ERROR;
krista@1357
  1870
        default:
krista@1357
  1871
            gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  1872
            return PEP_GET_KEY_FAILED;
vb@24
  1873
    };
krista@1426
  1874
roker@880
  1875
    stringlist_t *_keylist = new_stringlist(NULL);
vb@24
  1876
    stringlist_t *_k = _keylist;
krista@1426
  1877
vb@24
  1878
    do {
vb@74
  1879
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1880
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1881
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1882
        switch (gpgme_error) {
krista@1357
  1883
            case GPG_ERR_EOF:
vb@24
  1884
                break;
krista@1357
  1885
            case GPG_ERR_NO_ERROR:
krista@1357
  1886
                assert(key);
krista@1357
  1887
                assert(key->subkeys);
edouard@1525
  1888
                if(!key->subkeys)
krista@1357
  1889
                    break;
edouard@1525
  1890
                assert(key->uids);
edouard@1525
  1891
                gpgme_user_id_t kuid = key->uids;
krista@2057
  1892
                // check that at least one uid's email matches pattern exactly,
krista@2057
  1893
                // modulo the email-diff heuristic
edouard@1525
  1894
                while(kuid) {
krista@2681
  1895
                    if((pattern == NULL) ||
krista@2681
  1896
                       (strstr(pattern, "@") == NULL) || // not an email
krista@2681
  1897
                       (kuid->email && _email_heuristic_match(kuid->email, pattern)))
edouard@1760
  1898
                    { 
edouard@1525
  1899
                        char *fpr = key->subkeys->fpr;
edouard@1525
  1900
                        assert(fpr);
edouard@1525
  1901
                        _k = stringlist_add(_k, fpr);
edouard@1525
  1902
                        assert(_k);
edouard@1525
  1903
                        if (_k == NULL){
edouard@1525
  1904
                            free_stringlist(_keylist);
edouard@1525
  1905
                            gpg.gpgme_op_keylist_end(session->ctx);
edouard@1525
  1906
                            return PEP_OUT_OF_MEMORY;
edouard@1525
  1907
                        }
edouard@1525
  1908
                        break;
edouard@1525
  1909
                    }
edouard@1525
  1910
                    kuid = kuid->next;
edouard@1525
  1911
                }
edouard@1525
  1912
                break;
krista@1357
  1913
            case GPG_ERR_ENOMEM:
krista@1357
  1914
                free_stringlist(_keylist);
krista@1357
  1915
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  1916
                return PEP_OUT_OF_MEMORY;
krista@1357
  1917
            default:
krista@1357
  1918
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  1919
                return PEP_UNKNOWN_ERROR;
vb@24
  1920
        };
vb@24
  1921
    } while (gpgme_error != GPG_ERR_EOF);
krista@1426
  1922
vb@74
  1923
    gpg.gpgme_op_keylist_end(session->ctx);
krista@2098
  1924
    if (_keylist->value == NULL) {
vb@523
  1925
        free_stringlist(_keylist);
vb@523
  1926
        _keylist = NULL;
krista@2057
  1927
        
krista@2098
  1928
        if (pattern != NULL) {
krista@2098
  1929
            // If match failed, check to see if we've got a dotted address in the pattern.
krista@2098
  1930
            // (last chance of the heuristic, really)
krista@2098
  1931
            // If so, try again without any dots.
krista@2098
  1932
            const char* dotpos = strstr(pattern, ".");
krista@2098
  1933
            const char* atpos = strstr(pattern, "@");
krista@2098
  1934
            if (dotpos && atpos && (dotpos < atpos)) {
krista@2098
  1935
                char* undotted = _undot_address(pattern);
krista@2098
  1936
                if (undotted) {
krista@2098
  1937
                    PEP_STATUS status = _pgp_search_keys(session, undotted,
krista@2098
  1938
                                                         keylist, private_only);
krista@2098
  1939
                    free(undotted);
krista@2098
  1940
                    return status;
krista@2098
  1941
                }
krista@2057
  1942
            }
krista@2057
  1943
        }
krista@2057
  1944
    }    
krista@2057
  1945
    
vb@24
  1946
    *keylist = _keylist;
vb@24
  1947
    return PEP_STATUS_OK;
vb@24
  1948
}
vb@24
  1949
krista@1357
  1950
PEP_STATUS pgp_find_keys(
krista@1357
  1951
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
krista@1357
  1952
    )
krista@1357
  1953
{
krista@1357
  1954
    return _pgp_search_keys(session, pattern, keylist, 0);
krista@1426
  1955
}
krista@1357
  1956
krista@1357
  1957
PEP_STATUS pgp_find_private_keys(
krista@1357
  1958
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
krista@1357
  1959
)
krista@1357
  1960
{
krista@1357
  1961
    return _pgp_search_keys(session, pattern, keylist, 1);
krista@1357
  1962
}
krista@1357
  1963
vb@2539
  1964
// this function is delivering a list of triples with fpr, email, name of all
vb@2539
  1965
// ultimatedly trusted private keys
vb@2539
  1966
vb@2539
  1967
PEP_STATUS pgp_find_trusted_private_keys(
vb@2539
  1968
        PEP_SESSION session, stringlist_t **keylist
vb@2539
  1969
    )
vb@2539
  1970
{
vb@2539
  1971
    assert(session && keylist);
vb@2539
  1972
    if (!session || !keylist)
krista@2458
  1973
        return PEP_ILLEGAL_VALUE;
krista@2458
  1974
vb@2539
  1975
    *keylist = NULL;
vb@2539
  1976
krista@2416
  1977
    gpgme_key_t key;
krista@2458
  1978
    gpgme_error_t gpgme_error;
vb@2539
  1979
vb@2539
  1980
    stringlist_t *private_keylist = NULL;
vb@2539
  1981
    PEP_STATUS status = pgp_find_private_keys(session, NULL, &private_keylist);
vb@2539
  1982
    if (status)
vb@2539
  1983
        return status;
vb@2539
  1984
    if (!private_keylist || !private_keylist->value)
vb@2539
  1985
        return status;
vb@2539
  1986
vb@2539
  1987
    stringlist_t *result_list = new_stringlist(NULL);
vb@2539
  1988
    if (!result_list)
vb@2539
  1989
        return PEP_OUT_OF_MEMORY;
vb@2539
  1990
    stringlist_t *_result_list = result_list;
vb@2539
  1991
vb@2539
  1992
    stringlist_t *keylist_curr;
vb@2539
  1993
    for (keylist_curr = private_keylist; keylist_curr && keylist_curr->value; keylist_curr = keylist_curr->next) {
vb@2539
  1994
        // a. get key data
vb@2539
  1995
        gpgme_error = gpg.gpgme_get_key(session->ctx, keylist_curr->value, &key, 1);
vb@2539
  1996
        gpgme_error = _GPGERR(gpgme_error);
vb@2539
  1997
        assert(gpgme_error != GPG_ERR_ENOMEM);
vb@2539
  1998
        switch (gpgme_error) {
vb@2539
  1999
            case GPG_ERR_NO_ERROR:
vb@2539
  2000
                break;
vb@2539
  2001
            case GPG_ERR_EOF:
vb@2539
  2002
                status = PEP_KEY_NOT_FOUND;
vb@2539
  2003
                break;
vb@2539
  2004
            case GPG_ERR_INV_VALUE:
vb@2539
  2005
                status = PEP_ILLEGAL_VALUE;
vb@2539
  2006
                break;
vb@2539
  2007
            case GPG_ERR_AMBIGUOUS_NAME:
vb@2539
  2008
                status = PEP_KEY_HAS_AMBIG_NAME;
vb@2539
  2009
                break;
vb@2539
  2010
            case GPG_ERR_ENOMEM:
vb@2539
  2011
                free_stringlist(result_list);
vb@2539
  2012
                free_stringlist(private_keylist);
vb@2539
  2013
                return PEP_OUT_OF_MEMORY;
vb@2539
  2014
            default:
vb@2539
  2015
                assert(0);
vb@2539
  2016
                status = PEP_UNKNOWN_ERROR;
vb@2539
  2017
        }
vb@2539
  2018
        if (key && gpgme_error == GPG_ERR_NO_ERROR) {
vb@2539
  2019
            if (key->revoked || key->disabled) {
vb@2539
  2020
                status = PEP_KEY_UNSUITABLE;
krista@2416
  2021
            }
vb@2539
  2022
            else {
vb@2539
  2023
                if (key->fpr && key->secret && key->can_encrypt && key->can_sign) {
vb@2539
  2024
                    if (key->owner_trust == GPGME_VALIDITY_ULTIMATE &&
vb@2539
  2025
                            key->uids && key->uids->email && key->uids->name) { 
vb@2539
  2026
                        _result_list = stringlist_add(_result_list, key->fpr);
vb@2539
  2027
                        if (!_result_list) {
vb@2539
  2028
                            free_stringlist(result_list);
vb@2539
  2029
                            free_stringlist(private_keylist);
vb@2539
  2030
                            return PEP_OUT_OF_MEMORY;
vb@2539
  2031
                        }
vb@2539
  2032
                        _result_list = stringlist_add(_result_list, key->uids->email);
vb@2539
  2033
                        if (!_result_list) {
vb@2539
  2034
                            free_stringlist(result_list);
vb@2539
  2035
                            free_stringlist(private_keylist);
vb@2539
  2036
                            return PEP_OUT_OF_MEMORY;
vb@2539
  2037
                        }
vb@2539
  2038
                        _result_list = stringlist_add(_result_list, key->uids->name);
vb@2539
  2039
                        if (!_result_list) {
vb@2539
  2040
                            free_stringlist(result_list);
vb@2539
  2041
                            free_stringlist(private_keylist);
vb@2539
  2042
                            return PEP_OUT_OF_MEMORY;
krista@2457
  2043
                        }
krista@2457
  2044
                    }
krista@2457
  2045
                }
krista@2416
  2046
            }
krista@2416
  2047
        }
krista@2416
  2048
    }
vb@2539
  2049
vb@2539
  2050
    free_stringlist(private_keylist);
vb@2539
  2051
    *keylist = result_list;
vb@2539
  2052
    return PEP_STATUS_OK;
krista@2416
  2053
}
krista@2416
  2054
vb@24
  2055
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
vb@24
  2056
{
vb@24
  2057
    gpgme_error_t gpgme_error;
vb@24
  2058
vb@24
  2059
    assert(session);
vb@24
  2060
    assert(pattern);
vb@24
  2061
vb@74
  2062
    gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
vb@24
  2063
        GPGME_EXPORT_MODE_EXTERN, NULL);
vb@45
  2064
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2065
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  2066
    if (gpgme_error == GPG_ERR_NO_ERROR)
vb@24
  2067
        return PEP_STATUS_OK;
vb@24
  2068
    else
vb@24
  2069
        return PEP_CANNOT_SEND_KEY;
vb@24
  2070
}
vb@24
  2071
vb@24
  2072
PEP_STATUS pgp_get_key_rating(
vb@24
  2073
    PEP_SESSION session,
vb@24
  2074
    const char *fpr,
vb@24
  2075
    PEP_comm_type *comm_type
vb@24
  2076
    )
vb@24
  2077
{
vb@24
  2078
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
  2079
    gpgme_error_t gpgme_error;
vb@24
  2080
    gpgme_key_t key;
vb@24
  2081
vb@24
  2082
    assert(session);
vb@24
  2083
    assert(fpr);
vb@24
  2084
    assert(comm_type);
vb@24
  2085
vb@24
  2086
    *comm_type = PEP_ct_unknown;
vb@24
  2087
vb@74
  2088
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
vb@45
  2089
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2090
    switch (gpgme_error) {
vb@24
  2091
    case GPG_ERR_NO_ERROR:
vb@24
  2092
        break;
vb@24
  2093
    case GPG_ERR_INV_VALUE:
vb@24
  2094
        assert(0);
vb@24
  2095
        return PEP_UNKNOWN_ERROR;
vb@24
  2096
    default:
vb@24
  2097
        return PEP_GET_KEY_FAILED;
vb@24
  2098
    };
vb@24
  2099
vb@74
  2100
    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  2101
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2102
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  2103
vb@24
  2104
    if (key == NULL) {
vb@74
  2105
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2106
        return PEP_KEY_NOT_FOUND;
vb@24
  2107
    }
vb@24
  2108
vb@24
  2109
    switch (key->protocol) {
vb@24
  2110
    case GPGME_PROTOCOL_OpenPGP:
vb@24
  2111
    case GPGME_PROTOCOL_DEFAULT:
vb@24
  2112
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
vb@24
  2113
        break;
vb@24
  2114
    case GPGME_PROTOCOL_CMS:
vb@24
  2115
        *comm_type = PEP_ct_CMS_unconfirmed;
vb@24
  2116
        break;
vb@24
  2117
    default:
vb@24
  2118
        *comm_type = PEP_ct_unknown;
vb@74
  2119
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2120
        return PEP_STATUS_OK;
vb@24
  2121
    }
krista@3104
  2122
    
vb@24
  2123
krista@3104
  2124
    // N.B. and FIXME 
krista@3104
  2125
    // We could get a key with a bad signing subkey and a good encryption
krista@3104
  2126
    // subkey. For now, we reject this, because it forces large changes in
krista@3104
  2127
    // how we rate keys. It's on the to-do list, but it's low priority.
krista@3104
  2128
    // We don't really want to be doing much for tinkered keys in the first
krista@3104
  2129
    // place.
vb@24
  2130
    switch (gpgme_error) {
vb@24
  2131
    case GPG_ERR_EOF:
vb@24
  2132
        break;
vb@24
  2133
    case GPG_ERR_NO_ERROR:
vb@24
  2134
        assert(key);
vb@24
  2135
        assert(key->subkeys);
krista@3104
  2136
        
krista@3104
  2137
        // is main key expired or revoked? If so, we can cut short this nonsense.
krista@3104
  2138
        if (key->invalid)
krista@3104
  2139
            *comm_type = PEP_ct_key_b0rken;
krista@3104
  2140
        else if (key->revoked)
krista@3104
  2141
            *comm_type = PEP_ct_key_revoked;            
krista@3104
  2142
        else if (key->expired)
krista@3104
  2143
            *comm_type = PEP_ct_key_expired;
krista@3104
  2144
        else {
krista@3104
  2145
            // Ok, so we now need to check subkeys. Normally, we could just
krista@3104
  2146
            // shortcut this by looking at key->can_sign and key->can_encrypt,
krista@3104
  2147
            // but we want the REASON we can't use a key, so this gets ugly.
krista@3104
  2148
            PEP_comm_type max_comm_type = *comm_type;
krista@3104
  2149
                        
krista@3104
  2150
            PEP_comm_type best_sign = PEP_ct_no_encryption;
krista@3104
  2151
            PEP_comm_type best_enc = PEP_ct_no_encryption;
krista@3104
  2152
            
krista@3104
  2153
            for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
krista@3104
  2154
                if (sk->can_sign || sk->can_encrypt) {
krista@3104
  2155
                    PEP_comm_type curr_sign = PEP_ct_no_encryption;
krista@3104
  2156
                    PEP_comm_type curr_enc = PEP_ct_no_encryption;
krista@3104
  2157
                    
krista@3104
  2158
                    if (sk->length < 1024) {
krista@3104
  2159
                        if (sk->can_sign)
krista@3104
  2160
                            curr_sign = PEP_ct_key_too_short;
krista@3104
  2161
                        if (sk->can_encrypt)                               
krista@3104
  2162
                            curr_enc = PEP_ct_key_too_short;
krista@3104
  2163
                    }
krista@3104
  2164
                    else if (
krista@3104
  2165
                        ((sk->pubkey_algo == GPGME_PK_RSA)
krista@3104
  2166
                        || (sk->pubkey_algo == GPGME_PK_RSA_E)
krista@3104
  2167
                        || (sk->pubkey_algo == GPGME_PK_RSA_S))
krista@3104
  2168
                        && sk->length == 1024) {
krista@3104
  2169
                        if (sk->can_sign)
krista@3104
  2170
                            curr_sign = PEP_ct_OpenPGP_weak_unconfirmed;
krista@3104
  2171
                        if (sk->can_encrypt)                               
krista@3104
  2172
                            curr_enc = PEP_ct_OpenPGP_weak_unconfirmed;
krista@3104
  2173
                    }
krista@3104
  2174
                    else {
krista@3104
  2175
                        if (sk->can_sign)
krista@3104
  2176
                            curr_sign = max_comm_type;
krista@3104
  2177
                        if (sk->can_encrypt)
krista@3104
  2178
                            curr_enc = max_comm_type;
krista@3104
  2179
                    }
krista@3104
  2180
                    if (sk->invalid) {
krista@3104
  2181
                        if (sk->can_sign)
krista@3104
  2182
                            curr_sign = PEP_ct_key_b0rken;
krista@3104
  2183
                        if (sk->can_encrypt)                               
krista@3104
  2184
                            curr_enc = PEP_ct_key_b0rken;
krista@3104
  2185
                    }
krista@3104
  2186
                    if (sk->expired) {
krista@3104
  2187
                        if (sk->can_sign)
krista@3104
  2188
                            curr_sign = PEP_ct_key_expired;
krista@3104
  2189
                        if (sk->can_encrypt)                               
krista@3104
  2190
                            curr_enc = PEP_ct_key_expired;
krista@3104
  2191
                    }
krista@3104
  2192
                    if (sk->revoked) {
krista@3104
  2193
                        if (sk->can_sign)
krista@3104
  2194
                            curr_sign = PEP_ct_key_revoked;
krista@3104
  2195
                        if (sk->can_encrypt)                               
krista@3104
  2196
                            curr_enc = PEP_ct_key_revoked;
krista@3104
  2197
                    }
krista@3104
  2198
                    if (sk->can_sign)
krista@3104
  2199
                        best_sign = _MAX(curr_sign, best_sign);
krista@3104
  2200
                    if (sk->can_encrypt)
krista@3104
  2201
                        best_enc = _MAX(curr_enc, best_enc);
krista@3104
  2202
                }    
krista@3104
  2203
            }
krista@3104
  2204
            if (best_enc == PEP_ct_no_encryption ||
krista@3104
  2205
                best_sign == PEP_ct_no_encryption) {
vb@24
  2206
                *comm_type = PEP_ct_key_b0rken;
vb@24
  2207
            }
krista@3104
  2208
            else {
krista@3104
  2209
                *comm_type = _MIN(best_sign, _MIN(max_comm_type, best_enc));
krista@3104
  2210
            }                
vb@24
  2211
        }
vb@24
  2212
        break;
vb@24
  2213
    case GPG_ERR_ENOMEM:
vb@74
  2214
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2215
        *comm_type = PEP_ct_unknown;
vb@24
  2216
        return PEP_OUT_OF_MEMORY;
vb@24
  2217
    default:
vb@74
  2218
        gpg.gpgme_op_keylist_end(session->ctx);
vb@46
  2219
        return PEP_UNKNOWN_ERROR;
vb@24
  2220
    };
vb@24
  2221
vb@74
  2222
    gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2223
vb@24
  2224
    return status;
vb@24
  2225
}
vb@200
  2226
vb@200
  2227
krista@1924
  2228
static ssize_t _nullwriter(
krista@1924
  2229
        void *_handle,
krista@1924
  2230
        const void *buffer,
krista@1924
  2231
        size_t size
krista@1924
  2232
    )
krista@1924
  2233
{
krista@1924
  2234
    return size;
krista@1924
  2235
}
krista@1924
  2236
krista@1924
  2237
typedef struct _replace_only_uid_state {
krista@1924
  2238
    enum {
krista@1924
  2239
        replace_uid_command = 0,
krista@1924
  2240
        replace_uid_realname,
krista@1924
  2241
        replace_uid_email,
kgrothoff@1926
  2242
        replace_uid_comment,
krista@1924
  2243
        replace_uid_adduid_ok,
krista@1924
  2244
        replace_uid_select_for_delete,
krista@1924
  2245
        replace_uid_delete,
krista@1924
  2246
        replace_uid_delete_confirm,
krista@1924
  2247
        replace_uid_select_for_trust,
krista@1924
  2248
        replace_uid_trust,
krista@1924
  2249
        replace_uid_trust_ultimate,
krista@1924
  2250
        replace_uid_trust_ultimate_confirm,
krista@1924
  2251
        replace_uid_quit,
krista@1924
  2252
        replace_uid_save_okay,
krista@1924
  2253
        replace_uid_exit,
krista@1924
  2254
        replace_uid_error = -1
krista@1924
  2255
    } state;
krista@1924
  2256
const char *realname;
krista@1924
  2257
const char *email;
krista@1924
  2258
} replace_only_uid_state;
krista@1924
  2259
kgrothoff@1926
  2260
krista@1924
  2261
static gpgme_error_t replace_only_uid_fsm(
krista@1924
  2262
    void *_handle,
krista@1924
  2263
    gpgme_status_code_t statuscode,
krista@1924
  2264
    const char *args,
krista@1924
  2265
    int fd
krista@1924
  2266
)
krista@1924
  2267
{
krista@1924
  2268
    replace_only_uid_state *handle = _handle;
krista@1924
  2269
        
krista@1924
  2270
    switch (handle->state) {
krista@1924
  2271
        case replace_uid_command:
krista@1924
  2272
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2273
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2274
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2275
                    handle->state = replace_uid_error;
krista@1924
  2276
                    return GPG_ERR_GENERAL;
krista@1924
  2277
                }
krista@1924
  2278
                gpg.gpgme_io_write(fd, "adduid\n", 7);
krista@1924
  2279
                handle->state = replace_uid_realname;
krista@1924
  2280
            }
krista@1924
  2281
            break;
krista@1924
  2282
            
krista@1924
  2283
        case replace_uid_realname:
krista@1924
  2284
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2285
                assert(strcmp(args, "keygen.name") == 0);
krista@1924
  2286
                assert(handle->realname);
krista@1924
  2287
                if (strcmp(args, "keygen.name") || !handle->realname) {
krista@1924
  2288
                    handle->state = replace_uid_error;
krista@1924
  2289
                    return GPG_ERR_GENERAL;
krista@1924
  2290
                }
krista@1924
  2291
                size_t realname_strlen = strlen(handle->realname);
krista@1924
  2292
                char* realname = (char*)calloc(1, realname_strlen + 2); // \n + \0
krista@1924
  2293
                if (!realname) {
krista@1924
  2294
                    handle->state = replace_uid_error;
krista@1924
  2295
                    return GPG_ERR_ENOMEM;
krista@1924
  2296
                }
kgrothoff@1926
  2297
                strlcpy(realname, handle->realname, realname_strlen + 1);
roker@2055
  2298
                realname[realname_strlen] = '\n';
krista@1924
  2299
                gpg.gpgme_io_write(fd, realname, realname_strlen + 1);
krista@1924
  2300
                handle->state = replace_uid_email;
krista@1924
  2301
                free(realname);
krista@1924
  2302
            }
krista@1924
  2303
            break;
krista@1924
  2304
            
krista@1924
  2305
        case replace_uid_email:
krista@1924
  2306
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2307
                assert(strcmp(args, "keygen.email") == 0);
krista@1924
  2308
                assert(handle->email);
krista@1924
  2309
                if (strcmp(args, "keygen.email") || !handle->email) {
krista@1924
  2310
                    handle->state = replace_uid_error;
krista@1924
  2311
                    return GPG_ERR_GENERAL;
krista@1924
  2312
                }
krista@1924
  2313
                size_t email_strlen = strlen(handle->email);
krista@1924
  2314
                char* email = (char*)calloc(1, email_strlen + 2); // \n + \0
krista@1924
  2315
                if (!email) {
krista@1924
  2316
                    handle->state = replace_uid_error;
krista@1924
  2317
                    return GPG_ERR_ENOMEM;
krista@1924
  2318
                }
kgrothoff@1926
  2319
                strlcpy(email, handle->email, email_strlen + 1);
roker@2055
  2320
                email[email_strlen] = '\n';
krista@1924
  2321
                gpg.gpgme_io_write(fd, email, email_strlen + 1);
kgrothoff@1926
  2322
                handle->state = replace_uid_comment;
krista@1924
  2323
                free(email);
krista@1924
  2324
            }
krista@1924
  2325
            break;
krista@1924
  2326
kgrothoff@1926
  2327
        case replace_uid_comment:
kgrothoff@1926
  2328
            if (statuscode == GPGME_STATUS_GET_LINE) {
kgrothoff@1926
  2329
                assert(strcmp(args, "keygen.comment") == 0);
kgrothoff@1926
  2330
                if (strcmp(args, "keygen.comment") || !handle->email) {
kgrothoff@1926
  2331
                    handle->state = replace_uid_error;
kgrothoff@1926
  2332
                    return GPG_ERR_GENERAL;
kgrothoff@1926
  2333
                }
kgrothoff@1926
  2334
                gpg.gpgme_io_write(fd, "\n", 1);
kgrothoff@1926
  2335
                //handle->state = replace_uid_adduid_ok;
kgrothoff@1926
  2336
                handle->state = replace_uid_select_for_delete;
kgrothoff@1926
  2337
            }
kgrothoff@1926
  2338
            break;
kgrothoff@1926
  2339
/*
krista@1924
  2340
        case replace_uid_adduid_ok:
krista@1924
  2341
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2342
                assert(strcmp(args, "keygen.userid.cmd") == 0);
krista@1924
  2343
                if (strcmp(args, "keygen.userid.cmd")) {
krista@1924
  2344
                    handle->state = replace_uid_error;
krista@1924
  2345
                    return GPG_ERR_GENERAL;
krista@1924
  2346
                }
krista@1924
  2347
                gpg.gpgme_io_write(fd, "O\n", 2);
krista@1924
  2348
                handle->state = replace_uid_select_for_delete;
krista@1924
  2349
            }
krista@1924
  2350
            break;
kgrothoff@1926
  2351
	    */
krista@1924
  2352
krista@1924
  2353
        case replace_uid_select_for_delete:
krista@1924
  2354
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2355
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2356
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2357
                    handle->state = replace_uid_error;
krista@1924
  2358
                    return GPG_ERR_GENERAL;
krista@1924
  2359
                }
krista@1924
  2360
                gpg.gpgme_io_write(fd, "uid 1\n", 6);
krista@1924
  2361
                handle->state = replace_uid_delete;
krista@1924
  2362
            }
krista@1924
  2363
            break;
krista@1924
  2364
krista@1924
  2365
        case replace_uid_delete:
krista@1924
  2366
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2367
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2368
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2369
                    handle->state = replace_uid_error;
krista@1924
  2370
                    return GPG_ERR_GENERAL;
krista@1924
  2371
                }
krista@1924
  2372
                gpg.gpgme_io_write(fd, "deluid\n", 7);
krista@1924
  2373
                handle->state = replace_uid_delete_confirm;
krista@1924
  2374
            }
krista@1924
  2375
            break;
krista@1924
  2376
krista@1924
  2377
        case replace_uid_delete_confirm:
kgrothoff@1926
  2378
            if (statuscode == GPGME_STATUS_GET_BOOL) {
krista@1924
  2379
                assert(strcmp(args, "keyedit.remove.uid.okay") == 0);
krista@1924
  2380
                if (strcmp(args, "keyedit.remove.uid.okay")) {
krista@1924
  2381
                    handle->state = replace_uid_error;
krista@1924
  2382
                    return GPG_ERR_GENERAL;
krista@1924
  2383
                }
krista@1924
  2384
                gpg.gpgme_io_write(fd, "Y\n", 2);
krista@1924
  2385
                handle->state = replace_uid_select_for_trust;
krista@1924
  2386
            }
krista@1924
  2387
            break;
krista@1924
  2388
krista@1924
  2389
        case replace_uid_select_for_trust:
krista@1924
  2390
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2391
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2392
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2393
                    handle->state = replace_uid_error;
krista@1924
  2394
                    return GPG_ERR_GENERAL;
krista@1924
  2395
                }
kgrothoff@1926
  2396
                gpg.gpgme_io_write(fd, "uid 1\n", 6);
krista@1924
  2397
                handle->state = replace_uid_trust;
krista@1924
  2398
            }
krista@1924
  2399
            break;
krista@1924
  2400
krista@1924
  2401
        case replace_uid_trust:
krista@1924
  2402
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2403
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2404
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2405
                    handle->state = replace_uid_error;
krista@1924
  2406
                    return GPG_ERR_GENERAL;
krista@1924
  2407
                }
kgrothoff@1926
  2408
                gpg.gpgme_io_write(fd, "trust\n", 6);
krista@1924
  2409
                handle->state = replace_uid_trust_ultimate;
krista@1924
  2410
            }
krista@1924
  2411
            break;
krista@1924
  2412
krista@1924
  2413
        case replace_uid_trust_ultimate:
krista@1924
  2414
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2415
                assert(strcmp(args, "edit_ownertrust.value") == 0);
krista@1924
  2416
                if (strcmp(args, "edit_ownertrust.value")) {
krista@1924
  2417
                    handle->state = replace_uid_error;
krista@1924
  2418
                    return GPG_ERR_GENERAL;
krista@1924
  2419
                }
krista@1924
  2420
                gpg.gpgme_io_write(fd, "5\n", 2);
krista@1924
  2421
                handle->state = replace_uid_trust_ultimate_confirm;
krista@1924
  2422
            }
krista@1924
  2423
            break;
krista@1924
  2424
krista@1924
  2425
        case replace_uid_trust_ultimate_confirm:
kgrothoff@1926
  2426
            if (statuscode == GPGME_STATUS_GET_BOOL) {
krista@1924
  2427
                assert(strcmp(args, "edit_ownertrust.set_ultimate.okay") == 0);
krista@1924
  2428
                if (strcmp(args, "edit_ownertrust.set_ultimate.okay")) {
krista@1924
  2429
                    handle->state = replace_uid_error;
krista@1924
  2430
                    return GPG_ERR_GENERAL;
krista@1924
  2431
                }
krista@1924
  2432
                gpg.gpgme_io_write(fd, "Y\n", 2);
krista@1924
  2433
                handle->state = replace_uid_quit;
krista@1924
  2434
            }
krista@1924
  2435
            break;
krista@1924
  2436
krista@1924
  2437
        case replace_uid_quit:
krista@1924
  2438
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2439
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2440
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2441
                    handle->state = replace_uid_error;
krista@1924
  2442
                    return GPG_ERR_GENERAL;
krista@1924
  2443
                }
krista@1924
  2444
                gpg.gpgme_io_write(fd, "quit\n", 5);
krista@1924
  2445
                handle->state = replace_uid_save_okay;
krista@1924
  2446
            }
krista@1924
  2447
            break;
krista@1924
  2448
krista@1924
  2449
        case replace_uid_save_okay:
kgrothoff@1926
  2450
            if (statuscode == GPGME_STATUS_GET_BOOL) {
krista@1924
  2451
                assert(strcmp(args, "keyedit.save.okay") == 0);
krista@1924
  2452
                if (strcmp(args, "keyedit.save.okay")) {
krista@1924
  2453
                    handle->state = replace_uid_error;
krista@1924
  2454
                    return GPG_ERR_GENERAL;
krista@1924
  2455
                }
krista@1924
  2456
                gpg.gpgme_io_write(fd, "Y\n", 2);
krista@1924
  2457
                handle->state = replace_uid_exit;
krista@1924
  2458
            }
krista@1924
  2459
            break;
krista@1924
  2460
krista@1924
  2461
        case replace_uid_exit:
krista@1924
  2462
            break;
krista@1924
  2463
krista@1924
  2464
        case replace_uid_error:
krista@1924
  2465
            return GPG_ERR_GENERAL;
krista@1924
  2466
            
krista@1924
  2467
        default:
roker@2055
  2468
            break;
krista@1924
  2469
    }
krista@1924
  2470
    return GPG_ERR_NO_ERROR;
krista@1924
  2471
}
krista@1924
  2472
krista@1924
  2473
PEP_STATUS pgp_replace_only_uid(
krista@1924
  2474
        PEP_SESSION session,
krista@1924
  2475
        const char* fpr,
krista@1924
  2476
        const char* realname,
krista@1924
  2477
        const char* email
krista@1924
  2478
    )
krista@1924
  2479
{
krista@1924
  2480
    PEP_STATUS status = PEP_STATUS_OK;
krista@1924
  2481
    gpgme_error_t gpgme_error;
krista@1924
  2482
    gpgme_key_t key;
krista@1924
  2483
    gpgme_data_t output;
krista@1924
  2484
    replace_only_uid_state handle;
krista@1924
  2485
krista@1924
  2486
    assert(session);
krista@1924
  2487
    assert(fpr);
krista@1924
  2488
    assert(realname);
krista@1924
  2489
    assert(email);
krista@1924
  2490
    
krista@1924
  2491
    memset(&handle, 0, sizeof(replace_only_uid_state));
krista@1924
  2492
    handle.realname = realname;
krista@1924
  2493
    handle.email = email;
krista@1924
  2494
krista@1924
  2495
    status = find_single_key(session, fpr, &key);
krista@1924
  2496
    if (status != PEP_STATUS_OK)
krista@1924
  2497
        return status;
krista@1924
  2498
krista@1924
  2499
    struct gpgme_data_cbs data_cbs;
krista@1924
  2500
    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
krista@1924
  2501
    data_cbs.write = _nullwriter;
krista@1924
  2502
    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
krista@1924
  2503
krista@2553
  2504
    gpgme_error = _GPGERR(gpg.gpgme_op_edit(session->ctx, key, replace_only_uid_fsm, &handle,
krista@2553
  2505
            output));
krista@1924
  2506
    assert(gpgme_error == GPG_ERR_NO_ERROR);
krista@1924
  2507
    if(gpgme_error != GPG_ERR_NO_ERROR) {
krista@1924
  2508
        status = PEP_CANNOT_EDIT_KEY;
krista@1924
  2509
    }
krista@1924
  2510
krista@1924
  2511
    gpg.gpgme_data_release(output);
krista@1924
  2512
    gpg.gpgme_key_unref(key);
krista@1924
  2513
krista@1924
  2514
    return status;
krista@1924
  2515
}
krista@1924
  2516
krista@1924
  2517
vb@201
  2518
typedef struct _renew_state {
vb@211
  2519
    enum {
vb@200
  2520
        renew_command = 0,
vb@200
  2521
        renew_date,
vb@200
  2522
        renew_secret_key,
vb@200
  2523
        renew_command2,
vb@200
  2524
        renew_date2,
vb@200
  2525
        renew_quit,
vb@200
  2526
        renew_save,
vb@200
  2527
        renew_exit,
vb@200
  2528
        renew_error = -1
vb@200
  2529
    } state;
vb@201
  2530
    const char *date_ref;
vb@201
  2531
} renew_state;
vb@200
  2532
vb@201
  2533
static gpgme_error_t renew_fsm(
vb@200
  2534
        void *_handle,
vb@200
  2535
        gpgme_status_code_t statuscode,
vb@200
  2536
        const char *args,
vb@200
  2537
        int fd
vb@200
  2538
    )
vb@200
  2539
{
vb@201
  2540
    renew_state *handle = _handle;
vb@200
  2541
vb@200
  2542
    switch (handle->state) {
vb@200
  2543
        case renew_command:
vb@200
  2544
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2545
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  2546
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  2547
                    handle->state = renew_error;
vb@201
  2548
                    return GPG_ERR_GENERAL;
vb@201
  2549
                }
vb@223
  2550
                gpg.gpgme_io_write(fd, "expire\n", 7);
vb@200
  2551
                handle->state = renew_date;
vb@200
  2552
            }
vb@200
  2553
            break;
vb@200
  2554
vb@200
  2555
        case renew_date:
vb@200
  2556
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2557
                assert(strcmp(args, "keygen.valid") == 0);
vb@201
  2558
                if (strcmp(args, "keygen.valid")) {
vb@201
  2559
                    handle->state = renew_error;
vb@201
  2560
                    return GPG_ERR_GENERAL;
vb@201
  2561
                }
vb@223
  2562
                gpg.gpgme_io_write(fd, handle->date_ref, 11);
vb@200
  2563
                handle->state = renew_secret_key;
vb@200
  2564
            }
vb@200
  2565
            break;
vb@200
  2566
vb@200
  2567
        case renew_secret_key:
vb@200
  2568
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2569
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  2570
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  2571
                    handle->state = renew_error;
vb@201
  2572
                    return GPG_ERR_GENERAL;
vb@201
  2573
                }
vb@223
  2574
                gpg.gpgme_io_write(fd, "key 1\n", 6);
vb@200
  2575
                handle->state = renew_command2;
vb@200
  2576
            }
vb@200
  2577
            break;
vb@200
  2578
vb@200
  2579
        case renew_command2:
vb@200
  2580
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2581
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  2582
                if