src/pgp_gpg.c
author Volker Birk <vb@pep-project.org>
Wed, 22 Apr 2015 12:38:51 +0200
changeset 220 9234c753e2cf
parent 219 3b698a1336a0
child 221 498615df9416
permissions -rw-r--r--
adding missing functions in GPGME
vb@219
     1
#include "platform.h"
vb@130
     2
#include "pEp_internal.h"
vb@24
     3
#include "pgp_gpg.h"
vb@24
     4
vb@78
     5
#include <limits.h>
vb@78
     6
vb@62
     7
#include "wrappers.h"
vb@62
     8
vb@45
     9
#define _GPGERR(X) ((X) & 0xffffL)
vb@45
    10
vb@76
    11
static void *gpgme;
vb@76
    12
static struct gpg_s gpg;
vb@74
    13
vb@78
    14
static bool ensure_config_values(stringlist_t *keys, stringlist_t *values)
vb@24
    15
{
vb@24
    16
    static char buf[MAX_LINELENGTH];
vb@78
    17
    int r;
vb@62
    18
    FILE *f;
vb@78
    19
    stringlist_t *_k;
vb@78
    20
    stringlist_t *_v;
vb@79
    21
    unsigned int i;
vb@78
    22
    unsigned int found = 0;
vb@62
    23
vb@62
    24
    f = Fopen(gpg_conf(), "r");
vb@63
    25
    assert(f);
vb@63
    26
    if (f == NULL && errno == ENOMEM)
vb@62
    27
        return false;
vb@24
    28
vb@24
    29
    if (f != NULL) {
vb@78
    30
        int length = stringlist_length(keys);
vb@79
    31
        unsigned int n = (1 << length) - 1;
vb@78
    32
vb@78
    33
        assert(length <= sizeof(unsigned int) * CHAR_BIT);
vb@78
    34
        assert(length == stringlist_length(values));
vb@78
    35
vb@62
    36
        do {
vb@62
    37
            char * s;
vb@62
    38
vb@63
    39
            s = Fgets(buf, MAX_LINELENGTH, f);
vb@78
    40
            if (!feof(f)) {
vb@78
    41
                assert(s);
vb@78
    42
                if (s == NULL)
vb@78
    43
                    return false;
vb@62
    44
vb@78
    45
                if (s && !feof(f)) {
vb@80
    46
                    char * rest;
vb@80
    47
                    char * t = strtok_r(s, " ", &rest);
vb@78
    48
                    for (i = 1, _k = keys, _v = values; _k != NULL;
vb@78
    49
                            _k = _k->next, _v = _v->next, i <<= 1) {
vb@80
    50
                        if (t && strncmp(t, _k->value, strlen(_k->value)) == 0)
vb@78
    51
                            found |= i;
vb@78
    52
vb@78
    53
                        if (i == n) {
vb@78
    54
                            r = Fclose(f);
vb@78
    55
                            return true;
vb@78
    56
                        }
vb@78
    57
                    }
vb@24
    58
                }
vb@24
    59
            }
vb@62
    60
        } while (!feof(f));
vb@63
    61
        f = Freopen(gpg_conf(), "a", f);
vb@24
    62
    }
vb@24
    63
    else {
vb@63
    64
        f = Fopen(gpg_conf(), "w");
vb@24
    65
    }
vb@24
    66
vb@24
    67
    assert(f);
vb@24
    68
    if (f == NULL)
vb@24
    69
        return false;
vb@24
    70
vb@78
    71
    for (i = 1, _k = keys, _v = values; _k != NULL; _k = _k->next,
vb@78
    72
            _v = _v->next, i <<= 1) {
vb@78
    73
        if ((found & i) == 0) {
vb@79
    74
            r = Fprintf(f, "%s %s\n", _k->value, _v->value);
vb@79
    75
            assert(r >= 0);
vb@78
    76
        }
vb@78
    77
    }
vb@62
    78
vb@63
    79
    r = Fclose(f);
vb@62
    80
    assert(r == 0);
vb@24
    81
vb@24
    82
    return true;
vb@24
    83
}
vb@24
    84
