src/pgp_gpg.c
author Volker Birk <vb@pep-project.org>
Sat, 12 Nov 2016 21:31:53 +0100
changeset 1387 cc339b22d690
parent 1385 5f54184b1e94
child 1397 0a64816a6e37
child 1419 54d8198b2cdf
permissions -rw-r--r--
FIX: gpgme_key_release was not dynamically loaded
FIX: missing DYNAMIC_API on declaration of update_identity()
vb@219
     1
#include "platform.h"
vb@130
     2
#include "pEp_internal.h"
vb@24
     3
#include "pgp_gpg.h"
vb@24
     4
vb@78
     5
#include <limits.h>
vb@78
     6
vb@62
     7
#include "wrappers.h"
vb@62
     8
vb@45
     9
#define _GPGERR(X) ((X) & 0xffffL)
vb@45
    10
vb@76
    11
static void *gpgme;
vb@76
    12
static struct gpg_s gpg;
vb@74
    13
krista@763
    14
static bool ensure_config_values(stringlist_t *keys, stringlist_t *values, const char* config_file_path)
vb@24
    15
{
vb@24
    16
    static char buf[MAX_LINELENGTH];
vb@78
    17
    int r;
vb@62
    18
    FILE *f;
vb@78
    19
    stringlist_t *_k;
vb@78
    20
    stringlist_t *_v;
vb@79
    21
    unsigned int i;
vb@78
    22
    unsigned int found = 0;
vb@62
    23
krista@763
    24
    f = Fopen(config_file_path, "r");
vb@63
    25
    if (f == NULL && errno == ENOMEM)
vb@62
    26
        return false;
vb@24
    27
vb@24
    28
    if (f != NULL) {
vb@78
    29
        int length = stringlist_length(keys);
vb@79
    30
        unsigned int n = (1 << length) - 1;
vb@78
    31
krista@846
    32
        // make sure we 1) have the same number of keys and values
krista@846
    33
        // and 2) we don't have more key/value pairs than
krista@846
    34
        // the size of the bitfield used to hold the indices
krista@846
    35
        // of key/value pairs matching keys in the config file.
vb@78
    36
        assert(length <= sizeof(unsigned int) * CHAR_BIT);
vb@78
    37
        assert(length == stringlist_length(values));
krista@846
    38
        if (!(length == stringlist_length(values) &&
krista@846
    39
              length <= sizeof(unsigned int) * CHAR_BIT)) {
krista@915
    40
            r = Fclose(f);
krista@915
    41
            assert(r == 0);
krista@915
    42
        
krista@846
    43
            return false;
krista@846
    44
        }
krista@846
    45
        
vb@62
    46
        do {
vb@62
    47
            char * s;
vb@62
    48
vb@63
    49
            s = Fgets(buf, MAX_LINELENGTH, f);
vb@78
    50
            if (!feof(f)) {
vb@78
    51
                assert(s);
vb@78
    52
                if (s == NULL)
vb@78
    53
                    return false;
vb@62
    54
vb@78
    55
                if (s && !feof(f)) {
vb@80
    56
                    char * rest;
vb@80
    57
                    char * t = strtok_r(s, " ", &rest);
vb@78
    58
                    for (i = 1, _k = keys, _v = values; _k != NULL;
vb@78
    59
                            _k = _k->next, _v = _v->next, i <<= 1) {
vb@80
    60
                        if (t && strncmp(t, _k->value, strlen(_k->value)) == 0)
vb@78
    61
                            found |= i;
vb@78
    62
vb@78
    63
                        if (i == n) {
vb@78
    64
                            r = Fclose(f);
vb@78
    65
                            return true;
vb@78
    66
                        }
vb@78
    67
                    }
vb@24
    68
                }
vb@24
    69
            }
vb@62
    70
        } while (!feof(f));
krista@763
    71
        f = Freopen(config_file_path, "a", f);
vb@24
    72
    }
vb@24
    73
    else {
krista@763
    74
        f = Fopen(config_file_path, "w");
vb@24
    75
    }
vb@24
    76
vb@24
    77
    assert(f);
vb@24
    78
    if (f == NULL)
vb@24
    79
        return false;
vb@24
    80
vb@78
    81
    for (i = 1, _k = keys, _v = values; _k != NULL; _k = _k->next,
vb@78
    82
            _v = _v->next, i <<= 1) {
vb@78
    83
        if ((found & i) == 0) {
vb@79
    84
            r = Fprintf(f, "%s %s\n", _k->value, _v->value);
vb@79
    85
            assert(r >= 0);
vb@78
    86
        }
vb@78
    87
    }
vb@62
    88
vb@63
    89
    r = Fclose(f);
vb@62
    90
    assert(r == 0);
vb@24
    91
vb@24
    92
    return true;
vb@24
    93
}
vb@24
    94
krista@763
    95
vb@62
    96
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
vb@24
    97
{
vb@66
    98
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
    99
    gpgme_error_t gpgme_error;
vb@62
   100
    bool bResult;
vb@62
   101
    
vb@62
   102
    if (in_first) {
vb@78
   103
        stringlist_t *conf_keys   = new_stringlist("keyserver");
vb@78
   104
        stringlist_t *conf_values = new_stringlist("hkp://keys.gnupg.net");
vb@79
   105
vb@78
   106
        stringlist_add(conf_keys, "cert-digest-algo");
vb@78
   107
        stringlist_add(conf_values, "SHA256");
vb@78
   108
vb@80
   109
        stringlist_add(conf_keys, "no-emit-version");
vb@80
   110
        stringlist_add(conf_values, "");
vb@80
   111
vb@80
   112
        stringlist_add(conf_keys, "no-comments");
vb@80
   113
        stringlist_add(conf_values, "");
vb@80
   114
vb@80
   115
        stringlist_add(conf_keys, "personal-cipher-preferences");
vb@80
   116
        stringlist_add(conf_values, "AES AES256 AES192 CAST5");
vb@80
   117
vb@80
   118
        stringlist_add(conf_keys, "personal-digest-preferences");
vb@312
   119
        stringlist_add(conf_values, "SHA256 SHA512 SHA384 SHA224");
krista@763
   120
krista@763
   121
        bResult = ensure_config_values(conf_keys, conf_values, gpg_conf());
vb@24
   122
vb@78
   123
        free_stringlist(conf_keys);
vb@78
   124
        free_stringlist(conf_values);
vb@78
   125
Edouard@175
   126
        assert(bResult);
Edouard@175
   127
        if(!bResult){
Edouard@175
   128
            status = PEP_INIT_NO_GPG_HOME;
Edouard@175
   129
            goto pep_error;
Edouard@175
   130
        }
Edouard@175
   131
krista@763
   132
        conf_keys = new_stringlist("default-cache-ttl");
krista@763
   133
        conf_values = new_stringlist("300");
krista@763
   134
krista@763
   135
        stringlist_add(conf_keys, "max-cache-ttl");
krista@763
   136
        stringlist_add(conf_values, "1200");
krista@763
   137
krista@763
   138
        bResult = ensure_config_values(conf_keys, conf_values, gpg_agent_conf());
krista@763
   139
krista@763
   140
        free_stringlist(conf_keys);
krista@763
   141
        free_stringlist(conf_values);
krista@763
   142
krista@763
   143
        assert(bResult);
krista@763
   144
        if(!bResult){
krista@763
   145
            status = PEP_INIT_NO_GPG_HOME; /* FIXME: Wrong error here? */
krista@763
   146
            goto pep_error;
krista@763
   147
        }
Edouard@175
   148
vb@62
   149
        gpgme = dlopen(LIBGPGME, RTLD_LAZY);
vb@62
   150
        if (gpgme == NULL) {
vb@66
   151
            status = PEP_INIT_CANNOT_LOAD_GPGME;
vb@66
   152
            goto pep_error;
vb@62
   153
        }
vb@62
   154
vb@62
   155
        memset(&gpg, 0, sizeof(struct gpg_s));
vb@62
   156
vb@62
   157
        gpg.gpgme_set_locale
vb@62
   158
            = (gpgme_set_locale_t) (intptr_t) dlsym(gpgme,
vb@62
   159
            "gpgme_set_locale");
vb@62
   160
        assert(gpg.gpgme_set_locale);
vb@62
   161
vb@62
   162
        gpg.gpgme_check
vb@62
   163
            = (gpgme_check_version_t) (intptr_t) dlsym(gpgme,
vb@62
   164
            "gpgme_check_version");
vb@62
   165
        assert(gpg.gpgme_check);
vb@62
   166
vb@62
   167
        gpg.gpgme_new
vb@62
   168
            = (gpgme_new_t) (intptr_t) dlsym(gpgme, "gpgme_new");
vb@62
   169
        assert(gpg.gpgme_new);
vb@62
   170
vb@62
   171
        gpg.gpgme_release
vb@62
   172
            = (gpgme_release_t) (intptr_t) dlsym(gpgme, "gpgme_release");
vb@62
   173
        assert(gpg.gpgme_release);
vb@62
   174
vb@507
   175
        gpg.gpgme_get_engine_info
vb@507
   176
            = (gpgme_get_engine_info_t) (intptr_t) dlsym(gpgme,
vb@507
   177
            "gpgme_get_engine_info");
vb@507
   178
        assert(gpg.gpgme_get_engine_info);
vb@507
   179
vb@62
   180
        gpg.gpgme_set_protocol
vb@62
   181
            = (gpgme_set_protocol_t) (intptr_t) dlsym(gpgme,
vb@62
   182
            "gpgme_set_protocol");
vb@62
   183
        assert(gpg.gpgme_set_protocol);
vb@62
   184
vb@62
   185
        gpg.gpgme_set_armor
vb@62
   186
            = (gpgme_set_armor_t) (intptr_t) dlsym(gpgme,
vb@62
   187
            "gpgme_set_armor");
vb@62
   188
        assert(gpg.gpgme_set_armor);
vb@62
   189
vb@62
   190
        gpg.gpgme_data_new
vb@62
   191
            = (gpgme_data_new_t) (intptr_t) dlsym(gpgme,
vb@62
   192
            "gpgme_data_new");
vb@62
   193
        assert(gpg.gpgme_data_new);
vb@62
   194
vb@62
   195
        gpg.gpgme_data_new_from_mem
vb@62
   196
            = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(gpgme,
vb@62
   197
            "gpgme_data_new_from_mem");
vb@62
   198
        assert(gpg.gpgme_data_new_from_mem);
vb@62
   199
vb@221
   200
        gpg.gpgme_data_new_from_cbs
vb@221
   201
            = (gpgme_data_new_from_cbs_t) (intptr_t) dlsym(gpgme,
vb@221
   202
            "gpgme_data_new_from_cbs");
vb@221
   203
        assert(gpg.gpgme_data_new_from_cbs);
vb@221
   204
vb@62
   205
        gpg.gpgme_data_release
vb@62
   206
            = (gpgme_data_release_t) (intptr_t) dlsym(gpgme,
vb@62
   207
            "gpgme_data_release");
vb@62
   208
        assert(gpg.gpgme_data_release);
vb@62
   209
vb@62
   210
        gpg.gpgme_data_identify
vb@62
   211
            = (gpgme_data_identify_t) (intptr_t) dlsym(gpgme,
vb@62
   212
            "gpgme_data_identify");
vb@62
   213
        assert(gpg.gpgme_data_identify);
vb@62
   214
vb@62
   215
        gpg.gpgme_data_seek
vb@62
   216
            = (gpgme_data_seek_t) (intptr_t) dlsym(gpgme,
vb@62
   217
            "gpgme_data_seek");
vb@62
   218
        assert(gpg.gpgme_data_seek);
vb@62
   219
vb@62
   220
        gpg.gpgme_data_read
vb@62
   221
            = (gpgme_data_read_t) (intptr_t) dlsym(gpgme,
vb@62
   222
            "gpgme_data_read");
vb@62
   223
        assert(gpg.gpgme_data_read);
vb@62
   224
vb@62
   225
        gpg.gpgme_op_decrypt
vb@62
   226
            = (gpgme_op_decrypt_t) (intptr_t) dlsym(gpgme,
vb@62
   227
            "gpgme_op_decrypt");
vb@62
   228
        assert(gpg.gpgme_op_decrypt);
vb@62
   229
vb@62
   230
        gpg.gpgme_op_verify
vb@62
   231
            = (gpgme_op_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   232
            "gpgme_op_verify");
vb@62
   233
        assert(gpg.gpgme_op_verify);
vb@62
   234
vb@62
   235
        gpg.gpgme_op_decrypt_verify
vb@62
   236
            = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   237
            "gpgme_op_decrypt_verify");
vb@62
   238
        assert(gpg.gpgme_op_decrypt_verify);
vb@62
   239
vb@62
   240
        gpg.gpgme_op_decrypt_result
vb@62
   241
            = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(gpgme,
vb@62
   242
            "gpgme_op_decrypt_result");
vb@62
   243
        assert(gpg.gpgme_op_decrypt_result);
vb@62
   244
vb@62
   245
        gpg.gpgme_op_encrypt_sign
vb@62
   246
            = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(gpgme,
vb@62
   247
            "gpgme_op_encrypt_sign");
vb@62
   248
        assert(gpg.gpgme_op_encrypt_sign);
vb@62
   249
vb@62
   250
        gpg.gpgme_op_verify_result
vb@62
   251
            = (gpgme_op_verify_result_t) (intptr_t) dlsym(gpgme,
vb@62
   252
            "gpgme_op_verify_result");
vb@62
   253
        assert(gpg.gpgme_op_verify_result);
vb@62
   254
vb@62
   255
        gpg.gpgme_signers_clear
vb@62
   256
            = (gpgme_signers_clear_t) (intptr_t) dlsym(gpgme,
vb@62
   257
            "gpgme_signers_clear");
vb@62
   258
        assert(gpg.gpgme_signers_clear);
vb@62
   259
vb@62
   260
        gpg.gpgme_signers_add
vb@62
   261
            = (gpgme_signers_add_t) (intptr_t) dlsym(gpgme,
vb@62
   262
            "gpgme_signers_add");
vb@62
   263
        assert(gpg.gpgme_signers_add);
vb@62
   264
vb@62
   265
        gpg.gpgme_get_key
vb@62
   266
            = (gpgme_get_key_t) (intptr_t) dlsym(gpgme, "gpgme_get_key");
vb@62
   267
        assert(gpg.gpgme_get_key);
vb@62
   268
vb@62
   269
        gpg.gpgme_op_genkey
vb@62
   270
            = (gpgme_op_genkey_t) (intptr_t) dlsym(gpgme,
vb@62
   271
            "gpgme_op_genkey");
vb@62
   272
        assert(gpg.gpgme_op_genkey);
vb@62
   273
vb@62
   274
        gpg.gpgme_op_genkey_result
vb@62
   275
            = (gpgme_op_genkey_result_t) (intptr_t) dlsym(gpgme,
vb@62
   276
            "gpgme_op_genkey_result");
vb@62
   277
        assert(gpg.gpgme_op_genkey_result);
vb@62
   278
vb@62
   279
        gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
vb@62
   280
            dlsym(gpgme, "gpgme_op_delete");
vb@62
   281
        assert(gpg.gpgme_op_delete);
vb@62
   282
vb@62
   283
        gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
vb@62
   284
            dlsym(gpgme, "gpgme_op_import");
vb@62
   285
        assert(gpg.gpgme_op_import);
vb@62
   286
Edouard@728
   287
        gpg.gpgme_op_import_result
Edouard@728
   288
            = (gpgme_op_import_result_t) (intptr_t) dlsym(gpgme,
Edouard@728
   289
            "gpgme_op_import_result");
Edouard@728
   290
        assert(gpg.gpgme_op_import_result);
Edouard@728
   291
vb@62
   292
        gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
vb@62
   293
            dlsym(gpgme, "gpgme_op_export");
vb@62
   294
        assert(gpg.gpgme_op_export);
vb@62
   295
vb@62
   296
        gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
vb@62
   297
            dlsym(gpgme, "gpgme_set_keylist_mode");
vb@62
   298
        assert(gpg.gpgme_set_keylist_mode);
vb@62
   299
vb@62
   300
        gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
vb@62
   301
            dlsym(gpgme, "gpgme_get_keylist_mode");
vb@62
   302
        assert(gpg.gpgme_get_keylist_mode);
vb@62
   303
vb@62
   304
        gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
vb@62
   305
            dlsym(gpgme, "gpgme_op_keylist_start");
vb@62
   306
        assert(gpg.gpgme_op_keylist_start);
vb@62
   307
vb@62
   308
        gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
vb@62
   309
            dlsym(gpgme, "gpgme_op_keylist_next");
vb@62
   310
        assert(gpg.gpgme_op_keylist_next);
vb@62
   311
vb@62
   312
        gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
vb@62
   313
            dlsym(gpgme, "gpgme_op_keylist_end");
vb@62
   314
        assert(gpg.gpgme_op_keylist_end);
vb@62
   315
vb@62
   316
        gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
vb@62
   317
            dlsym(gpgme, "gpgme_op_import_keys");
vb@62
   318
        assert(gpg.gpgme_op_import_keys);
vb@62
   319
vb@62
   320
        gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
vb@62
   321
            dlsym(gpgme, "gpgme_key_ref");
vb@62
   322
        assert(gpg.gpgme_key_ref);
vb@62
   323
vb@62
   324
        gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
vb@62
   325
            dlsym(gpgme, "gpgme_key_unref");
vb@62
   326
        assert(gpg.gpgme_key_unref);
vb@62
   327
vb@1387
   328
		gpg.gpgme_key_release = (gpgme_key_release_t)(intptr_t)
vb@1387
   329
			dlsym(gpgme, "gpgme_key_release");
vb@1387
   330
		assert(gpg.gpgme_key_release);
vb@1387
   331
vb@221
   332
        gpg.gpgme_op_edit = (gpgme_op_edit_t) (intptr_t)
vb@221
   333
            dlsym(gpgme, "gpgme_op_edit");
vb@221
   334
        assert(gpg.gpgme_op_edit);
vb@221
   335
vb@223
   336
        gpg.gpgme_io_write = (gpgme_io_write_t) (intptr_t)
vb@223
   337
            dlsym(gpgme, "gpgme_io_write");
vb@223
   338
        assert(gpg.gpgme_io_write);
vb@223
   339
vb@62
   340
        gpg.version = gpg.gpgme_check(NULL);
vb@62
   341
        
roker@876
   342
        const char * const cLocal = setlocale(LC_ALL, NULL);
Edouard@348
   343
        if (!cLocal || (strcmp(cLocal, "C") == 0))
vb@62
   344
            setlocale(LC_ALL, "");
vb@62
   345
vb@62
   346
        gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
vb@62
   347
#ifdef LC_MESSAGES // Windoze
vb@62
   348
        gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
vb@62
   349
#endif
vb@24
   350
    }
