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