vb@62
    85
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
vb@24
    86
{
vb@66
    87
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
    88
    gpgme_error_t gpgme_error;
vb@62
    89
    bool bResult;
vb@62
    90
    
vb@62
    91
    if (in_first) {
vb@78
    92
        stringlist_t *conf_keys   = new_stringlist("keyserver");
vb@78
    93
        stringlist_t *conf_values = new_stringlist("hkp://keys.gnupg.net");
vb@79
    94
vb@78
    95
        stringlist_add(conf_keys, "cert-digest-algo");
vb@78
    96
        stringlist_add(conf_values, "SHA256");
vb@78
    97
vb@80
    98
        stringlist_add(conf_keys, "no-emit-version");
vb@80
    99
        stringlist_add(conf_values, "");
vb@80
   100
vb@80
   101
        stringlist_add(conf_keys, "no-comments");
vb@80
   102
        stringlist_add(conf_values, "");
vb@80
   103
vb@80
   104
        stringlist_add(conf_keys, "personal-cipher-preferences");
vb@80
   105
        stringlist_add(conf_values, "AES AES256 AES192 CAST5");
vb@80
   106
vb@80
   107
        stringlist_add(conf_keys, "personal-digest-preferences");
vb@80
   108
        stringlist_add(conf_values, "SHA512 SHA384 SHA256 SHA224");
vb@80
   109
        
vb@78
   110
        bResult = ensure_config_values(conf_keys, conf_values);
vb@24
   111
vb@78
   112
        free_stringlist(conf_keys);
vb@78
   113
        free_stringlist(conf_values);
vb@78
   114
Edouard@175
   115
        assert(bResult);
Edouard@175
   116
        if(!bResult){
Edouard@175
   117
            status = PEP_INIT_NO_GPG_HOME;
Edouard@175
   118
            goto pep_error;
Edouard@175
   119
        }
Edouard@175
   120
Edouard@175
   121
vb@62
   122
        gpgme = dlopen(LIBGPGME, RTLD_LAZY);
vb@62
   123
        if (gpgme == NULL) {
vb@66
   124
            status = PEP_INIT_CANNOT_LOAD_GPGME;
vb@66
   125
            goto pep_error;
vb@62
   126
        }
vb@62
   127
vb@62
   128
        memset(&gpg, 0, sizeof(struct gpg_s));
vb@62
   129
vb@62
   130
        gpg.gpgme_set_locale
vb@62
   131
            = (gpgme_set_locale_t) (intptr_t) dlsym(gpgme,
vb@62
   132
            "gpgme_set_locale");
vb@62
   133
        assert(gpg.gpgme_set_locale);
vb@62
   134
vb@62
   135
        gpg.gpgme_check
vb@62
   136
            = (gpgme_check_version_t) (intptr_t) dlsym(gpgme,
vb@62
   137
            "gpgme_check_version");
vb@62
   138
        assert(gpg.gpgme_check);
vb@62
   139
vb@62
   140
        gpg.gpgme_new
vb@62
   141
            = (gpgme_new_t) (intptr_t) dlsym(gpgme, "gpgme_new");
vb@62
   142
        assert(gpg.gpgme_new);
vb@62
   143
vb@62
   144
        gpg.gpgme_release
vb@62
   145
            = (gpgme_release_t) (intptr_t) dlsym(gpgme, "gpgme_release");
vb@62
   146
        assert(gpg.gpgme_release);
vb@62
   147
vb@62
   148
        gpg.gpgme_set_protocol
vb@62
   149
            = (gpgme_set_protocol_t) (intptr_t) dlsym(gpgme,
vb@62
   150
            "gpgme_set_protocol");
vb@62
   151
        assert(gpg.gpgme_set_protocol);
vb@62
   152
vb@62
   153
        gpg.gpgme_set_armor
vb@62
   154
            = (gpgme_set_armor_t) (intptr_t) dlsym(gpgme,
vb@62
   155
            "gpgme_set_armor");
vb@62
   156
        assert(gpg.gpgme_set_armor);
vb@62
   157
vb@62
   158
        gpg.gpgme_data_new
vb@62
   159
            = (gpgme_data_new_t) (intptr_t) dlsym(gpgme,
vb@62
   160
            "gpgme_data_new");
vb@62
   161
        assert(gpg.gpgme_data_new);
vb@62
   162
vb@62
   163
        gpg.gpgme_data_new_from_mem
vb@62
   164
            = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(gpgme,
vb@62
   165
            "gpgme_data_new_from_mem");
vb@62
   166
        assert(gpg.gpgme_data_new_from_mem);
vb@62
   167
vb@62
   168
        gpg.gpgme_data_release
vb@62
   169
            = (gpgme_data_release_t) (intptr_t) dlsym(gpgme,
vb@62
   170
            "gpgme_data_release");
vb@62
   171
        assert(gpg.gpgme_data_release);
vb@62
   172
vb@62
   173
        gpg.gpgme_data_identify
vb@62
   174
            = (gpgme_data_identify_t) (intptr_t) dlsym(gpgme,
vb@62
   175
            "gpgme_data_identify");
vb@62
   176
        assert(gpg.gpgme_data_identify);
vb@62
   177
vb@62
   178
        gpg.gpgme_data_seek
vb@62
   179
            = (gpgme_data_seek_t) (intptr_t) dlsym(gpgme,
vb@62
   180
            "gpgme_data_seek");
vb@62
   181
        assert(gpg.gpgme_data_seek);
vb@62
   182
vb@62
   183
        gpg.gpgme_data_read
vb@62
   184
            = (gpgme_data_read_t) (intptr_t) dlsym(gpgme,
vb@62
   185
            "gpgme_data_read");
vb@62
   186
        assert(gpg.gpgme_data_read);
vb@62
   187
vb@62
   188
        gpg.gpgme_op_decrypt
vb@62
   189
            = (gpgme_op_decrypt_t) (intptr_t) dlsym(gpgme,
vb@62
   190
            "gpgme_op_decrypt");
vb@62
   191
        assert(gpg.gpgme_op_decrypt);
vb@62
   192
vb@62
   193
        gpg.gpgme_op_verify
vb@62
   194
            = (gpgme_op_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   195
            "gpgme_op_verify");
vb@62
   196
        assert(gpg.gpgme_op_verify);
vb@62
   197
vb@62
   198
        gpg.gpgme_op_decrypt_verify
vb@62
   199
            = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   200
            "gpgme_op_decrypt_verify");
vb@62
   201
        assert(gpg.gpgme_op_decrypt_verify);
vb@62
   202
vb@62
   203
        gpg.gpgme_op_decrypt_result
vb@62
   204
            = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(gpgme,
vb@62
   205
            "gpgme_op_decrypt_result");
vb@62
   206
        assert(gpg.gpgme_op_decrypt_result);
vb@62
   207
vb@62
   208
        gpg.gpgme_op_encrypt_sign
vb@62
   209
            = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(gpgme,
vb@62
   210
            "gpgme_op_encrypt_sign");
vb@62
   211
        assert(gpg.gpgme_op_encrypt_sign);
vb@62
   212
vb@62
   213
        gpg.gpgme_op_verify_result
vb@62
   214
            = (gpgme_op_verify_result_t) (intptr_t) dlsym(gpgme,
vb@62
   215
            "gpgme_op_verify_result");
vb@62
   216
        assert(gpg.gpgme_op_verify_result);
vb@62
   217
vb@62
   218
        gpg.gpgme_signers_clear
vb@62
   219
            = (gpgme_signers_clear_t) (intptr_t) dlsym(gpgme,
vb@62
   220
            "gpgme_signers_clear");
vb@62
   221
        assert(gpg.gpgme_signers_clear);
vb@62
   222
vb@62
   223
        gpg.gpgme_signers_add
vb@62
   224
            = (gpgme_signers_add_t) (intptr_t) dlsym(gpgme,
vb@62
   225
            "gpgme_signers_add");
vb@62
   226
        assert(gpg.gpgme_signers_add);
vb@62
   227
vb@62
   228
        gpg.gpgme_get_key
vb@62
   229
            = (gpgme_get_key_t) (intptr_t) dlsym(gpgme, "gpgme_get_key");
vb@62
   230
        assert(gpg.gpgme_get_key);
vb@62
   231
vb@62
   232
        gpg.gpgme_op_genkey
vb@62
   233
            = (gpgme_op_genkey_t) (intptr_t) dlsym(gpgme,
vb@62
   234
            "gpgme_op_genkey");
vb@62
   235
        assert(gpg.gpgme_op_genkey);
vb@62
   236
vb@62
   237
        gpg.gpgme_op_genkey_result
vb@62
   238
            = (gpgme_op_genkey_result_t) (intptr_t) dlsym(gpgme,
vb@62
   239
            "gpgme_op_genkey_result");
vb@62
   240
        assert(gpg.gpgme_op_genkey_result);
vb@62
   241
vb@62
   242
        gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
vb@62
   243
            dlsym(gpgme, "gpgme_op_delete");
vb@62
   244
        assert(gpg.gpgme_op_delete);
vb@62
   245
vb@62
   246
        gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
vb@62
   247
            dlsym(gpgme, "gpgme_op_import");
vb@62
   248
        assert(gpg.gpgme_op_import);
vb@62
   249
vb@62
   250
        gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
vb@62
   251
            dlsym(gpgme, "gpgme_op_export");
vb@62
   252
        assert(gpg.gpgme_op_export);
vb@62
   253
vb@62
   254
        gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
vb@62
   255
            dlsym(gpgme, "gpgme_set_keylist_mode");
vb@62
   256
        assert(gpg.gpgme_set_keylist_mode);
vb@62
   257
vb@62
   258
        gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
vb@62
   259
            dlsym(gpgme, "gpgme_get_keylist_mode");
vb@62
   260
        assert(gpg.gpgme_get_keylist_mode);
vb@62
   261
vb@62
   262
        gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
vb@62
   263
            dlsym(gpgme, "gpgme_op_keylist_start");
vb@62
   264
        assert(gpg.gpgme_op_keylist_start);
vb@62
   265
vb@62
   266
        gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
vb@62
   267
            dlsym(gpgme, "gpgme_op_keylist_next");
vb@62
   268
        assert(gpg.gpgme_op_keylist_next);
vb@62
   269
vb@62
   270
        gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
vb@62
   271
            dlsym(gpgme, "gpgme_op_keylist_end");
vb@62
   272
        assert(gpg.gpgme_op_keylist_end);
vb@62
   273
vb@62
   274
        gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
vb@62
   275
            dlsym(gpgme, "gpgme_op_import_keys");
vb@62
   276
        assert(gpg.gpgme_op_import_keys);
vb@62
   277
vb@62
   278
        gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
vb@62
   279
            dlsym(gpgme, "gpgme_key_ref");
vb@62
   280
        assert(gpg.gpgme_key_ref);
vb@62
   281
vb@62
   282
        gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
vb@62
   283
            dlsym(gpgme, "gpgme_key_unref");
vb@62
   284
        assert(gpg.gpgme_key_unref);
vb@62
   285
vb@62
   286
        gpg.version = gpg.gpgme_check(NULL);
vb@62
   287
        
vb@62
   288
        if (strcmp(setlocale(LC_ALL, NULL), "C") == 0)
vb@62
   289
            setlocale(LC_ALL, "");
vb@62
   290
vb@62
   291
        gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
vb@62
   292
#ifdef LC_MESSAGES // Windoze
vb@62
   293
        gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
vb@62
   294
#endif
vb@24
   295
    }
vb@24
   296
vb@62
   297
    gpgme_error = gpg.gpgme_new(&session->ctx);
vb@45
   298
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   299
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@66
   300
        status = PEP_INIT_GPGME_INIT_FAILED;
vb@66
   301
        goto pep_error;
vb@24
   302
    }
vb@46
   303
    assert(session->ctx);
vb@24
   304
vb@62
   305
    gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
vb@45
   306
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   307
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   308
vb@62
   309
    gpg.gpgme_set_armor(session->ctx, 1);
vb@24
   310
vb@24
   311
    return PEP_STATUS_OK;
vb@66
   312
vb@66
   313
pep_error:
vb@66
   314
    pgp_release(session, in_first);
vb@66
   315
    return status;
vb@24
   316
}
vb@24
   317
vb@62
   318
void pgp_release(PEP_SESSION session, bool out_last)
vb@24
   319
{
vb@62
   320
    if (session->ctx) {
vb@74
   321
        gpg.gpgme_release(session->ctx);
vb@62
   322
        session->ctx = NULL;
vb@62
   323
    }
vb@62
   324
vb@74
   325
    if (out_last)
vb@74
   326
        if (gpgme)
vb@74
   327
            dlclose(gpgme);
vb@24
   328
}
vb@24
   329
vb@24
   330
PEP_STATUS pgp_decrypt_and_verify(
vb@24
   331
    PEP_SESSION session, const char *ctext, size_t csize,
vb@24
   332
    char **ptext, size_t *psize, stringlist_t **keylist
vb@24
   333
    )
vb@24
   334
{
vb@24
   335
    PEP_STATUS result;
vb@24
   336
    gpgme_error_t gpgme_error;
vb@24
   337
    gpgme_data_t cipher, plain;
vb@24
   338
    gpgme_data_type_t dt;
vb@24
   339
vb@24
   340
    stringlist_t *_keylist = NULL;
vb@24
   341
    int i_key = 0;
vb@24
   342
vb@46
   343
    assert(session);
vb@24
   344
    assert(ctext);
vb@24
   345
    assert(csize);
vb@24
   346
    assert(ptext);
vb@24
   347
    assert(psize);
vb@24
   348
    assert(keylist);
vb@24
   349
vb@24
   350
    *ptext = NULL;
vb@24
   351
    *psize = 0;
vb@24
   352
    *keylist = NULL;
vb@24
   353
vb@74
   354
    gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
vb@45
   355
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   356
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   357
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   358
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   359
            return PEP_OUT_OF_MEMORY;
vb@24
   360
        else
vb@24
   361
            return PEP_UNKNOWN_ERROR;
vb@24
   362
    }
vb@24
   363
vb@74
   364
    gpgme_error = gpg.gpgme_data_new(&plain);
vb@45
   365
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   366
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   367
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   368
        gpg.gpgme_data_release(cipher);
vb@24
   369
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   370
            return PEP_OUT_OF_MEMORY;
vb@24
   371
        else
vb@24
   372
            return PEP_UNKNOWN_ERROR;
vb@24
   373
    }
vb@24
   374
vb@74
   375
    dt = gpg.gpgme_data_identify(cipher);
vb@24
   376
    switch (dt) {
vb@24
   377
    case GPGME_DATA_TYPE_PGP_SIGNED:
vb@24
   378
    case GPGME_DATA_TYPE_PGP_OTHER:
vb@74
   379
        gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
vb@24
   380
            plain);
vb@45
   381
        gpgme_error = _GPGERR(gpgme_error);
vb@24
   382
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
   383
        assert(gpgme_error != GPG_ERR_NO_DATA);
vb@24
   384