vb@24
   351
vb@62
   352
    gpgme_error = gpg.gpgme_new(&session->ctx);
vb@45
   353
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   354
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@66
   355
        status = PEP_INIT_GPGME_INIT_FAILED;
vb@66
   356
        goto pep_error;
vb@24
   357
    }
vb@46
   358
    assert(session->ctx);
vb@24
   359
vb@62
   360
    gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
vb@45
   361
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   362
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   363
vb@62
   364
    gpg.gpgme_set_armor(session->ctx, 1);
vb@24
   365
vb@24
   366
    return PEP_STATUS_OK;
vb@66
   367
vb@66
   368
pep_error:
vb@66
   369
    pgp_release(session, in_first);
vb@66
   370
    return status;
vb@24
   371
}
vb@24
   372
vb@62
   373
void pgp_release(PEP_SESSION session, bool out_last)
vb@24
   374
{
vb@62
   375
    if (session->ctx) {
vb@74
   376
        gpg.gpgme_release(session->ctx);
vb@62
   377
        session->ctx = NULL;
vb@62
   378
    }
vb@62
   379
vb@74
   380
    if (out_last)
vb@74
   381
        if (gpgme)
vb@74
   382
            dlclose(gpgme);
vb@24
   383
}
vb@24
   384
vb@24
   385
PEP_STATUS pgp_decrypt_and_verify(
vb@24
   386
    PEP_SESSION session, const char *ctext, size_t csize,
vb@24
   387
    char **ptext, size_t *psize, stringlist_t **keylist
vb@24
   388
    )
vb@24
   389
{
vb@24
   390
    PEP_STATUS result;
vb@24
   391
    gpgme_error_t gpgme_error;
vb@24
   392
    gpgme_data_t cipher, plain;
vb@24
   393
    gpgme_data_type_t dt;
vb@24
   394
vb@24
   395
    stringlist_t *_keylist = NULL;
roker@723
   396
    //int i_key = 0;
vb@24
   397
vb@46
   398
    assert(session);
vb@24
   399
    assert(ctext);
vb@24
   400
    assert(csize);
vb@24
   401
    assert(ptext);
vb@24
   402
    assert(psize);
vb@24
   403
    assert(keylist);
vb@24
   404
vb@24
   405
    *ptext = NULL;
vb@24
   406
    *psize = 0;
vb@24
   407
    *keylist = NULL;
vb@24
   408
vb@74
   409
    gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
vb@45
   410
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   411
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   412
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   413
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   414
            return PEP_OUT_OF_MEMORY;
vb@24
   415
        else
vb@24
   416
            return PEP_UNKNOWN_ERROR;
vb@24
   417
    }
vb@24
   418
vb@74
   419
    gpgme_error = gpg.gpgme_data_new(&plain);
vb@45
   420
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   421
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   422
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   423
        gpg.gpgme_data_release(cipher);
vb@24
   424
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   425
            return PEP_OUT_OF_MEMORY;
vb@24
   426
        else
vb@24
   427
            return PEP_UNKNOWN_ERROR;
vb@24
   428
    }
vb@24
   429
vb@74
   430
    dt = gpg.gpgme_data_identify(cipher);
vb@24
   431
    switch (dt) {
vb@24
   432
    case GPGME_DATA_TYPE_PGP_SIGNED:
vb@24
   433
    case GPGME_DATA_TYPE_PGP_OTHER:
vb@74
   434
        gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
vb@24
   435
            plain);
vb@45
   436
        gpgme_error = _GPGERR(gpgme_error);
vb@24
   437
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
   438
        assert(gpgme_error != GPG_ERR_NO_DATA);
vb@24
   439
