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