vb@24
   385
        switch (gpgme_error) {
vb@24
   386
        case GPG_ERR_NO_ERROR:
vb@24
   387
        {
vb@24
   388
            gpgme_verify_result_t gpgme_verify_result;
vb@24
   389
            char *_buffer = NULL;
vb@24
   390
            size_t reading;
vb@74
   391
            size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
vb@24
   392
            gpgme_signature_t gpgme_signature;
vb@24
   393
vb@24
   394
            assert(length != -1);
vb@74
   395
            gpg.gpgme_data_seek(plain, 0, SEEK_SET);
vb@24
   396
vb@24
   397
            // TODO: make things less memory consuming
vb@24
   398
            // the following algorithm allocates memory for the complete
vb@24
   399
            // text
vb@24
   400
vb@24
   401
            _buffer = malloc(length + 1);
vb@24
   402
            assert(_buffer);
vb@24
   403
            if (_buffer == NULL) {
vb@74
   404
                gpg.gpgme_data_release(plain);
vb@74
   405
                gpg.gpgme_data_release(cipher);
vb@24
   406
                return PEP_OUT_OF_MEMORY;
vb@24
   407
            }
vb@24
   408
vb@74
   409
            reading = gpg.gpgme_data_read(plain, _buffer, length);
vb@24
   410
            assert(length == reading);
vb@24
   411
vb@24
   412
            gpgme_verify_result =
vb@74
   413
                gpg.gpgme_op_verify_result(session->ctx);
vb@24
   414
            assert(gpgme_verify_result);
vb@24
   415
            gpgme_signature = gpgme_verify_result->signatures;
vb@24
   416
vb@24
   417
            if (gpgme_signature) {
vb@24
   418
                stringlist_t *k;
vb@24
   419
                _keylist = new_stringlist(NULL);
vb@24
   420
                assert(_keylist);
vb@24
   421
                if (_keylist == NULL) {
vb@74
   422
                    gpg.gpgme_data_release(plain);
vb@74
   423
                    gpg.gpgme_data_release(cipher);
vb@24
   424
                    free(_buffer);
vb@24
   425
                    return PEP_OUT_OF_MEMORY;
vb@24
   426
                }
vb@24
   427
                k = _keylist;
vb@24
   428
vb@24
   429
                result = PEP_DECRYPTED_AND_VERIFIED;
vb@24
   430
                do {
Edouard@136
   431
                    switch (_GPGERR(gpgme_signature->status)) {
vb@24
   432
                    case GPG_ERR_NO_ERROR:
vb@24
   433
                        k = stringlist_add(k, gpgme_signature->fpr);
vb@24
   434
                        break;
vb@24
   435
                    case GPG_ERR_CERT_REVOKED:
vb@24
   436
                    case GPG_ERR_BAD_SIGNATURE:
vb@24
   437
                        result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@24
   438
                        break;
vb@24
   439
                    case GPG_ERR_SIG_EXPIRED:
vb@24
   440
                    case GPG_ERR_KEY_EXPIRED:
vb@24
   441
                    case GPG_ERR_NO_PUBKEY:
vb@24
   442
                        k = stringlist_add(k, gpgme_signature->fpr);
vb@24
   443
                        if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@24
   444
                            result = PEP_DECRYPTED;
vb@24
   445
                        break;
vb@24
   446
                    case GPG_ERR_GENERAL:
vb@24
   447
                        break;
vb@24
   448
                    default:
vb@24
   449
                        if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@24
   450
                            result = PEP_DECRYPTED;
vb@24
   451
                        break;
vb@24
   452
                    }
vb@24
   453
                } while ((gpgme_signature = gpgme_signature->next));
vb@24
   454
            }
vb@24
   455
            else {
vb@24
   456
                result = PEP_DECRYPTED;
vb@24
   457
            }
vb@24
   458
vb@24
   459
            if (result == PEP_DECRYPTED_AND_VERIFIED
vb@24
   460
                || result == PEP_DECRYPTED) {
vb@24
   461
                *ptext = _buffer;
vb@24
   462
                *psize = reading;
vb@24
   463
                (*ptext)[*psize] = 0; // safeguard for naive users
vb@24
   464
                *keylist = _keylist;
vb@24
   465
            }
vb@24
   466
            else {
vb@24
   467
                free_stringlist(_keylist);
vb@24
   468
                free(_buffer);
vb@24
   469
            }
vb@24
   470
            break;
vb@24
   471
        }
vb@24
   472
        case GPG_ERR_DECRYPT_FAILED:
vb@24
   473
            result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   474
            break;
vb@24
   475
        case GPG_ERR_BAD_PASSPHRASE:
vb@24
   476
            NOT_IMPLEMENTED;
vb@24
   477
        default:
vb@24
   478
        {
vb@74
   479
            gpgme_decrypt_result_t gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
vb@24
   480
            result = PEP_DECRYPT_NO_KEY;
vb@24
   481
vb@24
   482
            if (gpgme_decrypt_result != NULL) {
vb@24
   483
                if (gpgme_decrypt_result->unsupported_algorithm)
vb@24
   484
                    *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
vb@24
   485
                else
vb@24
   486
                    *keylist = new_stringlist("");
vb@24
   487
                assert(*keylist);
vb@24
   488
                if (*keylist == NULL) {
vb@24
   489
                    result = PEP_OUT_OF_MEMORY;
vb@24
   490
                    break;
vb@24
   491
                }
vb@24
   492
                stringlist_t *_keylist = *keylist;
vb@24
   493
                for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
vb@24
   494
                    _keylist = stringlist_add(_keylist, r->keyid);
vb@24
   495
                    assert(_keylist);
vb@24
   496
                    if (_keylist == NULL) {
vb@24
   497
                        free_stringlist(*keylist);
vb@24
   498
                        *keylist = NULL;
vb@24
   499
                        result = PEP_OUT_OF_MEMORY;
vb@24
   500
                        break;
vb@24
   501
                    }
vb@24
   502
                }
vb@24
   503
                if (result == PEP_OUT_OF_MEMORY)
vb@24
   504
                    break;
vb@24
   505
            }
vb@24
   506
        }
vb@24
   507
        }
vb@24
   508
        break;
vb@24
   509
vb@24
   510
    default:
vb@24
   511
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   512
    }
vb@24
   513
vb@74
   514
    gpg.gpgme_data_release(plain);
vb@74
   515
    gpg.gpgme_data_release(cipher);
vb@24
   516
    return result;
vb@24
   517
}
vb@24
   518
vb@24
   519
PEP_STATUS pgp_verify_text(
vb@24
   520
    PEP_SESSION session, const char *text, size_t size,
vb@24
   521
    const char *signature, size_t sig_size, stringlist_t **keylist
vb@24
   522
    )
vb@24
   523
{
vb@24
   524
    PEP_STATUS result;
vb@24
   525
    gpgme_error_t gpgme_error;
vb@24
   526
    gpgme_data_t d_text, d_sig;
vb@24
   527
    stringlist_t *_keylist;
vb@24
   528
vb@24
   529
    assert(session);
vb@24
   530
    assert(text);
vb@24
   531
    assert(size);
vb@24
   532
    assert(signature);
vb@24
   533
    assert(sig_size);
vb@24
   534
    assert(keylist);
vb@24
   535
vb@24
   536
    *keylist = NULL;
vb@24
   537
vb@74
   538
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
vb@45
   539
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   540
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   541
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   542
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   543
            return PEP_OUT_OF_MEMORY;
vb@24
   544
        else
vb@24
   545
            return PEP_UNKNOWN_ERROR;
vb@24
   546
    }
vb@24
   547
vb@74
   548
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
vb@45
   549
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   550
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   551
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   552
        gpg.gpgme_data_release(d_text);
vb@24
   553
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   554
            return PEP_OUT_OF_MEMORY;
vb@24
   555
        else
vb@24
   556
            return PEP_UNKNOWN_ERROR;
vb@24
   557
    }
vb@24
   558
vb@74
   559
    gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
vb@45
   560
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   561
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
   562
vb@24
   563
    switch (gpgme_error) {
vb@24
   564
    case GPG_ERR_NO_ERROR:
vb@24
   565
    {
vb@24
   566
        gpgme_verify_result_t gpgme_verify_result;
vb@24
   567
        gpgme_signature_t gpgme_signature;
vb@24
   568
vb@24
   569
        gpgme_verify_result =
vb@74
   570
            gpg.gpgme_op_verify_result(session->ctx);
vb@24
   571
        assert(gpgme_verify_result);
vb@24
   572
        gpgme_signature = gpgme_verify_result->signatures;
vb@24
   573
vb@24
   574
        if (gpgme_signature) {
vb@24
   575
            stringlist_t *k;
vb@24
   576
            _keylist = new_stringlist(NULL);
vb@24
   577
            assert(_keylist);
vb@24
   578
            if (_keylist == NULL) {
vb@74
   579
                gpg.gpgme_data_release(d_text);
vb@74
   580
                gpg.gpgme_data_release(d_sig);
vb@24
   581
                return PEP_OUT_OF_MEMORY;
vb@24
   582
            }
vb@24
   583
            k = _keylist;
vb@24
   584
vb@24
   585
            result = PEP_VERIFIED;
vb@24
   586
            do {
vb@24
   587
                k = stringlist_add(k, gpgme_signature->fpr);
vb@24
   588
                if (k == NULL) {
vb@24
   589
                    free_stringlist(_keylist);
vb@74
   590
                    gpg.gpgme_data_release(d_text);
vb@74
   591
                    gpg.gpgme_data_release(d_sig);
vb@24
   592
                    return PEP_OUT_OF_MEMORY;
vb@24
   593
                }
vb@24
   594
                if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
vb@24
   595
                    if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
vb@24
   596
                        || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
vb@24
   597
                        if (result == PEP_VERIFIED
vb@24
   598
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
   599
                            result = PEP_UNENCRYPTED;
vb@24
   600
                    }
vb@24
   601
                    else {
vb@24
   602
                        result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@24
   603
                        break;
vb@24
   604
                    }
vb@24
   605
                }
vb@24
   606
                else {
vb@24
   607
                    if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
vb@24
   608
                        if (result == PEP_VERIFIED)
vb@24
   609
                            result = PEP_VERIFIED_AND_TRUSTED;
vb@24
   610
                    }
vb@24
   611
                    if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
vb@24
   612
                        // good
vb@24
   613
                    }
vb@24
   614
                    else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
vb@24
   615
                        result = PEP_VERIFY_NO_KEY;
vb@24
   616
                    }
vb@24
   617
                    else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
vb@24
   618
                        if (result == PEP_VERIFIED
vb@24
   619
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
   620
                            result = PEP_UNENCRYPTED;
vb@24
   621
                    }
vb@24
   622
                    else {
vb@24
   623
                        // do nothing
vb@24
   624
                    }
vb@24
   625
                }