vb@24
   440
        switch (gpgme_error) {
vb@344
   441
            case GPG_ERR_NO_ERROR:
vb@344
   442
            {
vb@344
   443
                gpgme_verify_result_t gpgme_verify_result;
vb@344
   444
                char *_buffer = NULL;
vb@344
   445
                size_t reading;
vb@344
   446
                size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
vb@344
   447
                gpgme_signature_t gpgme_signature;
vb@24
   448
vb@344
   449
                assert(length != -1);
vb@344
   450
                gpg.gpgme_data_seek(plain, 0, SEEK_SET);
vb@24
   451
vb@344
   452
                // TODO: make things less memory consuming
vb@344
   453
                // the following algorithm allocates memory for the complete
vb@344
   454
                // text
vb@24
   455
vb@344
   456
                _buffer = malloc(length + 1);
vb@344
   457
                assert(_buffer);
vb@344
   458
                if (_buffer == NULL) {
vb@74
   459
                    gpg.gpgme_data_release(plain);
vb@74
   460
                    gpg.gpgme_data_release(cipher);
vb@24
   461
                    return PEP_OUT_OF_MEMORY;
vb@24
   462
                }
vb@24
   463
vb@344
   464
                reading = gpg.gpgme_data_read(plain, _buffer, length);
vb@344
   465
                assert(length == reading);
vb@24
   466
vb@344
   467
                gpgme_verify_result =
vb@344
   468
                    gpg.gpgme_op_verify_result(session->ctx);
vb@344
   469
                assert(gpgme_verify_result);
vb@344
   470
                gpgme_signature = gpgme_verify_result->signatures;
vb@24
   471
vb@344
   472
                if (gpgme_signature) {
vb@344
   473
                    stringlist_t *k;
vb@344
   474
                    _keylist = new_stringlist(NULL);
vb@24
   475
                    assert(_keylist);
vb@24
   476
                    if (_keylist == NULL) {
vb@344
   477
                        gpg.gpgme_data_release(plain);
vb@344
   478
                        gpg.gpgme_data_release(cipher);
vb@344
   479
                        free(_buffer);
vb@344
   480
                        return PEP_OUT_OF_MEMORY;
vb@344
   481
                    }
vb@344
   482
                    k = _keylist;
vb@344
   483
vb@344
   484
                    result = PEP_DECRYPTED_AND_VERIFIED;
vb@344
   485
                    do {
vb@344
   486
                        switch (_GPGERR(gpgme_signature->status)) {
vb@344
   487
                        case GPG_ERR_NO_ERROR:
Edouard@505
   488
                        {
Edouard@674
   489
                            // Some versions of gpg returns signer's 
Edouard@674
   490
                            // signing subkey fingerprint instead of
Edouard@674
   491
                            // signer's primary key fingerprint.
Edouard@674
   492
                            // This is meant to get signer's primary 
Edouard@674
   493
                            // key fingerprint, using subkey's.
Edouard@674
   494
Edouard@728
   495
                            gpgme_key_t key = NULL;
Edouard@505
   496
Edouard@505
   497
                            gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@505
   498
                                gpgme_signature->fpr, &key, 0);
Edouard@505
   499
                            gpgme_error = _GPGERR(gpgme_error);
Edouard@505
   500
                            assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@505
   501
                            if (gpgme_error == GPG_ERR_ENOMEM) {
Edouard@505
   502
                                free_stringlist(_keylist);
Edouard@505
   503
                                gpg.gpgme_data_release(plain);
Edouard@505
   504
                                gpg.gpgme_data_release(cipher);
Edouard@505
   505
                                free(_buffer);
Edouard@505
   506
                                return PEP_OUT_OF_MEMORY;
Edouard@505
   507
                            }
Edouard@505
   508
                            // Primary key is given as the first subkey
Edouard@674
   509
                            if (gpgme_error == GPG_ERR_NO_ERROR &&  
Edouard@674
   510
                                key && key->subkeys && key->subkeys->fpr 
Edouard@674
   511
                                && key->subkeys->fpr[0])
Edouard@674
   512
                            {
Edouard@505
   513
                                k = stringlist_add(k, key->subkeys->fpr);
Edouard@677
   514
Edouard@674
   515
                                gpg.gpgme_key_unref(key);
Edouard@677
   516
Edouard@677
   517
                                if (k == NULL) {
Edouard@677
   518
                                    free_stringlist(_keylist);
Edouard@677
   519
                                    gpg.gpgme_data_release(plain);
Edouard@677
   520
                                    gpg.gpgme_data_release(cipher);
Edouard@677
   521
                                    free(_buffer);
Edouard@677
   522
                                    return PEP_OUT_OF_MEMORY;
Edouard@677
   523
                                }
Edouard@674
   524
                            }
Edouard@674
   525
                            else 
Edouard@674
   526
                            {
Edouard@505
   527
                                result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@505
   528
                                break;
Edouard@505
   529
                            }
vb@344
   530
                            break;
Edouard@505
   531
                        }
vb@344
   532
                        case GPG_ERR_CERT_REVOKED:
vb@344
   533
                        case GPG_ERR_BAD_SIGNATURE:
vb@344
   534
                            result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@344
   535
                            break;
vb@344
   536
                        case GPG_ERR_SIG_EXPIRED:
vb@344
   537
                        case GPG_ERR_KEY_EXPIRED:
vb@344
   538
                        case GPG_ERR_NO_PUBKEY:
vb@344
   539
                            k = stringlist_add(k, gpgme_signature->fpr);
Edouard@674
   540
                            if (k == NULL) {
Edouard@674
   541
                                free_stringlist(_keylist);
Edouard@674
   542
                                gpg.gpgme_data_release(plain);
Edouard@674
   543
                                gpg.gpgme_data_release(cipher);
Edouard@674
   544
                                free(_buffer);
Edouard@674
   545
                                return PEP_OUT_OF_MEMORY;
Edouard@674
   546
                            }
vb@344
   547
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@344
   548
                                result = PEP_DECRYPTED;
vb@344
   549
                            break;
vb@344
   550
                        case GPG_ERR_GENERAL:
vb@344
   551
                            break;
vb@344
   552
                        default:
vb@344
   553
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@344
   554
                                result = PEP_DECRYPTED;
vb@344
   555
                            break;
vb@344
   556
                        }
vb@344
   557
                    } while ((gpgme_signature = gpgme_signature->next));
vb@344
   558
                }
vb@344
   559
                else {
vb@344
   560
                    result = PEP_DECRYPTED;
vb@344
   561
                }
vb@344
   562
vb@344
   563
                if (result == PEP_DECRYPTED_AND_VERIFIED
vb@344
   564
                    || result == PEP_DECRYPTED) {
vb@344
   565
                    *ptext = _buffer;
vb@344
   566
                    *psize = reading;
vb@344
   567
                    (*ptext)[*psize] = 0; // safeguard for naive users
vb@344
   568
                    *keylist = _keylist;
vb@344
   569
                }
vb@344
   570
                else {
vb@344
   571
                    free_stringlist(_keylist);
vb@344
   572
                    free(_buffer);
vb@344
   573
                }
vb@344
   574
                break;
vb@344
   575
            }
vb@344
   576
            case GPG_ERR_BAD_PASSPHRASE:
Edouard@725
   577
                result = PEP_DECRYPT_NO_KEY;
Edouard@725
   578
                break;
vb@344
   579
            case GPG_ERR_DECRYPT_FAILED:
vb@344
   580
            default:
vb@344
   581
            {
vb@344
   582
                gpgme_decrypt_result_t gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
vb@344
   583
                result = PEP_DECRYPT_NO_KEY;
vb@344
   584
vb@344
   585
                if (gpgme_decrypt_result != NULL) {
vb@344
   586
                    if (gpgme_decrypt_result->unsupported_algorithm)
vb@344
   587
                        *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
vb@344
   588
                    else
vb@344
   589
                        *keylist = new_stringlist("");
vb@344
   590
                    assert(*keylist);
vb@344
   591
                    if (*keylist == NULL) {
vb@24
   592
                        result = PEP_OUT_OF_MEMORY;
vb@24
   593
                        break;
vb@24
   594
                    }
vb@344
   595
                    stringlist_t *_keylist = *keylist;
vb@344
   596
                    for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
vb@344
   597
                        _keylist = stringlist_add(_keylist, r->keyid);
vb@344
   598
                        assert(_keylist);
vb@344
   599
                        if (_keylist == NULL) {
vb@344
   600
                            free_stringlist(*keylist);
vb@344
   601
                            *keylist = NULL;
vb@344
   602
                            result = PEP_OUT_OF_MEMORY;
vb@344
   603
                            break;
vb@344
   604
                        }
vb@344
   605
                    }
vb@344
   606
                    if (result == PEP_OUT_OF_MEMORY)
vb@344
   607
                        break;
vb@24
   608
                }
vb@24
   609
            }
vb@24
   610
        }
vb@24
   611
        break;
vb@24
   612
vb@24
   613
    default:
vb@24
   614
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   615
    }
vb@24
   616
vb@74
   617
    gpg.gpgme_data_release(plain);
vb@74
   618
    gpg.gpgme_data_release(cipher);
vb@24
   619
    return result;
vb@24
   620
}
vb@24
   621
vb@24
   622
PEP_STATUS pgp_verify_text(
vb@24
   623
    PEP_SESSION session, const char *text, size_t size,
vb@24
   624
    const char *signature, size_t sig_size, stringlist_t **keylist
vb@24
   625
    )
vb@24
   626
{
vb@24
   627
    PEP_STATUS result;
vb@24
   628
    gpgme_error_t gpgme_error;
vb@24
   629
    gpgme_data_t d_text, d_sig;
vb@24
   630
    stringlist_t *_keylist;
vb@24
   631
vb@24
   632
    assert(session);
vb@24
   633
    assert(text);
vb@24
   634
    assert(size);
vb@24
   635
    assert(signature);
vb@24
   636
    assert(sig_size);
vb@24
   637
    assert(keylist);
vb@24
   638
vb@24
   639
    *keylist = NULL;
vb@24
   640
vb@74
   641
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
vb@45
   642
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   643
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   644
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   645
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   646
            return PEP_OUT_OF_MEMORY;
vb@24
   647
        else
vb@24
   648
            return PEP_UNKNOWN_ERROR;
vb@24
   649
    }
vb@24
   650
vb@74
   651
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
vb@45
   652
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   653
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   654
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   655
        gpg.gpgme_data_release(d_text);
vb@24
   656
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   657
            return PEP_OUT_OF_MEMORY;
vb@24
   658
        else
vb@24
   659
            return PEP_UNKNOWN_ERROR;
vb@24
   660
    }
vb@24
   661
vb@74
   662
    gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
vb@45
   663
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   664
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
   665
vb@24
   666
    switch (gpgme_error) {
vb@24
   667
    case GPG_ERR_NO_ERROR:
vb@24
   668
    {
vb@24
   669
        gpgme_verify_result_t gpgme_verify_result;
vb@24
   670
        gpgme_signature_t gpgme_signature;
vb@24
   671
vb@24
   672
        gpgme_verify_result =
vb@74
   673
            gpg.gpgme_op_verify_result(session->ctx);
vb@24
   674
        assert(gpgme_verify_result);
vb@24
   675
        gpgme_signature = gpgme_verify_result->signatures;
vb@24
   676
vb@24
   677
        if (gpgme_signature) {
vb@24
   678
            stringlist_t *k;
vb@24
   679
            _keylist = new_stringlist(NULL);
vb@24
   680
            assert(_keylist);
vb@24
   681
            if (_keylist == NULL) {
vb@74
   682
                gpg.gpgme_data_release(d_text);
vb@74
   683
                gpg.gpgme_data_release(d_sig);
vb@24
   684
                return PEP_OUT_OF_MEMORY;
vb@24
   685
            }
vb@24
   686
            k = _keylist;
vb@24
   687
vb@24
   688
            result = PEP_VERIFIED;
vb@24
   689
            do {
Edouard@502
   690
                gpgme_key_t key;
Edouard@502
   691
                memset(&key,0,sizeof(key));
Edouard@502
   692
Edouard@502
   693
                // GPGME may give subkey's fpr instead of primary key's fpr. 
Edouard@502
   694
                // Therefore we ask for the primary fingerprint instead
Edouard@502
   695
                // we assume that gpgme_get_key can find key by subkey's fpr
Edouard@502
   696
                gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@502
   697
                    gpgme_signature->fpr, &key, 0);
Edouard@502
   698
                gpgme_error = _GPGERR(gpgme_error);
Edouard@502
   699
                assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@502
   700
                if (gpgme_error == GPG_ERR_ENOMEM) {
vb@24
   701
                    free_stringlist(_keylist);
Edouard@505
   702
                    gpg.gpgme_data_release(d_text);
Edouard@505
   703
                    gpg.gpgme_data_release(d_sig);
vb@24
   704
                    return PEP_OUT_OF_MEMORY;
vb@24
   705
                }
Edouard@502
   706
                // Primary key is given as the first subkey
Edouard@674
   707
                if (gpgme_error == GPG_ERR_NO_ERROR &&  
Edouard@674
   708
                    key && key->subkeys && key->subkeys->fpr 
Edouard@674
   709
                    && key->subkeys->fpr[0])
Edouard@674
   710
                {
Edouard@504
   711
                    k = stringlist_add(k, key->subkeys->fpr);
Edouard@677
   712
Edouard@674
   713
                    gpg.gpgme_key_unref(key);
Edouard@677
   714
Edouard@677
   715
                    if (k == NULL) {
Edouard@677
   716
                        free_stringlist(_keylist);
Edouard@677
   717
                        gpg.gpgme_data_release(d_text);
Edouard@677
   718
                        gpg.gpgme_data_release(d_sig);
Edouard@677
   719
                        return PEP_OUT_OF_MEMORY;
Edouard@677
   720
                    }
Edouard@502
   721
                }
Edouard@502
   722
                else {
Edouard@502
   723
                    result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@502
   724
                    break;
Edouard@502
   725
                }
Edouard@502
   726
vb@24
   727
                if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
vb@24
   728
                    if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
vb@24
   729
                        || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
vb@24
   730
                        if (result == PEP_VERIFIED
vb@24
   731
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
   732
                            result = PEP_UNENCRYPTED;
vb@24
   733
                    }
vb@24
   734
                    else {
vb@24
   735
                        result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@24
   736
                        break;
vb@24
   737
                    }
vb@24
   738
                }
vb@24
   739
                else {
vb@24
   740
                    if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
vb@24
   741
                        if (result == PEP_VERIFIED)
vb@24
   742
                            result = PEP_VERIFIED_AND_TRUSTED;
vb@24
   743
                    }
vb@24
   744
                    if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
vb@24
   745
                        // good
vb@24
   746
                    }
vb@24
   747
                    else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
vb@24
   748
                        result = PEP_VERIFY_NO_KEY;
vb@24
   749
                    }
vb@24
   750
                    else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
vb@24
   751
                        if (result == PEP_VERIFIED
vb@24
   752
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
   753
                            result = PEP_UNENCRYPTED;
vb@24
   754
                    }
vb@24
   755
                    else {
vb@24
   756
                        // do nothing
vb@24
   757
                    }
vb@24
   758
                }
vb@24
   759
            } while ((gpgme_signature = gpgme_signature->next));
vb@24
   760
            *keylist = _keylist;
vb@24
   761
        }
vb@24
   762
        else {
vb@24
   763
            result = PEP_UNENCRYPTED;
vb@24
   764
        }
vb@24
   765
        break;
vb@24
   766
    }
vb@24
   767
        break;
vb@24
   768
    case GPG_ERR_NO_DATA:
vb@24
   769
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   770
        break;
vb@24
   771
    case GPG_ERR_INV_VALUE:
vb@24
   772
    default:
vb@24
   773
        result = PEP_UNKNOWN_ERROR;
vb@24
   774
        break;
vb@24
   775
    }
vb@24
   776
vb@74
   777
    gpg.gpgme_data_release(d_text);
