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