vb@24
   626
            } while ((gpgme_signature = gpgme_signature->next));
vb@24
   627
            *keylist = _keylist;
vb@24
   628
        }
vb@24
   629
        else {
vb@24
   630
            result = PEP_UNENCRYPTED;
vb@24
   631
        }
vb@24
   632
        break;
vb@24
   633
    }
vb@24
   634
        break;
vb@24
   635
    case GPG_ERR_NO_DATA:
vb@24
   636
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   637
        break;
vb@24
   638
    case GPG_ERR_INV_VALUE:
vb@24
   639
    default:
vb@24
   640
        result = PEP_UNKNOWN_ERROR;
vb@24
   641
        break;
vb@24
   642
    }
vb@24
   643
vb@74
   644
    gpg.gpgme_data_release(d_text);
vb@74
   645
    gpg.gpgme_data_release(d_sig);
vb@24
   646
vb@24
   647
    return result;
vb@24
   648
}
vb@24
   649
vb@24
   650
PEP_STATUS pgp_encrypt_and_sign(
vb@24
   651
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
vb@24
   652
    size_t psize, char **ctext, size_t *csize
vb@24
   653
    )
vb@24
   654
{
vb@24
   655
    PEP_STATUS result;
vb@24
   656
    gpgme_error_t gpgme_error;
vb@24
   657
    gpgme_data_t plain, cipher;
vb@24
   658
    gpgme_key_t *rcpt;
vb@24
   659
    gpgme_encrypt_flags_t flags;
vb@24
   660
    const stringlist_t *_keylist;
vb@24
   661
    int i, j;
vb@24
   662
vb@46
   663
    assert(session);
vb@24
   664
    assert(keylist);
vb@24
   665
    assert(ptext);
vb@24
   666
    assert(psize);
vb@24
   667
    assert(ctext);
vb@24
   668
    assert(csize);
vb@24
   669
vb@24
   670
    *ctext = NULL;
vb@24
   671
    *csize = 0;
vb@24
   672
vb@74
   673
    gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
vb@45
   674
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   675
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   676
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   677
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   678
            return PEP_OUT_OF_MEMORY;
vb@24
   679
        else
vb@24
   680
            return PEP_UNKNOWN_ERROR;
vb@24
   681
    }
vb@24
   682
vb@74
   683
    gpgme_error = gpg.gpgme_data_new(&cipher);
vb@45
   684
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   685
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   686
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   687
        gpg.gpgme_data_release(plain);
vb@24
   688
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   689
            return PEP_OUT_OF_MEMORY;
vb@24
   690
        else
vb@24
   691
            return PEP_UNKNOWN_ERROR;
vb@24
   692
    }
vb@24
   693
vb@109
   694
    rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
vb@24
   695
    assert(rcpt);
vb@24
   696
    if (rcpt == NULL) {
vb@74
   697
        gpg.gpgme_data_release(plain);
vb@74
   698
        gpg.gpgme_data_release(cipher);
vb@24
   699
        return PEP_OUT_OF_MEMORY;
vb@24
   700
    }
vb@24
   701
vb@74
   702
    gpg.gpgme_signers_clear(session->ctx);
vb@24
   703
vb@24
   704
    for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
vb@24
   705
        assert(_keylist->value);
vb@74
   706
        gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
vb@24
   707
            &rcpt[i], 0);
vb@45
   708
        gpgme_error = _GPGERR(gpgme_error);
vb@24
   709
        assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
   710
vb@24
   711
        switch (gpgme_error) {
vb@24
   712
        case GPG_ERR_ENOMEM:
vb@24
   713
            for (j = 0; j<i; j++)
vb@74
   714
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   715
            free(rcpt);
vb@74
   716
            gpg.gpgme_data_release(plain);
vb@74
   717
            gpg.gpgme_data_release(cipher);
vb@24
   718
            return PEP_OUT_OF_MEMORY;
vb@24
   719
        case GPG_ERR_NO_ERROR:
vb@24
   720
            if (i == 0) {
vb@74
   721
                gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
vb@45
   722
                _gpgme_error = _GPGERR(_gpgme_error);
vb@24
   723
                assert(_gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   724
            }
vb@24
   725
            break;
vb@24
   726
        case GPG_ERR_EOF:
vb@24
   727
            for (j = 0; j<i; j++)
vb@74
   728
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   729
            free(rcpt);
vb@74
   730
            gpg.gpgme_data_release(plain);
vb@74
   731
            gpg.gpgme_data_release(cipher);
vb@24
   732
            return PEP_KEY_NOT_FOUND;
vb@24
   733
        case GPG_ERR_AMBIGUOUS_NAME:
vb@24
   734
            for (j = 0; j<i; j++)
vb@74
   735
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   736
            free(rcpt);
vb@74
   737
            gpg.gpgme_data_release(plain);
vb@74
   738
            gpg.gpgme_data_release(cipher);
vb@24
   739
            return PEP_KEY_HAS_AMBIG_NAME;
vb@24
   740
        default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
vb@24
   741
            // FPR is not a fingerprint or key ID
vb@24
   742
            for (j = 0; j<i; j++)
vb@74
   743
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   744
            free(rcpt);
vb@74
   745
            gpg.gpgme_data_release(plain);
vb@74
   746
            gpg.gpgme_data_release(cipher);
vb@24
   747
            return PEP_GET_KEY_FAILED;
vb@24
   748
        }
vb@24
   749
    }
vb@24
   750
vb@24
   751
    // TODO: remove that and replace with proper key management
vb@24
   752
    flags = GPGME_ENCRYPT_ALWAYS_TRUST;
vb@24
   753
vb@74
   754
    gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
vb@24
   755
        plain, cipher);
vb@45
   756
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   757
    switch (gpgme_error) {
vb@24
   758
    case GPG_ERR_NO_ERROR:
vb@24
   759
    {
vb@24
   760
        char *_buffer = NULL;
vb@24
   761
        size_t reading;
vb@74
   762
        size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
vb@24
   763
        assert(length != -1);
vb@74
   764
        gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
vb@24
   765
vb@24
   766
        // TODO: make things less memory consuming
vb@24
   767
        // the following algorithm allocates a buffer for the complete text
vb@24
   768
vb@112
   769
        _buffer = malloc(length + 1);
vb@24
   770
        assert(_buffer);
vb@24
   771
        if (_buffer == NULL) {
vb@24
   772
            for (j = 0; j<stringlist_length(keylist); j++)
vb@74
   773
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
   774
            free(rcpt);
vb@74
   775
            gpg.gpgme_data_release(plain);
vb@74
   776
            gpg.gpgme_data_release(cipher);
vb@24
   777
            return PEP_OUT_OF_MEMORY;
vb@24
   778
        }
vb@24
   779
vb@74
   780
        reading = gpg.gpgme_data_read(cipher, _buffer, length);
vb@24
   781
        assert(length == reading);
vb@24
   782
vb@24
   783
        *ctext = _buffer;
vb@24
   784
        *csize = reading;
vb@24
   785
        (*ctext)[*csize] = 0; // safeguard for naive users
vb@24
   786
        result = PEP_STATUS_OK;
vb@24
   787
        break;
vb@24
   788
    }
vb@24
   789
    default:
vb@24
   790
        result = PEP_UNKNOWN_ERROR;
vb@24
   791
    }
vb@24
   792
vb@24
   793
    for (j = 0; j<stringlist_length(keylist); j++)
vb@74
   794
        gpg.gpgme_key_unref(rcpt[j]);
vb@24
   795
    free(rcpt);
vb@74
   796
    gpg.gpgme_data_release(plain);
vb@74
   797
    gpg.gpgme_data_release(cipher);
vb@24
   798
    return result;
vb@24
   799
}
vb@24
   800
vb@24
   801
PEP_STATUS pgp_generate_keypair(
vb@24
   802
    PEP_SESSION session, pEp_identity *identity
vb@24
   803
    )