vb@74
   778
    gpg.gpgme_data_release(d_sig);
vb@24
   779
vb@24
   780
    return result;
vb@24
   781
}
vb@24
   782
vb@24
   783
PEP_STATUS pgp_encrypt_and_sign(
vb@24
   784
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
vb@24
   785
    size_t psize, char **ctext, size_t *csize
vb@24
   786
    )
vb@24
   787
{
vb@24
   788
    PEP_STATUS result;
vb@24
   789
    gpgme_error_t gpgme_error;
vb@24
   790
    gpgme_data_t plain, cipher;
vb@24
   791
    gpgme_key_t *rcpt;
vb@24
   792
    gpgme_encrypt_flags_t flags;
vb@24
   793
    const stringlist_t *_keylist;
vb@24
   794
    int i, j;
vb@24
   795
vb@46
   796
    assert(session);
vb@24
   797
    assert(keylist);
vb@24
   798
    assert(ptext);
vb@24
   799
    assert(psize);
vb@24
   800
    assert(ctext);
vb@24
   801
    assert(csize);
vb@24
   802
vb@24
   803
    *ctext = NULL;
vb@24
   804
    *csize = 0;
vb@24
   805
vb@74
   806
    gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
vb@45
   807
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   808
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   809
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   810
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   811
            return PEP_OUT_OF_MEMORY;
vb@24
   812
        else
vb@24
   813
            return PEP_UNKNOWN_ERROR;
vb@24
   814
    }
vb@24
   815
vb@74
   816
    gpgme_error = gpg.gpgme_data_new(&cipher);
vb@45
   817
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   818
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   819
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   820
        gpg.gpgme_data_release(plain);
vb@24
   821
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   822
            return PEP_OUT_OF_MEMORY;
vb@24
   823
        else
vb@24
   824
            return PEP_UNKNOWN_ERROR;
vb@24
   825
    }
vb@24
   826
vb@109
   827
    rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
vb@24
   828
    assert(rcpt);
vb@24
   829
    if (rcpt == NULL) {
vb@74
   830
        gpg.gpgme_data_release(plain);
vb@74
   831
        gpg.gpgme_data_release(cipher);
vb@24
   832
        return PEP_OUT_OF_MEMORY;
vb@24
   833
    }
vb@24
   834
vb@74
   835
    gpg.gpgme_signers_clear(session->ctx);
vb@24
   836
vb@24
   837
    for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
vb@24
   838
        assert(_keylist->value);
vb@74
   839
        gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
vb@24
   840
            &rcpt[i], 0);
vb@45
   841
        gpgme_error = _GPGERR(gpgme_error);
vb@24
   842
        assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
   843
vb@24
   844
        switch (gpgme_error) {
vb@24
   845
        case GPG_ERR_ENOMEM:
vb@24
   846
            for (j = 0; j<i; j++)
vb@74
   847
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   848
            free(rcpt);
vb@74
   849
            gpg.gpgme_data_release(plain);
vb@74
   850
            gpg.gpgme_data_release(cipher);
vb@24
   851
            return PEP_OUT_OF_MEMORY;
vb@24
   852
        case GPG_ERR_NO_ERROR:
vb@24
   853
            if (i == 0) {
vb@74
   854
                gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
vb@45
   855
                _gpgme_error = _GPGERR(_gpgme_error);
vb@24
   856
                assert(_gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   857
            }
vb@24
   858
            break;
vb@24
   859
        case GPG_ERR_EOF:
vb@24
   860
            for (j = 0; j<i; j++)
vb@74
   861
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   862
            free(rcpt);
vb@74
   863
            gpg.gpgme_data_release(plain);
vb@74
   864
            gpg.gpgme_data_release(cipher);
vb@24
   865
            return PEP_KEY_NOT_FOUND;
vb@24
   866
        case GPG_ERR_AMBIGUOUS_NAME:
vb@24
   867
            for (j = 0; j<i; j++)
vb@74
   868
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   869
            free(rcpt);
vb@74
   870
            gpg.gpgme_data_release(plain);
vb@74
   871
            gpg.gpgme_data_release(cipher);
vb@24
   872
            return PEP_KEY_HAS_AMBIG_NAME;
vb@24
   873
        default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
vb@24
   874
            // FPR is not a fingerprint or key ID
vb@24
   875
            for (j = 0; j<i; j++)
vb@74
   876
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   877
            free(rcpt);
vb@74
   878
            gpg.gpgme_data_release(plain);
vb@74
   879
            gpg.gpgme_data_release(cipher);
vb@24
   880
            return PEP_GET_KEY_FAILED;
vb@24
   881
        }
vb@24
   882
    }
vb@24
   883
vb@24
   884
    // TODO: remove that and replace with proper key management
vb@24
   885
    flags = GPGME_ENCRYPT_ALWAYS_TRUST;
vb@24
   886
vb@74
   887
    gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
vb@24
   888
        plain, cipher);
vb@45
   889
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   890
    switch (gpgme_error) {
vb@24
   891
    case GPG_ERR_NO_ERROR:
vb@24
   892
    {
vb@24
   893
        char *_buffer = NULL;
vb@24
   894
        size_t reading;
vb@74
   895
        size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
vb@24
   896
        assert(length != -1);
vb@74
   897
        gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
vb@24
   898
vb@24
   899
        // TODO: make things less memory consuming
vb@24
   900
        // the following algorithm allocates a buffer for the complete text
vb@24
   901
vb@112
   902
        _buffer = malloc(length + 1);
vb@24
   903
        assert(_buffer);
vb@24
   904
        if (_buffer == NULL) {
vb@24
   905
            for (j = 0; j<stringlist_length(keylist); j++)
vb@74
   906
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   907
            free(rcpt);
vb@74
   908
            gpg.gpgme_data_release(plain);
vb@74
   909
            gpg.gpgme_data_release(cipher);
vb@24
   910
            return PEP_OUT_OF_MEMORY;
vb@24
   911
        }
vb@24
   912
vb@74
   913
        reading = gpg.gpgme_data_read(cipher, _buffer, length);
vb@24
   914
        assert(length == reading);
vb@24
   915
vb@24
   916
        *ctext = _buffer;
vb@24
   917
        *csize = reading;
vb@24
   918
        (*ctext)[*csize] = 0; // safeguard for naive users
vb@24
   919
        result = PEP_STATUS_OK;
vb@24
   920
        break;
vb@24
   921
    }
vb@24
   922
    default:
vb@24
   923
        result = PEP_UNKNOWN_ERROR;
vb@24
   924
    }
vb@24
   925
vb@24
   926
    for (j = 0; j<stringlist_length(keylist); j++)
vb@74
   927
        gpg.gpgme_key_unref(rcpt[j]);
vb@24
   928
    free(rcpt);
vb@74
   929
    gpg.gpgme_data_release(plain);
vb@74
   930
    gpg.gpgme_data_release(cipher);
vb@24
   931
    return result;
vb@24
   932
}
vb@24
   933
vb@24
   934
PEP_STATUS pgp_generate_keypair(
vb@24
   935
    PEP_SESSION session, pEp_identity *identity
vb@24
   936
    )
vb@24
   937
{
vb@24
   938
    gpgme_error_t gpgme_error;
vb@24
   939
    char *parms;
vb@24
   940
    const char *template =
vb@24
   941
        "<GnupgKeyParms format=\"internal\">\n"
vb@24
   942
        "Key-Type: RSA\n"
vb@24
   943
        "Key-Length: 4096\n"
vb@429
   944
        "Subkey-Type: RSA\n"
vb@429
   945
        "Subkey-Length: 4096\n"
vb@24
   946
        "Name-Real: %s\n"
vb@24
   947
        "Name-Email: %s\n"
vb@24
   948
        /* "Passphrase: %s\n" */
vb@24
   949
        "Expire-Date: 1y\n"
vb@24
   950
        "</GnupgKeyParms>\n";
vb@24
   951
    int result;
vb@24
   952
    gpgme_genkey_result_t gpgme_genkey_result;
vb@24
   953
vb@24
   954
    assert(session);
vb@24
   955
    assert(identity);
vb@24
   956
    assert(identity->address);
vb@298
   957
    assert(identity->fpr == NULL || identity->fpr[0] == 0);
vb@24
   958
    assert(identity->username);
vb@24
   959
vb@24
   960
    parms = calloc(1, PARMS_MAX);
vb@24
   961
    assert(parms);
vb@24
   962
    if (parms == NULL)
vb@24
   963
        return PEP_OUT_OF_MEMORY;
vb@24
   964
vb@24
   965
    result = snprintf(parms, PARMS_MAX, template, identity->username,
vb@46
   966
        identity->address); // , session->passphrase);
vb@24
   967
    assert(result < PARMS_MAX);
vb@24
   968
    if (result >= PARMS_MAX) {
vb@24
   969
        free(parms);
vb@24
   970
        return PEP_BUFFER_TOO_SMALL;
vb@24
   971
    }
vb@24
   972
vb@74
   973
    gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
vb@45
   974
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   975
    free(parms);
vb@24
   976
vb@24
   977
    switch (gpgme_error) {
vb@24
   978
    case GPG_ERR_NO_ERROR:
vb@24
   979
        break;
vb@24
   980
    case GPG_ERR_INV_VALUE:
vb@24
   981
        return PEP_ILLEGAL_VALUE;
vb@24
   982
    case GPG_ERR_GENERAL:
vb@24
   983
        return PEP_CANNOT_CREATE_KEY;
vb@24
   984
    default:
vb@24
   985
        assert(0);
vb@24
   986
        return PEP_UNKNOWN_ERROR;
vb@24
   987
    }
vb@24
   988
vb@74
   989
    gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
vb@24
   990
    assert(gpgme_genkey_result);
vb@24
   991
    assert(gpgme_genkey_result->fpr);
vb@24
   992
vb@298
   993
    free(identity->fpr);
vb@24
   994
    identity->fpr = strdup(gpgme_genkey_result->fpr);
vb@298
   995
    if (identity->fpr == NULL)
vb@298
   996
        return PEP_OUT_OF_MEMORY;
vb@24
   997
vb@24
   998
    return PEP_STATUS_OK;
vb@24
   999
}
vb@24
  1000
vb@24
  1001
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
vb@24
  1002
{
vb@24
  1003
    gpgme_error_t gpgme_error;
vb@24
  1004
    gpgme_key_t key;
vb@24
  1005
vb@24
  1006
    assert(session);
vb@24
  1007
    assert(fpr);
vb@24
  1008
vb@74
  1009
    gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
vb@45
  1010
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1011
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1012
    switch (gpgme_error) {
vb@24
  1013
    case GPG_ERR_NO_ERROR:
vb@24
  1014
        break;
vb@24
  1015
    case GPG_ERR_EOF:
vb@24
  1016
        return PEP_KEY_NOT_FOUND;
vb@24
  1017
    case GPG_ERR_INV_VALUE:
vb@24
  1018
        return PEP_ILLEGAL_VALUE;
vb@24
  1019
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1020
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1021
    case GPG_ERR_ENOMEM:
vb@24
  1022
        return PEP_OUT_OF_MEMORY;
vb@24
  1023
    default:
vb@24
  1024
        assert(0);
vb@24
  1025
        return PEP_UNKNOWN_ERROR;
vb@24
  1026
    }
vb@24
  1027
vb@74
  1028
    gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
vb@45
  1029
    gpgme_error = _GPGERR(gpgme_error);
vb@74
  1030
    gpg.gpgme_key_unref(key);
vb@24
  1031
    switch (gpgme_error) {
vb@24
  1032
    case GPG_ERR_NO_ERROR:
vb@24
  1033
        break;
vb@24
  1034
    case GPG_ERR_INV_VALUE:
vb@24
  1035
        assert(0);
vb@24
  1036
        return PEP_UNKNOWN_ERROR;
vb@24
  1037
    case GPG_ERR_NO_PUBKEY:
vb@24
  1038
        assert(0);
vb@24
  1039
        return PEP_KEY_NOT_FOUND;
vb@24
  1040
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1041
        assert(0);
vb@24
  1042
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1043
    default:
vb@24
  1044
        assert(0);
vb@24
  1045
        return PEP_UNKNOWN_ERROR;
vb@24
  1046
    }
vb@24
  1047
vb@24
  1048
    return PEP_STATUS_OK;
vb@24
  1049
}
vb@24
  1050
Edouard@728
  1051
PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
Edouard@728
  1052
                              size_t size, identity_list **private_idents)
