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