vb@24
   804
{
vb@24
   805
    gpgme_error_t gpgme_error;
vb@24
   806
    char *parms;
vb@24
   807
    const char *template =
vb@24
   808
        "<GnupgKeyParms format=\"internal\">\n"
vb@24
   809
        "Key-Type: RSA\n"
vb@24
   810
        "Key-Length: 4096\n"
vb@24
   811
        "Name-Real: %s\n"
vb@24
   812
        "Name-Email: %s\n"
vb@24
   813
        /* "Passphrase: %s\n" */
vb@24
   814
        "Expire-Date: 1y\n"
vb@24
   815
        "</GnupgKeyParms>\n";
vb@24
   816
    int result;
vb@24
   817
    gpgme_genkey_result_t gpgme_genkey_result;
vb@24
   818
vb@24
   819
    assert(session);
vb@24
   820
    assert(identity);
vb@24
   821
    assert(identity->address);
vb@24
   822
    assert(identity->fpr == NULL);
vb@24
   823
    assert(identity->username);
vb@24
   824
vb@24
   825
    parms = calloc(1, PARMS_MAX);
vb@24
   826
    assert(parms);
vb@24
   827
    if (parms == NULL)
vb@24
   828
        return PEP_OUT_OF_MEMORY;
vb@24
   829
vb@24
   830
    result = snprintf(parms, PARMS_MAX, template, identity->username,
vb@46
   831
        identity->address); // , session->passphrase);
vb@24
   832
    assert(result < PARMS_MAX);
vb@24
   833
    if (result >= PARMS_MAX) {
vb@24
   834
        free(parms);
vb@24
   835
        return PEP_BUFFER_TOO_SMALL;
vb@24
   836
    }
vb@24
   837
vb@74
   838
    gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
vb@45
   839
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   840
    free(parms);
vb@24
   841
vb@24
   842
    switch (gpgme_error) {
vb@24
   843
    case GPG_ERR_NO_ERROR:
vb@24
   844
        break;
vb@24
   845
    case GPG_ERR_INV_VALUE:
vb@24
   846
        return PEP_ILLEGAL_VALUE;
vb@24
   847
    case GPG_ERR_GENERAL:
vb@24
   848
        return PEP_CANNOT_CREATE_KEY;
vb@24
   849
    default:
vb@24
   850
        assert(0);
vb@24
   851
        return PEP_UNKNOWN_ERROR;
vb@24
   852
    }
vb@24
   853
vb@74
   854
    gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
vb@24
   855
    assert(gpgme_genkey_result);
vb@24
   856
    assert(gpgme_genkey_result->fpr);
vb@24
   857
vb@24
   858
    identity->fpr = strdup(gpgme_genkey_result->fpr);
vb@24
   859
vb@24
   860
    return PEP_STATUS_OK;
vb@24
   861
}
vb@24
   862
vb@24
   863
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
vb@24
   864
{
vb@24
   865
    gpgme_error_t gpgme_error;
vb@24
   866
    gpgme_key_t key;
vb@24
   867
vb@24
   868
    assert(session);
vb@24
   869
    assert(fpr);
vb@24
   870
vb@74
   871
    gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
vb@45
   872
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   873
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
   874
    switch (gpgme_error) {
vb@24
   875
    case GPG_ERR_NO_ERROR:
vb@24
   876
        break;
vb@24
   877
    case GPG_ERR_EOF:
vb@24
   878
        return PEP_KEY_NOT_FOUND;
vb@24
   879
    case GPG_ERR_INV_VALUE:
vb@24
   880
        return PEP_ILLEGAL_VALUE;
vb@24
   881
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
   882
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
   883
    case GPG_ERR_ENOMEM:
vb@24
   884
        return PEP_OUT_OF_MEMORY;
vb@24
   885
    default:
vb@24
   886
        assert(0);
vb@24
   887
        return PEP_UNKNOWN_ERROR;
vb@24
   888
    }
vb@24
   889
vb@74
   890
    gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
vb@45
   891
    gpgme_error = _GPGERR(gpgme_error);
vb@74
   892
    gpg.gpgme_key_unref(key);
vb@24
   893
    switch (gpgme_error) {
vb@24
   894
    case GPG_ERR_NO_ERROR:
vb@24
   895
        break;
vb@24
   896
    case GPG_ERR_INV_VALUE:
vb@24
   897
        assert(0);
vb@24
   898
        return PEP_UNKNOWN_ERROR;
vb@24
   899
    case GPG_ERR_NO_PUBKEY:
vb@24
   900
        assert(0);
vb@24
   901
        return PEP_KEY_NOT_FOUND;
vb@24
   902
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
   903
        assert(0);
vb@24
   904
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
   905
    default:
vb@24
   906
        assert(0);
vb@24
   907
        return PEP_UNKNOWN_ERROR;
vb@24
   908
    }
vb@24
   909
vb@24
   910
    return PEP_STATUS_OK;
vb@24
   911
}
vb@24
   912
Edouard@170
   913
PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data, size_t size)
vb@24
   914
{
vb@24
   915
    gpgme_error_t gpgme_error;
vb@24
   916
    gpgme_data_t dh;
vb@24
   917
vb@24
   918
    assert(session);
vb@24
   919
    assert(key_data);
vb@24
   920
vb@74
   921
    gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
vb@45
   922
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   923
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
   924
    switch (gpgme_error) {
vb@24
   925
    case GPG_ERR_NO_ERROR:
vb@24
   926
        break;
vb@24
   927
    case GPG_ERR_ENOMEM:
vb@24
   928
        return PEP_OUT_OF_MEMORY;
vb@24
   929
    case GPG_ERR_INV_VALUE:
vb@24
   930
        assert(0);
vb@24
   931
        return PEP_UNKNOWN_ERROR;
vb@24
   932
    default:
vb@24
   933
        assert(0);
vb@24
   934
        return PEP_UNKNOWN_ERROR;
vb@24
   935
    }
vb@24
   936
vb@74
   937
    gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
vb@45
   938
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   939
    switch (gpgme_error) {
vb@24
   940
    case GPG_ERR_NO_ERROR:
vb@24
   941
        break;
vb@24
   942
    case GPG_ERR_INV_VALUE:
vb@24
   943
        assert(0);
vb@74
   944
        gpg.gpgme_data_release(dh);
vb@24
   945
        return PEP_UNKNOWN_ERROR;
vb@24
   946
    case GPG_ERR_NO_DATA:
vb@74
   947
        gpg.gpgme_data_release(dh);
vb@24
   948
        return PEP_ILLEGAL_VALUE;
vb@24
   949
    default:
vb@24
   950
        assert(0);
vb@74
   951
        gpg.gpgme_data_release(dh);
vb@24
   952
        return PEP_UNKNOWN_ERROR;
vb@24
   953
    }
vb@24
   954
vb@74
   955
    gpg.gpgme_data_release(dh);
vb@24
   956
    return PEP_STATUS_OK;
vb@24
   957
}
vb@24
   958
Edouard@170
   959
PEP_STATUS pgp_export_keydata(
vb@24
   960
    PEP_SESSION session, const char *fpr, char **key_data, size_t *size
vb@24
   961
    )
vb@24
   962
{
vb@24
   963
    gpgme_error_t gpgme_error;
vb@24
   964
    gpgme_data_t dh;
vb@24
   965
    size_t _size;
vb@24
   966
    char *buffer;
vb@24
   967
    int reading;
vb@24
   968
vb@24
   969
    assert(session);
vb@24
   970
    assert(fpr);
vb@24
   971
    assert(key_data);
vb@24
   972
    assert(size);
vb@24
   973
vb@74
   974
    gpgme_error = gpg.gpgme_data_new(&dh);
vb@45
   975
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   976
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
   977
    switch (gpgme_error) {
vb@24
   978
    case GPG_ERR_NO_ERROR:
vb@24
   979
        break;
vb@24
   980
    case GPG_ERR_ENOMEM:
vb@24
   981
        return PEP_OUT_OF_MEMORY;
vb@24
   982
    case GPG_ERR_INV_VALUE:
vb@24
   983
        assert(0);
vb@24
   984
        return PEP_UNKNOWN_ERROR;
vb@24
   985
    default:
vb@24
   986
        assert(0);
vb@24
   987
        return PEP_UNKNOWN_ERROR;
vb@24
   988
    }
vb@24
   989
vb@74
   990
    gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
vb@24
   991
        GPGME_EXPORT_MODE_MINIMAL, dh);
vb@45
   992
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   993
    switch (gpgme_error) {
vb@24
   994
    case GPG_ERR_NO_ERROR:
vb@24
   995
        break;
vb@24
   996
    case GPG_ERR_EOF:
vb@74
   997
        gpg.gpgme_data_release(dh);
vb@24
   998
        return PEP_KEY_NOT_FOUND;
vb@24
   999
    case GPG_ERR_INV_VALUE:
vb@24
  1000
        assert(0);
vb@74
  1001
        gpg.gpgme_data_release(dh);
vb@24
  1002
        return PEP_UNKNOWN_ERROR;
vb@24
  1003
    default:
vb@24
  1004
        assert(0);
vb@74
  1005
        gpg.gpgme_data_release(dh);
vb@24
  1006
        return PEP_UNKNOWN_ERROR;
vb@24
  1007
    };
vb@24
  1008
vb@74
  1009
    _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
vb@24
  1010
    assert(_size != -1);
vb@74
  1011
    gpg.gpgme_data_seek(dh, 0, SEEK_SET);
vb@24
  1012
vb@24
  1013
    buffer = malloc(_size + 1);
vb@24
  1014
    assert(buffer);
vb@24
  1015
    if (buffer == NULL) {
vb@74
  1016
        gpg.gpgme_data_release(dh);
vb@24
  1017
        return PEP_OUT_OF_MEMORY;
vb@24
  1018
    }
vb@24
  1019
vb@74
  1020
    reading = gpg.gpgme_data_read(dh, buffer, _size);
vb@24
  1021
    assert(_size == reading);
vb@24
  1022
vb@24
  1023
    // safeguard for the naive user
vb@24
  1024
    buffer[_size] = 0;
vb@24
  1025
vb@24
  1026
    *key_data = buffer;
vb@24
  1027
    *size = _size;
vb@24
  1028
vb@74
  1029
    gpg.gpgme_data_release(dh);
vb@24
  1030
    return PEP_STATUS_OK;
vb@24
  1031
}
vb@24
  1032
vb@46
  1033
static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
vb@24
  1034
    gpgme_keylist_mode_t add_mode)