vb@24
  1053
{
vb@24
  1054
    gpgme_error_t gpgme_error;
vb@24
  1055
    gpgme_data_t dh;
vb@24
  1056
vb@24
  1057
    assert(session);
vb@24
  1058
    assert(key_data);
Edouard@728
  1059
   
Edouard@728
  1060
    if(private_idents) 
Edouard@728
  1061
        *private_idents = NULL;
vb@24
  1062
vb@74
  1063
    gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
vb@45
  1064
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1065
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1066
    switch (gpgme_error) {
vb@24
  1067
    case GPG_ERR_NO_ERROR:
vb@24
  1068
        break;
vb@24
  1069
    case GPG_ERR_ENOMEM:
vb@24
  1070
        return PEP_OUT_OF_MEMORY;
vb@24
  1071
    case GPG_ERR_INV_VALUE:
vb@24
  1072
        assert(0);
vb@24
  1073
        return PEP_UNKNOWN_ERROR;
vb@24
  1074
    default:
vb@24
  1075
        assert(0);
vb@24
  1076
        return PEP_UNKNOWN_ERROR;
vb@24
  1077
    }
vb@24
  1078
Edouard@728
  1079
    gpgme_import_result_t gpgme_import_result;
Edouard@728
  1080
vb@74
  1081
    gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
vb@45
  1082
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1083
    switch (gpgme_error) {
vb@24
  1084
    case GPG_ERR_NO_ERROR:
Edouard@728
  1085
        if(private_idents) 
Edouard@728
  1086
        {
Edouard@728
  1087
            gpgme_import_result =
Edouard@728
  1088
                gpg.gpgme_op_import_result(session->ctx);
Edouard@728
  1089
            assert(gpgme_import_result);
vb@1302
  1090
            if (!gpgme_import_result) {
vb@1302
  1091
                gpg.gpgme_data_release(dh);
vb@1302
  1092
                return PEP_UNKNOWN_ERROR;
vb@1302
  1093
            }
vb@1302
  1094
Edouard@728
  1095
            gpgme_import_status_t import;
Edouard@728
  1096
            for (import = gpgme_import_result->imports; 
Edouard@728
  1097
                 import; 
Edouard@728
  1098
                 import = import->next)
Edouard@728
  1099
             {
Edouard@728
  1100
                if (import &&
Edouard@728
  1101
                    import->result == GPG_ERR_NO_ERROR &&
Edouard@728
  1102
                    import->status & GPGME_IMPORT_SECRET )
Edouard@728
  1103
                {
Edouard@728
  1104
                    gpgme_key_t key = NULL;
Edouard@728
  1105
Edouard@728
  1106
                    gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@728
  1107
                        import->fpr, &key, 0);
Edouard@728
  1108
                    gpgme_error = _GPGERR(gpgme_error);
Edouard@728
  1109
                    assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@728
  1110
                    if (gpgme_error == GPG_ERR_ENOMEM) {
Edouard@728
  1111
                        gpg.gpgme_data_release(dh);
Edouard@728
  1112
                        return PEP_OUT_OF_MEMORY;
Edouard@728
  1113
                    }
Edouard@728
  1114
                    
Edouard@728
  1115
                    if (gpgme_error == GPG_ERR_NO_ERROR &&  
Edouard@728
  1116
                        key && key->uids && 
Edouard@728
  1117
                        key->uids->email && key->uids->name)
Edouard@728
  1118
                    {
Edouard@728
  1119
                        pEp_identity *ident = new_identity(
Edouard@728
  1120
                             key->uids->email, import->fpr, NULL, key->uids->name);
Edouard@728
  1121
Edouard@728
  1122
                        gpg.gpgme_key_unref(key);
Edouard@728
  1123
Edouard@728
  1124
                        if (ident == NULL) {
Edouard@728
  1125
                            gpg.gpgme_data_release(dh);
Edouard@728
  1126
                            return PEP_OUT_OF_MEMORY;
Edouard@728
  1127
                        }
Edouard@728
  1128
Edouard@728
  1129
                        *private_idents = identity_list_add(*private_idents, ident);
Edouard@728
  1130
Edouard@728
  1131
                        if (*private_idents == NULL) {
Edouard@728
  1132
                            gpg.gpgme_data_release(dh);
Edouard@728
  1133
                            return PEP_OUT_OF_MEMORY;
Edouard@728
  1134
                        }
Edouard@728
  1135
                    }
Edouard@728
  1136
                    else 
Edouard@728
  1137
                    {
Edouard@728
  1138
                        gpg.gpgme_key_unref(key);
Edouard@728
  1139
                        gpg.gpgme_data_release(dh);
Edouard@728
  1140
                        return PEP_UNKNOWN_ERROR;
Edouard@728
  1141
                    }
Edouard@728
  1142
                }
Edouard@728
  1143
            }
Edouard@728
  1144
        }
vb@24
  1145
        break;
vb@24
  1146
    case GPG_ERR_INV_VALUE:
vb@24
  1147
        assert(0);
vb@74
  1148
        gpg.gpgme_data_release(dh);
vb@24
  1149
        return PEP_UNKNOWN_ERROR;
vb@24
  1150
    case GPG_ERR_NO_DATA:
vb@74
  1151
        gpg.gpgme_data_release(dh);
vb@24
  1152
        return PEP_ILLEGAL_VALUE;
vb@24
  1153
    default:
vb@24
  1154
        assert(0);
vb@74
  1155
        gpg.gpgme_data_release(dh);
vb@24
  1156
        return PEP_UNKNOWN_ERROR;
vb@24
  1157
    }
vb@24
  1158
vb@74
  1159
    gpg.gpgme_data_release(dh);
vb@24
  1160
    return PEP_STATUS_OK;
vb@24
  1161
}
vb@24
  1162
Edouard@170
  1163
PEP_STATUS pgp_export_keydata(
vb@1103
  1164
        PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
vb@1103
  1165
        bool secret
vb@24
  1166
    )
vb@24
  1167
{
vb@24
  1168
    gpgme_error_t gpgme_error;
vb@24
  1169
    gpgme_data_t dh;
vb@24
  1170
    size_t _size;
vb@24
  1171
    char *buffer;
vb@24
  1172
    int reading;
vb@24
  1173
vb@24
  1174
    assert(session);
vb@24
  1175
    assert(fpr);
vb@24
  1176
    assert(key_data);
vb@24
  1177
    assert(size);
vb@24
  1178
vb@74
  1179
    gpgme_error = gpg.gpgme_data_new(&dh);
vb@45
  1180
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1181
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1182
    switch (gpgme_error) {
vb@24
  1183
    case GPG_ERR_NO_ERROR:
vb@24
  1184
        break;
vb@24
  1185
    case GPG_ERR_ENOMEM:
vb@24
  1186
        return PEP_OUT_OF_MEMORY;
vb@24
  1187
    case GPG_ERR_INV_VALUE:
vb@24
  1188
        assert(0);
vb@24
  1189
        return PEP_UNKNOWN_ERROR;
vb@24
  1190
    default:
vb@24
  1191
        assert(0);
vb@24
  1192
        return PEP_UNKNOWN_ERROR;
vb@24
  1193
    }
vb@24
  1194
vb@1103
  1195
    if (secret)
vb@1103
  1196
        gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
edouard@1163
  1197
            GPGME_EXPORT_MODE_SECRET, dh);
vb@1103
  1198
    else
vb@1103
  1199
        gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
vb@1103
  1200
            GPGME_EXPORT_MODE_MINIMAL, dh);
vb@45
  1201
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1202
    switch (gpgme_error) {
vb@24
  1203
    case GPG_ERR_NO_ERROR:
vb@24
  1204
        break;
vb@24
  1205
    case GPG_ERR_EOF:
vb@74
  1206
        gpg.gpgme_data_release(dh);
vb@24
  1207
        return PEP_KEY_NOT_FOUND;
vb@24
  1208
    case GPG_ERR_INV_VALUE:
vb@24
  1209
        assert(0);
vb@74
  1210
        gpg.gpgme_data_release(dh);
vb@24
  1211
        return PEP_UNKNOWN_ERROR;
vb@24
  1212
    default:
vb@24
  1213
        assert(0);
vb@74
  1214
        gpg.gpgme_data_release(dh);
vb@24
  1215
        return PEP_UNKNOWN_ERROR;
vb@24
  1216
    };
vb@24
  1217
vb@74
  1218
    _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
vb@24
  1219
    assert(_size != -1);
vb@74
  1220
    gpg.gpgme_data_seek(dh, 0, SEEK_SET);
vb@24
  1221
vb@24
  1222
    buffer = malloc(_size + 1);
vb@24
  1223
    assert(buffer);
vb@24
  1224
    if (buffer == NULL) {
vb@74
  1225
        gpg.gpgme_data_release(dh);
vb@24
  1226
        return PEP_OUT_OF_MEMORY;
vb@24
  1227
    }
vb@24
  1228
vb@74
  1229
    reading = gpg.gpgme_data_read(dh, buffer, _size);
vb@24
  1230
    assert(_size == reading);
vb@24
  1231
vb@24
  1232
    // safeguard for the naive user
vb@24
  1233
    buffer[_size] = 0;
vb@24
  1234
vb@24
  1235
    *key_data = buffer;
vb@24
  1236
    *size = _size;
vb@24
  1237
vb@74
  1238
    gpg.gpgme_data_release(dh);
vb@24
  1239
    return PEP_STATUS_OK;
vb@24
  1240
}
vb@24
  1241
krista@1031
  1242
PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern, 
krista@1031
  1243
                            stringpair_list_t** keyinfo_list)
krista@1031
  1244
{    
krista@1005
  1245
    gpgme_error_t gpgme_error;
krista@1005
  1246
    assert(session);
krista@1031
  1247
    assert(keyinfo_list);
krista@1005
  1248
    
krista@1031
  1249
    if (!session || !keyinfo_list)
krista@1005
  1250
        return PEP_ILLEGAL_VALUE;
krista@1005
  1251
    
krista@1031
  1252
    *keyinfo_list = NULL;
krista@1005
  1253
    
krista@1031
  1254
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
krista@1005
  1255
    gpgme_error = _GPGERR(gpgme_error);
krista@1005
  1256
    
krista@1005
  1257
    switch(gpgme_error) {
krista@1005
  1258
        case GPG_ERR_NO_ERROR:
krista@1005
  1259
            break;
krista@1005
  1260
        case GPG_ERR_INV_VALUE:
krista@1005
  1261
            assert(0);
krista@1005
  1262
            return PEP_UNKNOWN_ERROR;
krista@1005
  1263
        default:
krista@1005
  1264
            gpg.gpgme_op_keylist_end(session->ctx);
krista@1005
  1265
            return PEP_GET_KEY_FAILED;        
krista@1005
  1266
    };
krista@1005
  1267
    
krista@1005
  1268
    gpgme_key_t key;
krista@1031
  1269
    stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
krista@1031
  1270
    stringpair_list_t* list_curr = _keyinfo_list;
krista@1031
  1271
    stringpair_t* pair = NULL;
krista@1019
  1272
        
krista@1187
  1273
    do { 
krista@1005
  1274
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
krista@1005
  1275
        gpgme_error = _GPGERR(gpgme_error);
krista@1005
  1276
      
krista@1005
  1277
        switch(gpgme_error) {
krista@1005
  1278
            case GPG_ERR_EOF:
krista@1005
  1279
                break;
krista@1005
  1280
            case GPG_ERR_NO_ERROR:
krista@1005
  1281
                assert(key);
krista@1005
  1282
                assert(key->subkeys);
krista@1005
  1283
                if (!key || !key->subkeys)
krista@1005
  1284
                    return PEP_GET_KEY_FAILED;
krista@1040
  1285
krista@1005
  1286
                // first subkey is primary key
krista@1005
  1287
                char* fpr = key->subkeys->fpr;
roker@1199
  1288
                char* uid = key->uids->uid;
krista@1187
  1289
krista@1005
  1290
                assert(fpr);
roker@1199
  1291
                assert(uid);
krista@1031
  1292
                if (!fpr)
krista@1005
  1293
                    return PEP_GET_KEY_FAILED;
krista@1005
  1294
                
krista@1050
  1295
                if (key->subkeys->revoked)
krista@1040
  1296
                    continue;
krista@1040
  1297
                
krista@1031
  1298
                pair = new_stringpair(fpr, uid);
krista@1019
  1299
krista@1031
  1300
                assert(pair);
krista@1005
  1301
                
krista@1031
  1302
                if (pair) {
krista@1031
  1303
                    list_curr = stringpair_list_add(list_curr, pair);
krista@1031
  1304
                    pair = NULL;
krista@1005
  1305
                    
krista@1005
  1306
                    assert(list_curr);
krista@1005
  1307
                    if (list_curr != NULL)
krista@1005
  1308
                        break;
krista@1005
  1309
                    else
krista@1031
  1310
                        free_stringpair(pair);
krista@1005
  1311
                }
krista@1031
  1312
                // else fallthrough (list_curr or pair wasn't allocateable)
krista@1005
  1313
            case GPG_ERR_ENOMEM:
krista@1031
  1314
                free_stringpair_list(_keyinfo_list);
krista@1005
  1315
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1005
  1316
                return PEP_OUT_OF_MEMORY;
krista@1005
  1317
            default:
krista@1005
  1318
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1005
  1319
                return PEP_UNKNOWN_ERROR;
krista@1005
  1320
        }
krista@1005
  1321
    } while (gpgme_error != GPG_ERR_EOF);
krista@1005
  1322
    
krista@1032
  1323
    if (_keyinfo_list->value == NULL) {
krista@1031
  1324
        free_stringpair_list(_keyinfo_list);
krista@1031
  1325
        _keyinfo_list = NULL;
krista@1005
  1326
    }
krista@1005
  1327
    
krista@1031
  1328
    *keyinfo_list = _keyinfo_list;
krista@1005
  1329
    
krista@1005
  1330
    return PEP_STATUS_OK;
krista@1005
  1331
}
krista@1005
  1332
vb@46
  1333
static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
vb@24
  1334
    gpgme_keylist_mode_t add_mode)
vb@24
  1335
{
vb@24
  1336
    gpgme_error_t gpgme_error;
vb@24
  1337
    gpgme_keylist_mode_t mode;
vb@24
  1338
vb@74
  1339
    mode = gpg.gpgme_get_keylist_mode(session->ctx);
vb@24
  1340
vb@24
  1341
    mode &= ~remove_mode;
vb@24
  1342
    mode |= add_mode;
vb@24
  1343
vb@74
  1344
    gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
vb@45
  1345
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1346
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1347
}
vb@24
  1348
vb@24
  1349
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
vb@24
  1350
{
vb@24
  1351
    gpgme_error_t gpgme_error;
vb@24
  1352
    gpgme_key_t key;
vb@24
  1353
vb@24
  1354
    assert(session);
vb@24
  1355
    assert(pattern);
vb@24
  1356
vb@46
  1357
    _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
vb@24
  1358
vb@74
  1359
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
vb@45
  1360
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1361
    switch (gpgme_error) {
vb@24
  1362
    case GPG_ERR_NO_ERROR:
vb@24
  1363
        break;
vb@24
  1364
    case GPG_ERR_INV_VALUE:
vb@24
  1365
        assert(0);
vb@47
  1366
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1367
        return PEP_UNKNOWN_ERROR;
vb@24
  1368
    default:
vb@47
  1369
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1370
        return PEP_GET_KEY_FAILED;
vb@24
  1371
    };
vb@24
  1372
vb@47
  1373
    gpgme_ctx_t import_ctx;
vb@74
  1374
    gpgme_error = gpg.gpgme_new(&import_ctx);
vb@47
  1375
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@47
  1376
vb@24
  1377
    do {
vb@74
  1378
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1379
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1380
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1381
        switch (gpgme_error) {
vb@24
  1382
        case GPG_ERR_EOF:
vb@24
  1383
            break;
vb@24
  1384
        case GPG_ERR_NO_ERROR:
vb@24
  1385
        {
vb@24
  1386
            gpgme_error_t gpgme_error;
vb@24
  1387
            gpgme_key_t keys[2];
vb@24
  1388
vb@24
  1389
            keys[0] = key;
vb@24
  1390
            keys[1] = NULL;
vb@24
  1391
vb@74
  1392
            gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
vb@45
  1393
            gpgme_error = _GPGERR(gpgme_error);
vb@74
  1394
            gpg.gpgme_key_unref(key);
vb@24
  1395
            assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1396
            assert(gpgme_error != GPG_ERR_CONFLICT);
vb@24
  1397
        }
vb@24
  1398
            break;
vb@24
  1399
        case GPG_ERR_ENOMEM:
vb@74
  1400
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1401
            gpg.gpgme_release(import_ctx);
vb@47
  1402
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1403
            return PEP_OUT_OF_MEMORY;
vb@24
  1404
        default:
vb@74
  1405
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1406
            gpg.gpgme_release(import_ctx);
vb@47
  1407
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@46
  1408
            return PEP_UNKNOWN_ERROR;
vb@24
  1409
        };
vb@24
  1410
    } while (gpgme_error != GPG_ERR_EOF);
vb@24
  1411
vb@74
  1412
    gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1413
    gpg.gpgme_release(import_ctx);
vb@47
  1414
    _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1415
    return PEP_STATUS_OK;
vb@24
  1416
}
vb@24
  1417
krista@1357
  1418
krista@1357
  1419
static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
krista@1357
  1420
                            stringlist_t** keylist,
krista@1357
  1421
                            int private_only) {
vb@24
  1422
    gpgme_error_t gpgme_error;
vb@24
  1423
    gpgme_key_t key;
krista@1357
  1424
    
vb@24
  1425
    assert(session);
vb@24
  1426
    assert(pattern);
vb@24
  1427
    assert(keylist);
krista@1357
  1428
    
vb@24
  1429
    *keylist = NULL;
krista@1357
  1430
    
krista@1357
  1431
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
vb@45
  1432
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1433
    switch (gpgme_error) {
krista@1357
  1434
        case GPG_ERR_NO_ERROR:
krista@1357
  1435
            break;
krista@1357
  1436
        case GPG_ERR_INV_VALUE:
krista@1357
  1437
            assert(0);
krista@1357
  1438
            return PEP_UNKNOWN_ERROR;
krista@1357
  1439
        default:
krista@1357
  1440
            gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  1441
            return PEP_GET_KEY_FAILED;
vb@24
  1442
    };
krista@1357
  1443
    
roker@877
  1444
    stringlist_t *_keylist = new_stringlist(NULL);
vb@24
  1445
    stringlist_t *_k = _keylist;
krista@1357
  1446
    
vb@24
  1447
    do {
vb@74
  1448
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1449
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1450
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1451
        switch (gpgme_error) {
krista@1357
  1452
            case GPG_ERR_EOF:
vb@24
  1453
                break;
krista@1357
  1454
            case GPG_ERR_NO_ERROR:
krista@1357
  1455
                assert(key);
krista@1357
  1456
                assert(key->subkeys);
krista@1357
  1457
                char *fpr = key->subkeys->fpr;
krista@1357
  1458
                assert(fpr);
krista@1357
  1459
                _k = stringlist_add(_k, fpr);
krista@1357
  1460
                assert(_k);
krista@1357
  1461
                if (_k != NULL)
krista@1357
  1462
                    break;
krista@1357
  1463
            case GPG_ERR_ENOMEM:
krista@1357
  1464
                free_stringlist(_keylist);
krista@1357
  1465
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  1466
                return PEP_OUT_OF_MEMORY;
krista@1357
  1467
            default:
krista@1357
  1468
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  1469
                return PEP_UNKNOWN_ERROR;
vb@24
  1470
        };
vb@24
  1471
    } while (gpgme_error != GPG_ERR_EOF);
krista@1357
  1472
    
vb@74
  1473
    gpg.gpgme_op_keylist_end(session->ctx);
vb@523
  1474
    if (_keylist->value == NULL) {
vb@523
  1475
        free_stringlist(_keylist);
vb@523
  1476
        _keylist = NULL;
vb@523
  1477
    }
vb@24
  1478
    *keylist = _keylist;
vb@24
  1479
    return PEP_STATUS_OK;
vb@24
  1480
}
vb@24
  1481
krista@1357
  1482
PEP_STATUS pgp_find_keys(
krista@1357
  1483
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
krista@1357
  1484
    )
krista@1357
  1485
{
krista@1357
  1486
    return _pgp_search_keys(session, pattern, keylist, 0);
krista@1357
  1487
}    
krista@1357
  1488
krista@1357
  1489
PEP_STATUS pgp_find_private_keys(
krista@1357
  1490
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
krista@1357
  1491
)
krista@1357
  1492
{
krista@1357
  1493
    return _pgp_search_keys(session, pattern, keylist, 1);
krista@1357
  1494
}
krista@1357
  1495
vb@24
  1496
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
vb@24
  1497
{
vb@24
  1498
    gpgme_error_t gpgme_error;
vb@24
  1499
vb@24
  1500
    assert(session);
vb@24
  1501
    assert(pattern);
vb@24
  1502
vb@74
  1503
    gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
vb@24
  1504
        GPGME_EXPORT_MODE_EXTERN, NULL);
vb@45
  1505
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1506
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1507
    if (gpgme_error == GPG_ERR_NO_ERROR)
vb@24
  1508
        return PEP_STATUS_OK;
vb@24
  1509
    else
vb@24
  1510
        return PEP_CANNOT_SEND_KEY;
vb@24
  1511
}
vb@24
  1512
vb@24
  1513
PEP_STATUS pgp_get_key_rating(
vb@24
  1514
    PEP_SESSION session,
vb@24
  1515
    const char *fpr,
vb@24
  1516
    PEP_comm_type *comm_type
vb@24
  1517
    )
vb@24
  1518
{
vb@24
  1519
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
  1520
    gpgme_error_t gpgme_error;
vb@24
  1521
    gpgme_key_t key;
vb@24
  1522
vb@24
  1523
    assert(session);
vb@24
  1524
    assert(fpr);
vb@24
  1525
    assert(comm_type);
vb@24
  1526
vb@24
  1527
    *comm_type = PEP_ct_unknown;
vb@24
  1528
vb@74
  1529
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
vb@45
  1530
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1531
    switch (gpgme_error) {
vb@24
  1532
    case GPG_ERR_NO_ERROR:
vb@24
  1533
        break;
vb@24
  1534
    case GPG_ERR_INV_VALUE:
vb@24
  1535
        assert(0);
vb@24
  1536
        return PEP_UNKNOWN_ERROR;
vb@24
  1537
    default:
vb@24
  1538
        return PEP_GET_KEY_FAILED;
vb@24
  1539
    };
vb@24
  1540
vb@74
  1541
    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1542
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1543
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1544
vb@24
  1545
    if (key == NULL) {
vb@74
  1546
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1547
        return PEP_KEY_NOT_FOUND;
vb@24
  1548
    }
vb@24
  1549
vb@24
  1550
    switch (key->protocol) {
vb@24
  1551
    case GPGME_PROTOCOL_OpenPGP:
vb@24
  1552
    case GPGME_PROTOCOL_DEFAULT:
vb@24
  1553
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
vb@24
  1554
        break;
vb@24
  1555
    case GPGME_PROTOCOL_CMS:
vb@24
  1556
        *comm_type = PEP_ct_CMS_unconfirmed;
vb@24
  1557
        break;
vb@24
  1558
    default:
vb@24
  1559
        *comm_type = PEP_ct_unknown;
vb@74
  1560
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1561
        return PEP_STATUS_OK;
vb@24
  1562
    }
vb@24
  1563
vb@24
  1564
    switch (gpgme_error) {
vb@24
  1565
    case GPG_ERR_EOF:
vb@24
  1566
        break;
vb@24
  1567
    case GPG_ERR_NO_ERROR:
vb@24
  1568
        assert(key);
vb@24
  1569
        assert(key->subkeys);
vb@24
  1570
        for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
vb@24
  1571
            if (sk->length < 1024)
vb@24
  1572
                *comm_type = PEP_ct_key_too_short;
vb@24
  1573
            else if (
vb@24
  1574
                (
vb@24
  1575
                (sk->pubkey_algo == GPGME_PK_RSA)
vb@24
  1576
                || (sk->pubkey_algo == GPGME_PK_RSA_E)
vb@24
  1577
                || (sk->pubkey_algo == GPGME_PK_RSA_S)
vb@24
  1578
                )
vb@24
  1579
                && sk->length == 1024
vb@24
  1580
                )
vb@122
  1581
                *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
vb@24
  1582
vb@24
  1583
            if (sk->invalid) {
vb@24
  1584
                *comm_type = PEP_ct_key_b0rken;
vb@24
  1585
                break;
vb@24
  1586
            }
vb@24
  1587
            if (sk->expired) {
vb@24
  1588
                *comm_type = PEP_ct_key_expired;
vb@24
  1589
                break;
vb@24
  1590
            }
vb@24
  1591
            if (sk->revoked) {
vb@24
  1592
                *comm_type = PEP_ct_key_revoked;
vb@24
  1593
                break;
vb@24
  1594
            }
vb@24
  1595
        }
vb@24
  1596
        break;
vb@24
  1597
    case GPG_ERR_ENOMEM:
vb@74
  1598
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1599
        *comm_type = PEP_ct_unknown;
vb@24
  1600
        return PEP_OUT_OF_MEMORY;
vb@24
  1601
    default:
vb@74
  1602
        gpg.gpgme_op_keylist_end(session->ctx);
vb@46
  1603
        return PEP_UNKNOWN_ERROR;
vb@24
  1604
    };
vb@24
  1605
vb@74
  1606
    gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1607
vb@24
  1608
    return status;
vb@24
  1609
}
vb@200
  1610
vb@200
  1611
static PEP_STATUS find_single_key(
vb@200
  1612
        PEP_SESSION session,
vb@200
  1613
        const char *fpr,
vb@200
  1614
        gpgme_key_t *key
vb@200
  1615
    )