vb@24
  1035
{
vb@24
  1036
    gpgme_error_t gpgme_error;
vb@24
  1037
    gpgme_keylist_mode_t mode;
vb@24
  1038
vb@74
  1039
    mode = gpg.gpgme_get_keylist_mode(session->ctx);
vb@24
  1040
vb@24
  1041
    mode &= ~remove_mode;
vb@24
  1042
    mode |= add_mode;
vb@24
  1043
vb@74
  1044
    gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
vb@45
  1045
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1046
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1047
}
vb@24
  1048
vb@24
  1049
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
vb@24
  1050
{
vb@24
  1051
    gpgme_error_t gpgme_error;
vb@24
  1052
    gpgme_key_t key;
vb@24
  1053
vb@24
  1054
    assert(session);
vb@24
  1055
    assert(pattern);
vb@24
  1056
vb@46
  1057
    _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
vb@24
  1058
vb@74
  1059
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
vb@45
  1060
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1061
    switch (gpgme_error) {
vb@24
  1062
    case GPG_ERR_NO_ERROR:
vb@24
  1063
        break;
vb@24
  1064
    case GPG_ERR_INV_VALUE:
vb@24
  1065
        assert(0);
vb@47
  1066
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1067
        return PEP_UNKNOWN_ERROR;
vb@24
  1068
    default:
vb@47
  1069
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1070
        return PEP_GET_KEY_FAILED;
vb@24
  1071
    };
vb@24
  1072
vb@47
  1073
    gpgme_ctx_t import_ctx;
vb@74
  1074
    gpgme_error = gpg.gpgme_new(&import_ctx);
vb@47
  1075
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@47
  1076
vb@24
  1077
    do {
vb@74
  1078
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1079
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1080
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1081
        switch (gpgme_error) {
vb@24
  1082
        case GPG_ERR_EOF:
vb@24
  1083
            break;
vb@24
  1084
        case GPG_ERR_NO_ERROR:
vb@24
  1085
        {
vb@24
  1086
            gpgme_error_t gpgme_error;
vb@24
  1087
            gpgme_key_t keys[2];
vb@24
  1088
vb@24
  1089
            keys[0] = key;
vb@24
  1090
            keys[1] = NULL;
vb@24
  1091
vb@74
  1092
            gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
vb@45
  1093
            gpgme_error = _GPGERR(gpgme_error);
vb@74
  1094
            gpg.gpgme_key_unref(key);
vb@24
  1095
            assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1096
            assert(gpgme_error != GPG_ERR_CONFLICT);
vb@24
  1097
        }
vb@24
  1098
            break;
vb@24
  1099
        case GPG_ERR_ENOMEM:
vb@74
  1100
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1101
            gpg.gpgme_release(import_ctx);
vb@47
  1102
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1103
            return PEP_OUT_OF_MEMORY;
vb@24
  1104
        default:
vb@74
  1105
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1106
            gpg.gpgme_release(import_ctx);
vb@47
  1107
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@46
  1108
            return PEP_UNKNOWN_ERROR;
vb@24
  1109
        };
vb@24
  1110
    } while (gpgme_error != GPG_ERR_EOF);
vb@24
  1111
vb@74
  1112
    gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1113
    gpg.gpgme_release(import_ctx);
vb@47
  1114
    _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1115
    return PEP_STATUS_OK;
vb@24
  1116
}
vb@24
  1117
vb@24
  1118
PEP_STATUS pgp_find_keys(
vb@24
  1119
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
vb@24
  1120
    )
vb@24
  1121
{
vb@24
  1122
    gpgme_error_t gpgme_error;
vb@24
  1123
    gpgme_key_t key;
vb@24
  1124
    stringlist_t *_keylist;
vb@24
  1125
    char *fpr;
vb@24
  1126
vb@24
  1127
    assert(session);
vb@24
  1128
    assert(pattern);
vb@24
  1129
    assert(keylist);
vb@24
  1130
vb@24
  1131
    *keylist = NULL;
vb@24
  1132
vb@74
  1133
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
vb@45
  1134
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1135
    switch (gpgme_error) {
vb@24
  1136
    case GPG_ERR_NO_ERROR:
vb@24
  1137
        break;
vb@24
  1138
    case GPG_ERR_INV_VALUE:
vb@24
  1139
        assert(0);
vb@24
  1140
        return PEP_UNKNOWN_ERROR;
vb@24
  1141
    default:
vb@74
  1142
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1143
        return PEP_GET_KEY_FAILED;
vb@24
  1144
    };
vb@24
  1145
vb@24
  1146
    _keylist = new_stringlist(NULL);
vb@24
  1147
    stringlist_t *_k = _keylist;
vb@24
  1148
vb@24
  1149
    do {
vb@74
  1150
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1151
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1152
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1153
        switch (gpgme_error) {
vb@24
  1154
        case GPG_ERR_EOF:
vb@24
  1155
            break;
vb@24
  1156
        case GPG_ERR_NO_ERROR:
vb@24
  1157
            assert(key);
vb@24
  1158
            assert(key->subkeys);
vb@24
  1159
            fpr = key->subkeys->fpr;
vb@24
  1160
            assert(fpr);
vb@24
  1161
            _k = stringlist_add(_k, fpr);
vb@24
  1162
            assert(_k);
vb@24
  1163
            if (_k != NULL)
vb@24
  1164
                break;
vb@24
  1165
        case GPG_ERR_ENOMEM:
vb@24
  1166
            free_stringlist(_keylist);
vb@74
  1167
            gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1168
            return PEP_OUT_OF_MEMORY;
vb@24
  1169
        default:
vb@74
  1170
            gpg.gpgme_op_keylist_end(session->ctx);
vb@46
  1171
            return PEP_UNKNOWN_ERROR;
vb@24
  1172
        };
vb@24
  1173
    } while (gpgme_error != GPG_ERR_EOF);
vb@24
  1174
vb@74
  1175
    gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1176
    *keylist = _keylist;
vb@24
  1177
    return PEP_STATUS_OK;
vb@24
  1178
}
vb@24
  1179
vb@24
  1180
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
vb@24
  1181
{
vb@24
  1182
    gpgme_error_t gpgme_error;
vb@24
  1183
vb@24
  1184
    assert(session);
vb@24
  1185
    assert(pattern);
vb@24
  1186
vb@74
  1187
    gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
vb@24
  1188
        GPGME_EXPORT_MODE_EXTERN, NULL);
vb@45
  1189
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1190
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1191
    if (gpgme_error == GPG_ERR_NO_ERROR)
vb@24
  1192
        return PEP_STATUS_OK;
vb@24
  1193
    else
vb@24
  1194
        return PEP_CANNOT_SEND_KEY;
vb@24
  1195
}
vb@24
  1196
vb@24
  1197
PEP_STATUS pgp_get_key_rating(
vb@24
  1198
    PEP_SESSION session,
vb@24
  1199
    const char *fpr,
vb@24
  1200
    PEP_comm_type *comm_type
vb@24
  1201
    )
vb@24
  1202
{
vb@24
  1203
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
  1204
    gpgme_error_t gpgme_error;
vb@24
  1205
    gpgme_key_t key;
vb@24
  1206
vb@24
  1207
    assert(session);
vb@24
  1208
    assert(fpr);
vb@24
  1209
    assert(comm_type);
vb@24
  1210
vb@24
  1211
    *comm_type = PEP_ct_unknown;
vb@24
  1212
vb@74
  1213
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
vb@45
  1214
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1215
    switch (gpgme_error) {
vb@24
  1216
    case GPG_ERR_NO_ERROR:
vb@24
  1217
        break;
vb@24
  1218
    case GPG_ERR_INV_VALUE:
vb@24
  1219
        assert(0);
vb@24
  1220
        return PEP_UNKNOWN_ERROR;
vb@24
  1221
    default:
vb@24
  1222
        return PEP_GET_KEY_FAILED;
vb@24
  1223
    };
vb@24
  1224
vb@74
  1225
    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1226
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1227
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1228
vb@24
  1229
    if (key == NULL) {
vb@74
  1230
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1231
        return PEP_KEY_NOT_FOUND;
vb@24
  1232
    }
vb@24
  1233
vb@24
  1234
    switch (key->protocol) {
vb@24
  1235
    case GPGME_PROTOCOL_OpenPGP:
vb@24
  1236
    case GPGME_PROTOCOL_DEFAULT:
vb@24
  1237
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
vb@24
  1238
        break;
vb@24
  1239
    case GPGME_PROTOCOL_CMS:
vb@24
  1240
        *comm_type = PEP_ct_CMS_unconfirmed;
vb@24
  1241
        break;
vb@24
  1242
    default:
vb@24
  1243
        *comm_type = PEP_ct_unknown;
vb@74
  1244
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1245
        return PEP_STATUS_OK;
vb@24
  1246
    }
vb@24
  1247
vb@24
  1248
    switch (gpgme_error) {
vb@24
  1249
    case GPG_ERR_EOF:
vb@24
  1250
        break;
vb@24
  1251
    case GPG_ERR_NO_ERROR:
vb@24
  1252
        assert(key);
vb@24
  1253
        assert(key->subkeys);
vb@24
  1254
        for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
vb@24
  1255
            if (sk->length < 1024)
vb@24
  1256
                *comm_type = PEP_ct_key_too_short;
vb@24
  1257
            else if (
vb@24
  1258
                (
vb@24
  1259
                (sk->pubkey_algo == GPGME_PK_RSA)
vb@24
  1260
                || (sk->pubkey_algo == GPGME_PK_RSA_E)
vb@24
  1261
                || (sk->pubkey_algo == GPGME_PK_RSA_S)
vb@24
  1262
                )
vb@24
  1263
                && sk->length == 1024
vb@24
  1264
                )
vb@122
  1265
                *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
vb@24
  1266
vb@24
  1267
            if (sk->invalid) {
vb@24
  1268
                *comm_type = PEP_ct_key_b0rken;
vb@24
  1269
                break;
vb@24
  1270
            }
vb@24
  1271
            if (sk->expired) {
vb@24
  1272
                *comm_type = PEP_ct_key_expired;
vb@24
  1273
                break;
vb@24
  1274
            }
vb@24
  1275
            if (sk->revoked) {
vb@24
  1276
                *comm_type = PEP_ct_key_revoked;
vb@24
  1277
                break;
vb@24
  1278
            }
vb@24
  1279
        }
vb@24
  1280
        break;
vb@24
  1281
    case GPG_ERR_ENOMEM:
vb@74
  1282
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1283
        *comm_type = PEP_ct_unknown;
vb@24
  1284
        return PEP_OUT_OF_MEMORY;
vb@24
  1285
    default:
vb@74
  1286
        gpg.gpgme_op_keylist_end(session->ctx);
vb@46
  1287
        return PEP_UNKNOWN_ERROR;
vb@24
  1288
    };