vb@200
  1616
{
vb@200
  1617
    gpgme_error_t gpgme_error;
vb@200
  1618
vb@200
  1619
    *key = NULL;
vb@200
  1620
vb@200
  1621
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
vb@200
  1622
    gpgme_error = _GPGERR(gpgme_error);
vb@200
  1623
    switch (gpgme_error) {
vb@200
  1624
    case GPG_ERR_NO_ERROR:
vb@200
  1625
        break;
vb@200
  1626
    case GPG_ERR_INV_VALUE:
vb@200
  1627
        assert(0);
vb@200
  1628
        return PEP_UNKNOWN_ERROR;
vb@200
  1629
    default:
vb@200
  1630
        return PEP_GET_KEY_FAILED;
vb@200
  1631
    };
vb@200
  1632
vb@200
  1633
    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
vb@200
  1634
    gpgme_error = _GPGERR(gpgme_error);
vb@200
  1635
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@200
  1636
vb@200
  1637
    gpg.gpgme_op_keylist_end(session->ctx);
vb@200
  1638
vb@200
  1639
    return PEP_STATUS_OK;
vb@200
  1640
}
vb@200
  1641
vb@201
  1642
typedef struct _renew_state {
vb@211
  1643
    enum {
vb@200
  1644
        renew_command = 0,
vb@200
  1645
        renew_date,
vb@200
  1646
        renew_secret_key,
vb@200
  1647
        renew_command2,
vb@200
  1648
        renew_date2,
vb@200
  1649
        renew_quit,
vb@200
  1650
        renew_save,
vb@200
  1651
        renew_exit,
vb@200
  1652
        renew_error = -1
vb@200
  1653
    } state;
vb@201
  1654
    const char *date_ref;
vb@201
  1655
} renew_state;
vb@200
  1656
vb@201
  1657
static gpgme_error_t renew_fsm(
vb@200
  1658
        void *_handle,
vb@200
  1659
        gpgme_status_code_t statuscode,
vb@200
  1660
        const char *args,
vb@200
  1661
        int fd
vb@200
  1662
    )
vb@200
  1663
{
vb@201
  1664
    renew_state *handle = _handle;
vb@200
  1665
vb@200
  1666
    switch (handle->state) {
vb@200
  1667
        case renew_command:
vb@200
  1668
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1669
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  1670
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  1671
                    handle->state = renew_error;
vb@201
  1672
                    return GPG_ERR_GENERAL;
vb@201
  1673
                }
vb@223
  1674
                gpg.gpgme_io_write(fd, "expire\n", 7);
vb@200
  1675
                handle->state = renew_date;
vb@200
  1676
            }
vb@200
  1677
            break;
vb@200
  1678
vb@200
  1679
        case renew_date:
vb@200
  1680
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1681
                assert(strcmp(args, "keygen.valid") == 0);
vb@201
  1682
                if (strcmp(args, "keygen.valid")) {
vb@201
  1683
                    handle->state = renew_error;
vb@201
  1684
                    return GPG_ERR_GENERAL;
vb@201
  1685
                }
vb@223
  1686
                gpg.gpgme_io_write(fd, handle->date_ref, 11);
vb@200
  1687
                handle->state = renew_secret_key;
vb@200
  1688
            }
vb@200
  1689
            break;
vb@200
  1690
vb@200
  1691
        case renew_secret_key:
vb@200
  1692
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1693
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  1694
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  1695
                    handle->state = renew_error;
vb@201
  1696
                    return GPG_ERR_GENERAL;
vb@201
  1697
                }
vb@223
  1698
                gpg.gpgme_io_write(fd, "key 1\n", 6);
vb@200
  1699
                handle->state = renew_command2;
vb@200
  1700
            }
vb@200
  1701
            break;
vb@200
  1702
vb@200
  1703
        case renew_command2:
vb@200
  1704
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1705
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  1706
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  1707
                    handle->state = renew_error;
vb@201
  1708
                    return GPG_ERR_GENERAL;
vb@201
  1709
                }
vb@223
  1710
                gpg.gpgme_io_write(fd, "expire\n", 7);
vb@200
  1711
                handle->state = renew_date2;
vb@200
  1712
            }
vb@200
  1713
            break;
vb@200
  1714
vb@200
  1715
        case renew_date2:
vb@200
  1716
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1717
                assert(strcmp(args, "keygen.valid") == 0);
vb@201
  1718
                if (strcmp(args, "keygen.valid")) {
vb@201
  1719
                    handle->state = renew_error;
vb@201
  1720
                    return GPG_ERR_GENERAL;
vb@201
  1721
                }
vb@223
  1722
                gpg.gpgme_io_write(fd, handle->date_ref, 11);
vb@200
  1723
                handle->state = renew_quit;
vb@200
  1724
            }
vb@200
  1725
            break;
vb@200
  1726
vb@200
  1727
        case renew_quit:
vb@200
  1728
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1729
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  1730
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  1731
                    handle->state = renew_error;
vb@201
  1732
                    return GPG_ERR_GENERAL;
vb@201
  1733
                }
vb@223
  1734
                gpg.gpgme_io_write(fd, "quit\n", 5);
vb@200
  1735
                handle->state = renew_save;
vb@200
  1736
            }
vb@200
  1737
            break;
vb@200
  1738
vb@200
  1739
        case renew_save:
vb@200
  1740
            if (statuscode == GPGME_STATUS_GET_BOOL) {
vb@201
  1741
                assert(strcmp(args, "keyedit.save.okay") == 0);
vb@201
  1742
                if (strcmp(args, "keyedit.save.okay")) {
vb@201
  1743
                    handle->state = renew_error;
vb@201
  1744
                    return GPG_ERR_GENERAL;
vb@201
  1745
                }
vb@223
  1746
                gpg.gpgme_io_write(fd, "Y\n", 2);
vb@200
  1747
                handle->state = renew_exit;
vb@200
  1748
            }
vb@200
  1749
            break;
vb@200
  1750
vb@200
  1751
        case renew_exit:
vb@200
  1752
            break;
vb@200
  1753
vb@200
  1754
        case renew_error:
vb@200
  1755
            return GPG_ERR_GENERAL;
vb@200
  1756
    }
vb@200
  1757
vb@200
  1758
    return GPG_ERR_NO_ERROR;
vb@200
  1759
}
vb@200
  1760
vb@200
  1761
static ssize_t _nullwriter(
vb@200
  1762
        void *_handle,
vb@200
  1763
        const void *buffer,
vb@200
  1764
        size_t size
vb@200
  1765
    )
vb@200
  1766
{
vb@200
  1767
    return size;
vb@200
  1768
}
vb@200
  1769
vb@201
  1770
PEP_STATUS pgp_renew_key(
vb@201
  1771
        PEP_SESSION session,
vb@201
  1772
        const char *fpr,
vb@201
  1773
        const timestamp *ts
vb@201
  1774
    )
vb@200
  1775
{
vb@200
  1776
    PEP_STATUS status = PEP_STATUS_OK;
vb@200
  1777
    gpgme_error_t gpgme_error;
vb@200
  1778
    gpgme_key_t key;
vb@200
  1779
    gpgme_data_t output;
vb@201
  1780
    renew_state handle;
vb@203
  1781
    char date_text[12];
vb@200
  1782
vb@200
  1783
    assert(session);
vb@200
  1784
    assert(fpr);
vb@200
  1785
vb@201
  1786
    memset(&handle, 0, sizeof(renew_state));
vb@203
  1787
    snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
vb@201
  1788
            ts->tm_mon + 1, ts->tm_mday);
vb@201
  1789
    handle.date_ref = date_text;
vb@200
  1790
vb@200
  1791
    status = find_single_key(session, fpr, &key);
vb@200
  1792
    if (status != PEP_STATUS_OK)
vb@200
  1793
        return status;
vb@200
  1794
vb@200
  1795
    struct gpgme_data_cbs data_cbs;
vb@200
  1796
    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
vb@200
  1797
    data_cbs.write = _nullwriter;
vb@220
  1798
    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
vb@200
  1799
vb@220
  1800
    gpgme_error = gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
vb@200
  1801
            output);
vb@200
  1802
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@200
  1803
vb@200
  1804
    gpg.gpgme_data_release(output);
vb@200
  1805
    gpg.gpgme_key_unref(key);
vb@200
  1806
vb@200
  1807
    return PEP_STATUS_OK;
vb@200
  1808
}
vb@200
  1809
vb@211
  1810
typedef struct _revoke_state {
vb@211
  1811
    enum {
vb@211
  1812
        revoke_command = 0,
vb@211
  1813
        revoke_approve,
vb@211
  1814
        revoke_reason_code,
vb@211
  1815
        revoke_reason_text,
vb@211
  1816
        revoke_reason_ok,
vb@211
  1817
        revoke_quit,
vb@211
  1818
        revoke_save,
vb@211
  1819
        revoke_exit,
vb@211
  1820
        revoke_error = -1
vb@211
  1821
    } state;
vb@211
  1822
    const char *reason_ref;
vb@211
  1823
} revoke_state;
vb@211
  1824
roker@723
  1825
roker@723
  1826
/*** unused?
vb@211
  1827
static bool isemptystring(const char *str)
vb@211
  1828
{
vb@211
  1829
    if (str == NULL)
vb@211
  1830
        return true;
vb@211
  1831
vb@211
  1832
    for (; str; str++) {
vb@211
  1833
        if (*str != ' ' && *str != '\t' && *str != '\n')
vb@211
  1834
            return false;
vb@211
  1835
    }
vb@211
  1836
vb@211
  1837
    return true;
vb@211
  1838
}
roker@723
  1839
***/
roker@723
  1840
vb@211
  1841
vb@211
  1842
static gpgme_error_t revoke_fsm(
vb@211
  1843
        void *_handle,
vb@211
  1844
        gpgme_status_code_t statuscode,
vb@211
  1845
        const char *args,
vb@211
  1846
        int fd
vb@211
  1847
    )
vb@211
  1848
{
vb@211
  1849
    revoke_state *handle = _handle;
vb@211
  1850
vb@211
  1851
    switch (handle->state) {
vb@211
  1852
        case revoke_command:
vb@211
  1853
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@211
  1854
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@211
  1855
                if (strcmp(args, "keyedit.prompt")) {
vb@211
  1856
                    handle->state = revoke_error;
vb@211
  1857
                    return GPG_ERR_GENERAL;
vb@211
  1858
                }
vb@223
  1859
                gpg.gpgme_io_write(fd, "revkey\n", 7);
vb@211
  1860
                handle->state = revoke_approve;
vb@211
  1861
            }
vb@211
  1862
            break;
vb@211
  1863
vb@211
  1864
        case revoke_approve:
vb@211
  1865
            if (statuscode == GPGME_STATUS_GET_BOOL) {
vb@211
  1866
                assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
vb@211
  1867
                if (strcmp(args, "keyedit.revoke.subkey.okay")) {
vb@211
  1868
                    handle->state = revoke_error;
vb@211
  1869
                    return GPG_ERR_GENERAL;
vb@211
  1870
                }
vb@223
  1871
                gpg.gpgme_io_write(fd, "Y\n", 2);
vb@211
  1872
                handle->state = revoke_reason_code;
vb@211
  1873
            }
vb@211
  1874
            break;
vb@211
  1875
vb@211
  1876
        case revoke_reason_code:
vb@211
  1877
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@211
  1878
                assert(strcmp(args, "ask_revocation_reason.code") == 0);
vb@211
  1879
                if (strcmp(args, "ask_revocation_reason.code")) {
vb@211
  1880
                    handle->state = revoke_error;
vb@211
  1881
                    return GPG_ERR_GENERAL;
vb@211
  1882
                }
vb@223
  1883
                gpg.gpgme_io_write(fd, "1\n", 2);
vb@211
  1884
                handle->state = revoke_reason_text;
vb@211
  1885
            }
vb@211
  1886
            break;
vb@211
  1887
vb@211
  1888
        case revoke_reason_text:
vb@211
  1889
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@211
  1890
                assert(strcmp(args, "ask_revocation_reason.text") == 0);
vb@211
  1891
                if (strcmp(args, "ask_revocation_reason.text")) {
vb@211
  1892
                    handle->state = revoke_error;
vb@211
  1893
                    return GPG_ERR_GENERAL;
vb@211
  1894
                }
vb@213
  1895
                // BUG: issues when reason given
vb@213
  1896
                // Assertion failed: (gpg->cmd.code), function command_handler,
vb@213
  1897
                // file engine-gpg.c, line 662.
vb@213
  1898
                //
vb@213
  1899
                // if (isemptystring(handle->reason_ref)) {
vb@223
  1900
                    gpg.gpgme_io_write(fd, "\n", 1);
vb@213
  1901
                // }
vb@213
  1902
                // else {