vb@24
  1289
vb@74
  1290
    gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  1291
vb@24
  1292
    return status;
vb@24
  1293
}
vb@200
  1294
vb@200
  1295
static PEP_STATUS find_single_key(
vb@200
  1296
        PEP_SESSION session,
vb@200
  1297
        const char *fpr,
vb@200
  1298
        gpgme_key_t *key
vb@200
  1299
    )
vb@200
  1300
{
vb@200
  1301
    gpgme_error_t gpgme_error;
vb@200
  1302
vb@200
  1303
    *key = NULL;
vb@200
  1304
vb@200
  1305
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
vb@200
  1306
    gpgme_error = _GPGERR(gpgme_error);
vb@200
  1307
    switch (gpgme_error) {
vb@200
  1308
    case GPG_ERR_NO_ERROR:
vb@200
  1309
        break;
vb@200
  1310
    case GPG_ERR_INV_VALUE:
vb@200
  1311
        assert(0);
vb@200
  1312
        return PEP_UNKNOWN_ERROR;
vb@200
  1313
    default:
vb@200
  1314
        return PEP_GET_KEY_FAILED;
vb@200
  1315
    };
vb@200
  1316
vb@200
  1317
    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
vb@200
  1318
    gpgme_error = _GPGERR(gpgme_error);
vb@200
  1319
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@200
  1320
vb@200
  1321
    gpg.gpgme_op_keylist_end(session->ctx);
vb@200
  1322
vb@200
  1323
    return PEP_STATUS_OK;
vb@200
  1324
}
vb@200
  1325
vb@201
  1326
typedef struct _renew_state {
vb@211
  1327
    enum {
vb@200
  1328
        renew_command = 0,
vb@200
  1329
        renew_date,
vb@200
  1330
        renew_secret_key,
vb@200
  1331
        renew_command2,
vb@200
  1332
        renew_date2,
vb@200
  1333
        renew_quit,
vb@200
  1334
        renew_save,
vb@200
  1335
        renew_exit,
vb@200
  1336
        renew_error = -1
vb@200
  1337
    } state;
vb@201
  1338
    const char *date_ref;
vb@201
  1339
} renew_state;
vb@200
  1340
vb@201
  1341
static gpgme_error_t renew_fsm(
vb@200
  1342
        void *_handle,
vb@200
  1343
        gpgme_status_code_t statuscode,
vb@200
  1344
        const char *args,
vb@200
  1345
        int fd
vb@200
  1346
    )
vb@200
  1347
{
vb@201
  1348
    renew_state *handle = _handle;
vb@200
  1349
vb@200
  1350
    switch (handle->state) {
vb@200
  1351
        case renew_command:
vb@200
  1352
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1353
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  1354
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  1355
                    handle->state = renew_error;
vb@201
  1356
                    return GPG_ERR_GENERAL;
vb@201
  1357
                }
vb@200
  1358
                write(fd, "expire\n", 7);
vb@200
  1359
                handle->state = renew_date;
vb@200
  1360
            }
vb@200
  1361
            break;
vb@200
  1362
vb@200
  1363
        case renew_date:
vb@200
  1364
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1365
                assert(strcmp(args, "keygen.valid") == 0);
vb@201
  1366
                if (strcmp(args, "keygen.valid")) {
vb@201
  1367
                    handle->state = renew_error;
vb@201
  1368
                    return GPG_ERR_GENERAL;
vb@201
  1369
                }
vb@203
  1370
                write(fd, handle->date_ref, 11);
vb@200
  1371
                handle->state = renew_secret_key;
vb@200
  1372
            }
vb@200
  1373
            break;
vb@200
  1374
vb@200
  1375
        case renew_secret_key:
vb@200
  1376
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1377
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  1378
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  1379
                    handle->state = renew_error;
vb@201
  1380
                    return GPG_ERR_GENERAL;
vb@201
  1381
                }
vb@200
  1382
                write(fd, "key 1\n", 6);
vb@200
  1383
                handle->state = renew_command2;
vb@200
  1384
            }
vb@200
  1385
            break;
vb@200
  1386
vb@200
  1387
        case renew_command2:
vb@200
  1388
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1389
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  1390
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  1391
                    handle->state = renew_error;
vb@201
  1392
                    return GPG_ERR_GENERAL;
vb@201
  1393
                }
vb@200
  1394
                write(fd, "expire\n", 7);
vb@200
  1395
                handle->state = renew_date2;
vb@200
  1396
            }
vb@200
  1397
            break;
vb@200
  1398
vb@200
  1399
        case renew_date2:
vb@200
  1400
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1401
                assert(strcmp(args, "keygen.valid") == 0);
vb@201
  1402
                if (strcmp(args, "keygen.valid")) {
vb@201
  1403
                    handle->state = renew_error;
vb@201
  1404
                    return GPG_ERR_GENERAL;
vb@201
  1405
                }
vb@203
  1406
                write(fd, handle->date_ref, 11);
vb@200
  1407
                handle->state = renew_quit;
vb@200
  1408
            }
vb@200
  1409
            break;
vb@200
  1410
vb@200
  1411
        case renew_quit:
vb@200
  1412
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  1413
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  1414
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  1415
                    handle->state = renew_error;
vb@201
  1416
                    return GPG_ERR_GENERAL;
vb@201
  1417
                }
vb@200
  1418
                write(fd, "quit\n", 5);
vb@200
  1419
                handle->state = renew_save;
vb@200
  1420
            }
vb@200
  1421
            break;
vb@200
  1422
vb@200
  1423
        case renew_save:
vb@200
  1424
            if (statuscode == GPGME_STATUS_GET_BOOL) {
vb@201
  1425
                assert(strcmp(args, "keyedit.save.okay") == 0);
vb@201
  1426
                if (strcmp(args, "keyedit.save.okay")) {
vb@201
  1427
                    handle->state = renew_error;
vb@201
  1428
                    return GPG_ERR_GENERAL;
vb@201
  1429
                }
vb@200
  1430
                write(fd, "Y\n", 2);
vb@200
  1431
                handle->state = renew_exit;
vb@200
  1432
            }
vb@200
  1433
            break;
vb@200
  1434
vb@200
  1435
        case renew_exit:
vb@200
  1436
            break;
vb@200
  1437
vb@200
  1438
        case renew_error:
vb@200
  1439
            return GPG_ERR_GENERAL;
vb@200
  1440
    }
vb@200
  1441
vb@200
  1442
    return GPG_ERR_NO_ERROR;
vb@200
  1443
}
vb@200
  1444
vb@200
  1445
static ssize_t _nullwriter(
vb@200
  1446
        void *_handle,
vb@200
  1447
        const void *buffer,
vb@200
  1448
        size_t size
vb@200
  1449
    )
vb@200
  1450
{
vb@200
  1451
    return size;
vb@200
  1452
}
vb@200
  1453
vb@201
  1454
PEP_STATUS pgp_renew_key(
vb@201
  1455
        PEP_SESSION session,
vb@201
  1456
        const char *fpr,
vb@201
  1457
        const timestamp *ts
vb@201
  1458
    )
vb@200
  1459
{
vb@200
  1460
    PEP_STATUS status = PEP_STATUS_OK;
vb@200
  1461
    gpgme_error_t gpgme_error;
vb@200
  1462
    gpgme_key_t key;
vb@200
  1463
    gpgme_data_t output;
vb@201
  1464
    renew_state handle;
vb@203
  1465
    char date_text[12];
vb@200
  1466
vb@200
  1467
    assert(session);
vb@200
  1468
    assert(fpr);
vb@200
  1469
vb@201
  1470
    memset(&handle, 0, sizeof(renew_state));
vb@203
  1471
    snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
vb@201
  1472
            ts->tm_mon + 1, ts->tm_mday);
vb@201
  1473
    handle.date_ref = date_text;
vb@200
  1474
vb@200
  1475
    status = find_single_key(session, fpr, &key);
vb@200
  1476
    if (status != PEP_STATUS_OK)
vb@200
  1477
        return status;
vb@200
  1478
vb@200
  1479
    struct gpgme_data_cbs data_cbs;
vb@200
  1480
    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
vb@200
  1481
    data_cbs.write = _nullwriter;
vb@220
  1482
    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
vb@200
  1483
vb@220
  1484
    gpgme_error = gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
vb@200
  1485
            output);
vb@200
  1486
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@200
  1487
vb@200
  1488
    gpg.gpgme_data_release(output);
vb@200
  1489
    gpg.gpgme_key_unref(key);
vb@200
  1490
vb@200
  1491
    return PEP_STATUS_OK;
vb@200
  1492
}
vb@200
  1493
vb@211
  1494
typedef struct _revoke_state {
vb@211
  1495
    enum {
vb@211
  1496
        revoke_command = 0,
vb@211
  1497
        revoke_approve,
vb@211
  1498
        revoke_reason_code,
vb@211
  1499
        revoke_reason_text,
vb@211
  1500
        revoke_reason_ok,
vb@211
  1501
        revoke_quit,
vb@211
  1502
        revoke_save,
vb@211
  1503
        revoke_exit,
vb@211
  1504
        revoke_error = -1
vb@211
  1505
    } state;
vb@211
  1506
    const char *reason_ref;
vb@211
  1507
} revoke_state;
vb@211
  1508
vb@211
  1509
static bool isemptystring(const char *str)
vb@211
  1510
{
vb@211
  1511
    if (str == NULL)
vb@211
  1512
        return true;
vb@211
  1513
vb@211
  1514
    for (; str; str++) {
vb@211
  1515
        if (*str != ' ' && *str != '\t' && *str != '\n')
vb@211
  1516
            return false;
vb@211
  1517
    }
vb@211
  1518
vb@211
  1519
    return true;
vb@211
  1520
}
vb@211
  1521
vb@211
  1522
static gpgme_error_t revoke_fsm(
vb@211
  1523
        void *_handle,
vb@211
  1524
        gpgme_status_code_t statuscode,
vb@211
  1525
        const char *args,
vb@211
  1526
        int fd
vb@211
  1527
    )
vb@211
  1528
{
vb@211
  1529
    revoke_state *handle = _handle;
vb@211
  1530
vb@211
  1531
    switch (handle->state) {
vb@211
  1532
        case revoke_command:
vb@211
  1533
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@211
  1534
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@211
  1535
                if (strcmp(args, "keyedit.prompt")) {
vb@211
  1536
                    handle->state = revoke_error;
vb@211
  1537
                    return GPG_ERR_GENERAL;
vb@211
  1538
                }
vb@211
  1539
                write(fd, "revkey\n", 7);
vb@211
  1540
                handle->state = revoke_approve;
vb@211
  1541
            }
vb@211
  1542
            break;
vb@211
  1543
vb@211
  1544
        case revoke_approve:
vb@211
  1545
            if (statuscode == GPGME_STATUS_GET_BOOL) {
vb@211
  1546
                assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
vb@211
  1547
                if (strcmp(args, "keyedit.revoke.subkey.okay")) {
vb@211
  1548
                    handle->state = revoke_error;
vb@211
  1549
                    return GPG_ERR_GENERAL;
vb@211
  1550
                }
vb@211
  1551
                write(fd, "Y\n", 2);
vb@211
  1552
                handle->state = revoke_reason_code;
vb@211
  1553
            }
vb@211
  1554
            break;
vb@211
  1555
vb@211
  1556
        case revoke_reason_code:
vb@211
  1557
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@211
  1558
                assert(strcmp(args, "ask_revocation_reason.code") == 0);
vb@211
  1559
                if (strcmp(args, "ask_revocation_reason.code")) {
vb@211
  1560
                    handle->state = revoke_error;
vb@211
  1561
                    return GPG_ERR_GENERAL;
vb@211
  1562
                }
vb@211
  1563
                write(fd, "1\n", 2);
vb@211
  1564
                handle->state = revoke_reason_text;
vb@211
  1565
            }
vb@211
  1566
            break;
vb@211
  1567
vb@211
  1568
        case revoke_reason_text:
vb@211
  1569
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@211
  1570
                assert(strcmp(args, "ask_revocation_reason.text") == 0);
vb@211
  1571
                if (strcmp(args, "ask_revocation_reason.text")) {
vb@211
  1572
                    handle->state = revoke_error;
vb@211
  1573
                    return GPG_ERR_GENERAL;
vb@211
  1574
                }
vb@213
  1575
                // BUG: issues when reason given
vb@213
  1576
                // Assertion failed: (gpg->cmd.code), function command_handler,
vb@213
  1577
                // file engine-gpg.c, line 662.
vb@213
  1578
                //
vb@213
  1579
                // if (isemptystring(handle->reason_ref)) {
vb@211
  1580
                    write(fd, "\n", 1);
vb@213
  1581
                // }
vb@213
  1582
                // else {
vb@213
  1583
                //     size_t len = strlen(handle->reason_ref);
vb@213
  1584
                //     write(fd, handle->reason_ref, len);
vb@213
  1585
                //     if (handle->reason_ref[len - 1] == '\n')
vb@213
  1586
                //         write(fd, "\n", 1);
vb@213
  1587
                //     else
vb@213
  1588
                //         write(fd, "\n\n", 2);
vb@213
  1589
                // }
vb@211
  1590
                handle->state = revoke_reason_ok;
vb@211
  1591
            }
vb@211
  1592
            break;
vb@211
  1593
vb@211
  1594
        case revoke_reason_ok:
vb@211
  1595
            if (statuscode == GPGME_STATUS_GET_BOOL) {
vb@211
  1596
                assert(strcmp(args, "ask_revocation_reason.okay") == 0);
vb@211
  1597
                if (strcmp(args, "ask_revocation_reason.okay")) {
vb@211
  1598
                    handle->state = revoke_error;
vb@211
  1599
                    return GPG_ERR_GENERAL;
vb@211
  1600
                }
vb@211
  1601
                write(fd, "Y\n", 2);
vb@211
  1602
                handle->state = revoke_quit;
vb@211
  1603
            }
vb@211
  1604
            break;
vb@211
  1605
vb@211
  1606
        case revoke_quit:
vb@211
  1607
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@211
  1608
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@211
  1609
                if (strcmp(args, "keyedit.prompt")) {
vb@211
  1610
                    handle->state = revoke_error;
vb@211
  1611
                    return GPG_ERR_GENERAL;
vb@211
  1612
                }
vb@211
  1613
                write(fd, "quit\n", 5);
vb@211
  1614
                handle->state = revoke_save;
vb@211
  1615
            }
vb@211
  1616
            break;
vb@211
  1617
vb@211
  1618
        case revoke_save:
vb@211
  1619
            if (statuscode == GPGME_STATUS_GET_BOOL) {
vb@211
  1620
                assert(strcmp(args, "keyedit.save.okay") == 0);
vb@211
  1621
                if (strcmp(args, "keyedit.save.okay")) {
vb@211
  1622
                    handle->state = revoke_error;
vb@211
  1623
                    return GPG_ERR_GENERAL;
vb@211
  1624
                }
vb@211
  1625
                write(fd, "Y\n", 2);
vb@211
  1626
                handle->state = revoke_exit;
vb@211
  1627
            }
vb@211
  1628
            break;
vb@211
  1629
vb@211
  1630
        case revoke_exit:
vb@211
  1631
            break;
vb@211
  1632
vb@211
  1633
        case revoke_error:
vb@211
  1634
            return GPG_ERR_GENERAL;
vb@211
  1635
    }
vb@211
  1636
vb@211
  1637
    return GPG_ERR_NO_ERROR;
vb@211
  1638
}
vb@211
  1639
vb@211
  1640
PEP_STATUS pgp_revoke_key(
vb@211
  1641
        PEP_SESSION session,
vb@211
  1642
        const char *fpr,
vb@211
  1643
        const char *reason
vb@211
  1644
    )
vb@200
  1645
{
vb@200
  1646
    PEP_STATUS status = PEP_STATUS_OK;
vb@211
  1647
    gpgme_error_t gpgme_error;
vb@200
  1648
    gpgme_key_t key;
vb@211
  1649
    gpgme_data_t output;
vb@211
  1650
    revoke_state handle;
vb@211
  1651
vb@200
  1652
    assert(session);
vb@200
  1653
    assert(fpr);
vb@200
  1654
vb@211
  1655
    memset(&handle, 0, sizeof(revoke_state));
vb@213
  1656
    handle.reason_ref = reason;
vb@211
  1657
vb@200
  1658
    status = find_single_key(session, fpr, &key);
vb@200
  1659
    if (status != PEP_STATUS_OK)
vb@200
  1660
        return status;
vb@200
  1661
vb@211
  1662
    struct gpgme_data_cbs data_cbs;
vb@211
  1663
    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
vb@211
  1664
    data_cbs.write = _nullwriter;
vb@220
  1665
    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
vb@211
  1666
vb@220
  1667
    gpgme_error = gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
vb@211
  1668
            output);
vb@211
  1669
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@211
  1670
vb@211
  1671
    gpg.gpgme_data_release(output);
vb@211
  1672
    gpg.gpgme_key_unref(key);
vb@211
  1673
vb@200
  1674
    return PEP_STATUS_OK;
vb@200
  1675
}
vb@200
  1676
vb@214
  1677
PEP_STATUS pgp_key_expired(
vb@214
  1678
        PEP_SESSION session,
vb@214
  1679
        const char *fpr,
vb@214
  1680
        bool *expired
vb@214
  1681
    )
vb@214
  1682
{
vb@214
  1683
    PEP_STATUS status = PEP_STATUS_OK;
vb@214
  1684
    gpgme_key_t key;
vb@214
  1685
vb@214
  1686
    assert(session);
vb@214
  1687
    assert(fpr);
vb@214
  1688
    assert(expired);
vb@214
  1689
vb@214
  1690
    *expired = false;
vb@214
  1691
vb@214
  1692
    status = find_single_key(session, fpr, &key);
vb@214
  1693
    assert(status != PEP_OUT_OF_MEMORY);
vb@214
  1694
    if (status != PEP_STATUS_OK)
vb@214
  1695
        return status;
vb@214
  1696
vb@214
  1697
    *expired = key->subkeys->expired;
vb@214
  1698
    gpg.gpgme_key_unref(key);
vb@214
  1699
    return PEP_STATUS_OK;
vb@214
  1700
}
vb@214
  1701