vb@213
  1903
                //     size_t len = strlen(handle->reason_ref);
vb@223
  1904
                //     gpg.gpgme_io_write(fd, handle->reason_ref, len);
vb@213
  1905
                //     if (handle->reason_ref[len - 1] == '\n')
vb@223
  1906
                //         gpg.gpgme_io_write(fd, "\n", 1);
vb@213
  1907
                //     else
vb@223
  1908
                //         gpg.gpgme_io_write(fd, "\n\n", 2);
vb@213
  1909
                // }
vb@211
  1910
                handle->state = revoke_reason_ok;
vb@211
  1911
            }
vb@211
  1912
            break;
vb@211
  1913
vb@211
  1914
        case revoke_reason_ok:
vb@211
  1915
            if (statuscode == GPGME_STATUS_GET_BOOL) {
vb@211
  1916
                assert(strcmp(args, "ask_revocation_reason.okay") == 0);
vb@211
  1917
                if (strcmp(args, "ask_revocation_reason.okay")) {
vb@211
  1918
                    handle->state = revoke_error;
vb@211
  1919
                    return GPG_ERR_GENERAL;
vb@211
  1920
                }
vb@223
  1921
                gpg.gpgme_io_write(fd, "Y\n", 2);
vb@211
  1922
                handle->state = revoke_quit;
vb@211
  1923
            }
vb@211
  1924
            break;
vb@211
  1925
vb@211
  1926
        case revoke_quit:
vb@211
  1927
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@211
  1928
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@211
  1929
                if (strcmp(args, "keyedit.prompt")) {
vb@211
  1930
                    handle->state = revoke_error;
vb@211
  1931
                    return GPG_ERR_GENERAL;
vb@211
  1932
                }
vb@223
  1933
                gpg.gpgme_io_write(fd, "quit\n", 5);
vb@211
  1934
                handle->state = revoke_save;
vb@211
  1935
            }
vb@211
  1936
            break;
vb@211
  1937
vb@211
  1938
        case revoke_save:
vb@211
  1939
            if (statuscode == GPGME_STATUS_GET_BOOL) {
vb@211
  1940
                assert(strcmp(args, "keyedit.save.okay") == 0);
vb@211
  1941
                if (strcmp(args, "keyedit.save.okay")) {
vb@211
  1942
                    handle->state = revoke_error;
vb@211
  1943
                    return GPG_ERR_GENERAL;
vb@211
  1944
                }
vb@223
  1945
                gpg.gpgme_io_write(fd, "Y\n", 2);
vb@211
  1946
                handle->state = revoke_exit;
vb@211
  1947
            }
vb@211
  1948
            break;
vb@211
  1949
vb@211
  1950
        case revoke_exit:
vb@211
  1951
            break;
vb@211
  1952
vb@211
  1953
        case revoke_error:
vb@211
  1954
            return GPG_ERR_GENERAL;
vb@211
  1955
    }
vb@211
  1956
vb@211
  1957
    return GPG_ERR_NO_ERROR;
vb@211
  1958
}
vb@211
  1959
vb@211
  1960
PEP_STATUS pgp_revoke_key(
vb@211
  1961
        PEP_SESSION session,
vb@211
  1962
        const char *fpr,
vb@211
  1963
        const char *reason
vb@211
  1964
    )
vb@200
  1965
{
vb@200
  1966
    PEP_STATUS status = PEP_STATUS_OK;
vb@211
  1967
    gpgme_error_t gpgme_error;
vb@200
  1968
    gpgme_key_t key;
vb@211
  1969
    gpgme_data_t output;
vb@211
  1970
    revoke_state handle;
vb@211
  1971
vb@200
  1972
    assert(session);
vb@200
  1973
    assert(fpr);
vb@200
  1974
vb@211
  1975
    memset(&handle, 0, sizeof(revoke_state));
vb@213
  1976
    handle.reason_ref = reason;
vb@211
  1977
vb@200
  1978
    status = find_single_key(session, fpr, &key);
vb@200
  1979
    if (status != PEP_STATUS_OK)
vb@200
  1980
        return status;
vb@200
  1981
vb@211
  1982
    struct gpgme_data_cbs data_cbs;
vb@211
  1983
    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
vb@211
  1984
    data_cbs.write = _nullwriter;
vb@220
  1985
    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
vb@211
  1986
vb@220
  1987
    gpgme_error = gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
vb@211
  1988
            output);
vb@211
  1989
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@211
  1990
vb@211
  1991
    gpg.gpgme_data_release(output);
vb@211
  1992
    gpg.gpgme_key_unref(key);
vb@211
  1993
vb@200
  1994
    return PEP_STATUS_OK;
vb@200
  1995
}
vb@200
  1996
vb@214
  1997
PEP_STATUS pgp_key_expired(
vb@214
  1998
        PEP_SESSION session,
vb@214
  1999
        const char *fpr,
Edouard@701
  2000
        const time_t when,
vb@214
  2001
        bool *expired
vb@214
  2002
    )
vb@214
  2003
{
vb@214
  2004
    PEP_STATUS status = PEP_STATUS_OK;
vb@214
  2005
    gpgme_key_t key;
vb@214
  2006
vb@214
  2007
    assert(session);
vb@214
  2008
    assert(fpr);
vb@214
  2009
    assert(expired);
vb@214
  2010
vb@214
  2011
    *expired = false;
vb@214
  2012
vb@214
  2013
    status = find_single_key(session, fpr, &key);
vb@214
  2014
    if (status != PEP_STATUS_OK)
vb@214
  2015
        return status;
vb@214
  2016
Edouard@701
  2017
    if ((key && key->expired) ||
Edouard@701
  2018
        (key && key->subkeys && key->subkeys->expired))
Edouard@620
  2019
    {
Edouard@701
  2020
        // Already marked expired
Edouard@701
  2021
        *expired = 1;
Edouard@701
  2022
    }
Edouard@701
  2023
    else if (key)
Edouard@701
  2024
    {
Edouard@701
  2025
        // Detect if will be expired
Edouard@701
  2026
        // i.e. Check that keys capabilities will
Edouard@701
  2027
        // not be expired at given time.
Edouard@701
  2028
        gpgme_subkey_t _sk;
Edouard@701
  2029
        bool crt_available = false;
Edouard@701
  2030
        bool sgn_available = false;
Edouard@701
  2031
        bool enc_available = false;
Edouard@701
  2032
        for (_sk = key->subkeys; _sk; _sk = _sk->next) {
krista@1326
  2033
            if (_sk->expires > when || _sk->expires == 0) // not expired at that date ?
krista@1326
  2034
                                                          // Also, zero means "does not expire"
Edouard@701
  2035
            {
Edouard@701
  2036
                if (_sk->can_certify) crt_available = true;
Edouard@701
  2037
                if (_sk->can_sign) sgn_available = true;
Edouard@701
  2038
                if (_sk->can_encrypt) enc_available = true;
Edouard@701
  2039
                // Authenticate is not used here.
Edouard@701
  2040
            }
Edouard@701
  2041
        }
Edouard@701
  2042
        if(!(crt_available && sgn_available && enc_available))
Edouard@701
  2043
        {
Edouard@701
  2044
            *expired = 1;
Edouard@701
  2045
        }
Edouard@620
  2046
    }
Edouard@620
  2047
    else
Edouard@620
  2048
    {
Edouard@620
  2049
        status = PEP_KEY_NOT_FOUND;
Edouard@620
  2050
    }
Edouard@620
  2051
vb@214
  2052
    gpg.gpgme_key_unref(key);
Edouard@620
  2053
    return status;
vb@214
  2054
}
vb@214
  2055
Edouard@662
  2056
PEP_STATUS pgp_key_revoked(
Edouard@662
  2057
        PEP_SESSION session,
Edouard@662
  2058
        const char *fpr,
Edouard@662
  2059
        bool *revoked
Edouard@662
  2060
    )
Edouard@662
  2061
{
Edouard@662
  2062
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@662
  2063
    gpgme_key_t key;
Edouard@662
  2064
Edouard@662
  2065
    assert(session);
Edouard@662
  2066
    assert(fpr);
Edouard@662
  2067
    assert(revoked);
Edouard@662
  2068
Edouard@664
  2069
    *revoked = false;
Edouard@662
  2070
Edouard@662
  2071
    status = find_single_key(session, fpr, &key);
Edouard@662
  2072
    if (status != PEP_STATUS_OK)
Edouard@662
  2073
        return status;
Edouard@662
  2074
Edouard@662
  2075
    if (key && key->subkeys)
Edouard@662
  2076
    {
Edouard@664
  2077
        *revoked = key->subkeys->revoked;
Edouard@662
  2078
    }
Edouard@662
  2079
    else
Edouard@662
  2080
    {
Edouard@662
  2081
        status = PEP_KEY_NOT_FOUND;
Edouard@662
  2082
    }
Edouard@662
  2083
Edouard@662
  2084
    gpg.gpgme_key_unref(key);
Edouard@662
  2085
    return status;
Edouard@662
  2086
}
Edouard@662
  2087
vb@958
  2088
PEP_STATUS pgp_key_created(
vb@958
  2089
        PEP_SESSION session,
vb@958
  2090
        const char *fpr,
vb@958
  2091
        time_t *created
vb@958
  2092
    )
vb@958
  2093
{
vb@958
  2094
    PEP_STATUS status = PEP_STATUS_OK;
vb@958
  2095
    gpgme_key_t key;
vb@958
  2096
vb@958
  2097
    assert(session);
vb@958
  2098
    assert(fpr);
vb@958
  2099
    assert(created);
vb@958
  2100
vb@959
  2101
    *created = 0;
vb@959
  2102
vb@958
  2103
    status = find_single_key(session, fpr, &key);
vb@958
  2104
    if (status != PEP_STATUS_OK)
vb@958
  2105
        return status;
vb@958
  2106
vb@958
  2107
    if (key && key->subkeys)
vb@958
  2108
    {
vb@958
  2109
        *created = (time_t) key->subkeys->timestamp;
vb@958
  2110
    }
vb@958
  2111
    else
vb@958
  2112
    {
vb@958
  2113
        status = PEP_KEY_NOT_FOUND;
vb@958
  2114
    }
vb@958
  2115
vb@958
  2116
    gpg.gpgme_key_unref(key);
vb@958
  2117
    return status;
vb@958
  2118
}
vb@958
  2119
vb@507
  2120
PEP_STATUS pgp_binary(const char **path)
vb@507
  2121
{
vb@507
  2122
    assert(path);
vb@507
  2123
    if (path == NULL)
vb@507
  2124
        return PEP_ILLEGAL_VALUE;
vb@507
  2125
vb@507
  2126
    *path = NULL;
vb@507
  2127
vb@507
  2128
    gpgme_engine_info_t info;
vb@507
  2129
    int err = gpg.gpgme_get_engine_info(&info);
vb@507
  2130
    assert(err == GPG_ERR_NO_ERROR);
vb@507
  2131
    if (err != GPG_ERR_NO_ERROR)
vb@507
  2132
        return PEP_OUT_OF_MEMORY;
vb@507
  2133
vb@507
  2134
    *path = info->file_name;
vb@507
  2135
vb@507
  2136
    return PEP_STATUS_OK;
vb@507
  2137
}
vb@507
  2138
krista@1357
  2139
PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
krista@1352
  2140
        bool *has_private) {
krista@1357
  2141
    PEP_STATUS status = PEP_STATUS_OK;
krista@1357
  2142
    gpgme_key_t output_key;
krista@1357
  2143
    gpgme_error_t gpgerr = gpg.gpgme_get_key(session->ctx, fpr, &output_key, true);
krista@1352
  2144
    *has_private = false;
krista@1352
  2145
    switch (gpgerr) {
krista@1352
  2146
        case GPG_ERR_EOF:
krista@1352
  2147
        case GPG_ERR_INV_VALUE:
krista@1352
  2148
            status = PEP_KEY_NOT_FOUND;
krista@1352
  2149
            break;
krista@1352
  2150
        case GPG_ERR_AMBIGUOUS_NAME:
krista@1352
  2151
            status = PEP_KEY_HAS_AMBIG_NAME;
krista@1352
  2152
            break;
krista@1352
  2153
        case GPG_ERR_NO_ERROR:
krista@1352
  2154
            *has_private = true;
vb@1387
  2155
            gpg.gpgme_key_release(output_key);
krista@1352
  2156
            break;
krista@1352
  2157
        case GPG_ERR_ENOMEM:
krista@1352
  2158
            status = PEP_OUT_OF_MEMORY;
krista@1352
  2159
            break;
krista@1352
  2160
        default:
krista@1352
  2161
            status = PEP_UNKNOWN_ERROR;
krista@1352
  2162
            break;
krista@1352
  2163
    }
krista@1352
  2164
    return status;
edouard@1385
  2165
}
edouard@1385
  2166