src/pgp_gpg.c
author vb
Sat, 21 Feb 2015 16:55:43 +0100
changeset 62 ad5e484720e1
parent 47 5ed7e8a4f0c2
child 63 f5b2641f4ae7
permissions -rw-r--r--
signal() and init()
vb@62
     1
#include <errno.h>
vb@62
     2
vb@24
     3
#include "pgp_gpg.h"
vb@24
     4
#include "pEp_internal.h"
vb@24
     5
vb@62
     6
#include "wrappers.h"
vb@62
     7
vb@45
     8
#define _GPGERR(X) ((X) & 0xffffL)
vb@45
     9
vb@24
    10
static bool ensure_keyserver()
vb@24
    11
{
vb@24
    12
    static char buf[MAX_LINELENGTH];
vb@24
    13
    int n;
vb@62
    14
    FILE *f;
vb@62
    15
    int r;
vb@62
    16
vb@62
    17
    f = Fopen(gpg_conf(), "r");
vb@62
    18
    if (errno == ENOMEM)
vb@62
    19
        return false;
vb@24
    20
vb@24
    21
    if (f != NULL) {
vb@62
    22
        do {
vb@62
    23
            char * s;
vb@62
    24
vb@62
    25
            do {
vb@62
    26
                s = fgets(buf, MAX_LINELENGTH, f);
vb@62
    27
            } while (s == NULL && !feof(f) && errno == EINTR);
vb@62
    28
vb@62
    29
            assert(s);
vb@62
    30
            if (s == NULL)
vb@62
    31
                return false;
vb@62
    32
vb@24
    33
            if (s && !feof(f)) {
vb@24
    34
                char * t = strtok(s, " ");
vb@24
    35
                if (t && strcmp(t, "keyserver") == 0) {
vb@62
    36
                    do {
vb@62
    37
                        r = fclose(f);
vb@62
    38
                    } while (r == -1 && errno == EINTR);
vb@62
    39
                    assert(r == 0);
vb@24
    40
                    return true;
vb@24
    41
                }
vb@24
    42
            }
vb@62
    43
        } while (!feof(f));
vb@62
    44
        do {
vb@62
    45
            f = freopen(gpg_conf(), "a", f);
vb@62
    46
        } while (f == NULL && errno == EINTR);
vb@24
    47
    }
vb@24
    48
    else {
vb@62
    49
        do {
vb@62
    50
            f = fopen(gpg_conf(), "w");
vb@62
    51
        } while (f == NULL && errno == EINTR);
vb@24
    52
    }
vb@24
    53
vb@24
    54
    assert(f);
vb@24
    55
    if (f == NULL)
vb@24
    56
        return false;
vb@24
    57
vb@62
    58
    do {
vb@62
    59
        n = fprintf(f, "keyserver %s\n", DEFAULT_KEYSERVER);
vb@62
    60
    } while (n < 0 && errno == EINTR);
vb@24
    61
    assert(n >= 0);
vb@62
    62
vb@62
    63
    do {
vb@62
    64
        r = fclose(f);
vb@62
    65
    } while (r == -1 && errno == EINTR);
vb@62
    66
    assert(r == 0);
vb@24
    67
vb@24
    68
    return true;
vb@24
    69
}
vb@24
    70
vb@62
    71
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
vb@24
    72
{
vb@62
    73
    static struct gpg_s gpg;
vb@62
    74
    static void *gpgme;
vb@24
    75
    gpgme_error_t gpgme_error;
vb@62
    76
    bool bResult;
vb@62
    77
    
vb@62
    78
    if (in_first) {
vb@62
    79
        bResult = ensure_keyserver();
vb@62
    80
        assert(bResult);
vb@24
    81
vb@62
    82
        gpgme = dlopen(LIBGPGME, RTLD_LAZY);
vb@62
    83
        if (gpgme == NULL) {
vb@62
    84
            return PEP_INIT_CANNOT_LOAD_GPGME;
vb@62
    85
        }
vb@62
    86
vb@62
    87
        memset(&gpg, 0, sizeof(struct gpg_s));
vb@62
    88
vb@62
    89
        gpg.gpgme_set_locale
vb@62
    90
            = (gpgme_set_locale_t) (intptr_t) dlsym(gpgme,
vb@62
    91
            "gpgme_set_locale");
vb@62
    92
        assert(gpg.gpgme_set_locale);
vb@62
    93
vb@62
    94
        gpg.gpgme_check
vb@62
    95
            = (gpgme_check_version_t) (intptr_t) dlsym(gpgme,
vb@62
    96
            "gpgme_check_version");
vb@62
    97
        assert(gpg.gpgme_check);
vb@62
    98
vb@62
    99
        gpg.gpgme_new
vb@62
   100
            = (gpgme_new_t) (intptr_t) dlsym(gpgme, "gpgme_new");
vb@62
   101
        assert(gpg.gpgme_new);
vb@62
   102
vb@62
   103
        gpg.gpgme_release
vb@62
   104
            = (gpgme_release_t) (intptr_t) dlsym(gpgme, "gpgme_release");
vb@62
   105
        assert(gpg.gpgme_release);
vb@62
   106
vb@62
   107
        gpg.gpgme_set_protocol
vb@62
   108
            = (gpgme_set_protocol_t) (intptr_t) dlsym(gpgme,
vb@62
   109
            "gpgme_set_protocol");
vb@62
   110
        assert(gpg.gpgme_set_protocol);
vb@62
   111
vb@62
   112
        gpg.gpgme_set_armor
vb@62
   113
            = (gpgme_set_armor_t) (intptr_t) dlsym(gpgme,
vb@62
   114
            "gpgme_set_armor");
vb@62
   115
        assert(gpg.gpgme_set_armor);
vb@62
   116
vb@62
   117
        gpg.gpgme_data_new
vb@62
   118
            = (gpgme_data_new_t) (intptr_t) dlsym(gpgme,
vb@62
   119
            "gpgme_data_new");
vb@62
   120
        assert(gpg.gpgme_data_new);
vb@62
   121
vb@62
   122
        gpg.gpgme_data_new_from_mem
vb@62
   123
            = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(gpgme,
vb@62
   124
            "gpgme_data_new_from_mem");
vb@62
   125
        assert(gpg.gpgme_data_new_from_mem);
vb@62
   126
vb@62
   127
        gpg.gpgme_data_release
vb@62
   128
            = (gpgme_data_release_t) (intptr_t) dlsym(gpgme,
vb@62
   129
            "gpgme_data_release");
vb@62
   130
        assert(gpg.gpgme_data_release);
vb@62
   131
vb@62
   132
        gpg.gpgme_data_identify
vb@62
   133
            = (gpgme_data_identify_t) (intptr_t) dlsym(gpgme,
vb@62
   134
            "gpgme_data_identify");
vb@62
   135
        assert(gpg.gpgme_data_identify);
vb@62
   136
vb@62
   137
        gpg.gpgme_data_seek
vb@62
   138
            = (gpgme_data_seek_t) (intptr_t) dlsym(gpgme,
vb@62
   139
            "gpgme_data_seek");
vb@62
   140
        assert(gpg.gpgme_data_seek);
vb@62
   141
vb@62
   142
        gpg.gpgme_data_read
vb@62
   143
            = (gpgme_data_read_t) (intptr_t) dlsym(gpgme,
vb@62
   144
            "gpgme_data_read");
vb@62
   145
        assert(gpg.gpgme_data_read);
vb@62
   146
vb@62
   147
        gpg.gpgme_op_decrypt
vb@62
   148
            = (gpgme_op_decrypt_t) (intptr_t) dlsym(gpgme,
vb@62
   149
            "gpgme_op_decrypt");
vb@62
   150
        assert(gpg.gpgme_op_decrypt);
vb@62
   151
vb@62
   152
        gpg.gpgme_op_verify
vb@62
   153
            = (gpgme_op_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   154
            "gpgme_op_verify");
vb@62
   155
        assert(gpg.gpgme_op_verify);
vb@62
   156
vb@62
   157
        gpg.gpgme_op_decrypt_verify
vb@62
   158
            = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   159
            "gpgme_op_decrypt_verify");
vb@62
   160
        assert(gpg.gpgme_op_decrypt_verify);
vb@62
   161
vb@62
   162
        gpg.gpgme_op_decrypt_result
vb@62
   163
            = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(gpgme,
vb@62
   164
            "gpgme_op_decrypt_result");
vb@62
   165
        assert(gpg.gpgme_op_decrypt_result);
vb@62
   166
vb@62
   167
        gpg.gpgme_op_encrypt_sign
vb@62
   168
            = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(gpgme,
vb@62
   169
            "gpgme_op_encrypt_sign");
vb@62
   170
        assert(gpg.gpgme_op_encrypt_sign);
vb@62
   171
vb@62
   172
        gpg.gpgme_op_verify_result
vb@62
   173
            = (gpgme_op_verify_result_t) (intptr_t) dlsym(gpgme,
vb@62
   174
            "gpgme_op_verify_result");
vb@62
   175
        assert(gpg.gpgme_op_verify_result);
vb@62
   176
vb@62
   177
        gpg.gpgme_signers_clear
vb@62
   178
            = (gpgme_signers_clear_t) (intptr_t) dlsym(gpgme,
vb@62
   179
            "gpgme_signers_clear");
vb@62
   180
        assert(gpg.gpgme_signers_clear);
vb@62
   181
vb@62
   182
        gpg.gpgme_signers_add
vb@62
   183
            = (gpgme_signers_add_t) (intptr_t) dlsym(gpgme,
vb@62
   184
            "gpgme_signers_add");
vb@62
   185
        assert(gpg.gpgme_signers_add);
vb@62
   186
vb@62
   187
        gpg.gpgme_get_key
vb@62
   188
            = (gpgme_get_key_t) (intptr_t) dlsym(gpgme, "gpgme_get_key");
vb@62
   189
        assert(gpg.gpgme_get_key);
vb@62
   190
vb@62
   191
        gpg.gpgme_op_genkey
vb@62
   192
            = (gpgme_op_genkey_t) (intptr_t) dlsym(gpgme,
vb@62
   193
            "gpgme_op_genkey");
vb@62
   194
        assert(gpg.gpgme_op_genkey);
vb@62
   195
vb@62
   196
        gpg.gpgme_op_genkey_result
vb@62
   197
            = (gpgme_op_genkey_result_t) (intptr_t) dlsym(gpgme,
vb@62
   198
            "gpgme_op_genkey_result");
vb@62
   199
        assert(gpg.gpgme_op_genkey_result);
vb@62
   200
vb@62
   201
        gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
vb@62
   202
            dlsym(gpgme, "gpgme_op_delete");
vb@62
   203
        assert(gpg.gpgme_op_delete);
vb@62
   204
vb@62
   205
        gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
vb@62
   206
            dlsym(gpgme, "gpgme_op_import");
vb@62
   207
        assert(gpg.gpgme_op_import);
vb@62
   208
vb@62
   209
        gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
vb@62
   210
            dlsym(gpgme, "gpgme_op_export");
vb@62
   211
        assert(gpg.gpgme_op_export);
vb@62
   212
vb@62
   213
        gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
vb@62
   214
            dlsym(gpgme, "gpgme_set_keylist_mode");
vb@62
   215
        assert(gpg.gpgme_set_keylist_mode);
vb@62
   216
vb@62
   217
        gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
vb@62
   218
            dlsym(gpgme, "gpgme_get_keylist_mode");
vb@62
   219
        assert(gpg.gpgme_get_keylist_mode);
vb@62
   220
vb@62
   221
        gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
vb@62
   222
            dlsym(gpgme, "gpgme_op_keylist_start");
vb@62
   223
        assert(gpg.gpgme_op_keylist_start);
vb@62
   224
vb@62
   225
        gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
vb@62
   226
            dlsym(gpgme, "gpgme_op_keylist_next");
vb@62
   227
        assert(gpg.gpgme_op_keylist_next);
vb@62
   228
vb@62
   229
        gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
vb@62
   230
            dlsym(gpgme, "gpgme_op_keylist_end");
vb@62
   231
        assert(gpg.gpgme_op_keylist_end);
vb@62
   232
vb@62
   233
        gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
vb@62
   234
            dlsym(gpgme, "gpgme_op_import_keys");
vb@62
   235
        assert(gpg.gpgme_op_import_keys);
vb@62
   236
vb@62
   237
        gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
vb@62
   238
            dlsym(gpgme, "gpgme_key_ref");
vb@62
   239
        assert(gpg.gpgme_key_ref);
vb@62
   240
vb@62
   241
        gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
vb@62
   242
            dlsym(gpgme, "gpgme_key_unref");
vb@62
   243
        assert(gpg.gpgme_key_unref);
vb@62
   244
vb@62
   245
        gpg.version = gpg.gpgme_check(NULL);
vb@62
   246
        
vb@62
   247
        if (strcmp(setlocale(LC_ALL, NULL), "C") == 0)
vb@62
   248
            setlocale(LC_ALL, "");
vb@62
   249
vb@62
   250
        gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
vb@62
   251
#ifdef LC_MESSAGES // Windoze
vb@62
   252
        gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
vb@62
   253
#endif
vb@24
   254
    }
vb@24
   255
vb@62
   256
    session->gpg = &gpg;
vb@24
   257
vb@62
   258
    gpgme_error = gpg.gpgme_new(&session->ctx);
vb@45
   259
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   260
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   261
        return PEP_INIT_GPGME_INIT_FAILED;
vb@24
   262
    }
vb@46
   263
    assert(session->ctx);
vb@24
   264
vb@62
   265
    gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
vb@45
   266
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   267
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   268
vb@62
   269
    gpg.gpgme_set_armor(session->ctx, 1);
vb@24
   270
vb@24
   271
    return PEP_STATUS_OK;
vb@24
   272
}
vb@24
   273
vb@62
   274
void pgp_release(PEP_SESSION session, bool out_last)
vb@24
   275
{
vb@62
   276
    if (session->ctx) {
vb@62
   277
        session->gpg->gpgme_release(session->ctx);
vb@62
   278
        session->ctx = NULL;
vb@62
   279
    }
vb@62
   280
vb@62
   281
    if (out_last) {
vb@62
   282
        if (session->gpgme) {
vb@62
   283
            dlclose(session->gpgme);
vb@62
   284
            session->gpgme = NULL;
vb@62
   285
        }
vb@62
   286
    }
vb@24
   287
}
vb@24
   288
vb@24
   289
PEP_STATUS pgp_decrypt_and_verify(
vb@24
   290
    PEP_SESSION session, const char *ctext, size_t csize,
vb@24
   291
    char **ptext, size_t *psize, stringlist_t **keylist
vb@24
   292
    )
vb@24
   293
{
vb@24
   294
    PEP_STATUS result;
vb@24
   295
    gpgme_error_t gpgme_error;
vb@24
   296
    gpgme_data_t cipher, plain;
vb@24
   297
    gpgme_data_type_t dt;
vb@24
   298
vb@24
   299
    stringlist_t *_keylist = NULL;
vb@24
   300
    int i_key = 0;
vb@24
   301
vb@46
   302
    assert(session);
vb@24
   303
    assert(ctext);
vb@24
   304
    assert(csize);
vb@24
   305
    assert(ptext);
vb@24
   306
    assert(psize);
vb@24
   307
    assert(keylist);
vb@24
   308
vb@24
   309
    *ptext = NULL;
vb@24
   310
    *psize = 0;
vb@24
   311
    *keylist = NULL;
vb@24
   312
vb@62
   313
    gpgme_error = session->gpg->gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
vb@45
   314
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   315
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   316
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   317
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   318
            return PEP_OUT_OF_MEMORY;
vb@24
   319
        else
vb@24
   320
            return PEP_UNKNOWN_ERROR;
vb@24
   321
    }
vb@24
   322
vb@62
   323
    gpgme_error = session->gpg->gpgme_data_new(&plain);
vb@45
   324
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   325
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   326
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@62
   327
        session->gpg->gpgme_data_release(cipher);
vb@24
   328
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   329
            return PEP_OUT_OF_MEMORY;
vb@24
   330
        else
vb@24
   331
            return PEP_UNKNOWN_ERROR;
vb@24
   332
    }
vb@24
   333
vb@62
   334
    dt = session->gpg->gpgme_data_identify(cipher);
vb@24
   335
    switch (dt) {
vb@24
   336
    case GPGME_DATA_TYPE_PGP_SIGNED:
vb@24
   337
    case GPGME_DATA_TYPE_PGP_OTHER:
vb@62
   338
        gpgme_error = session->gpg->gpgme_op_decrypt_verify(session->ctx, cipher,
vb@24
   339
            plain);
vb@45
   340
        gpgme_error = _GPGERR(gpgme_error);
vb@24
   341
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
   342
        assert(gpgme_error != GPG_ERR_NO_DATA);
vb@24
   343
vb@24
   344
        switch (gpgme_error) {
vb@24
   345
        case GPG_ERR_NO_ERROR:
vb@24
   346
        {
vb@24
   347
            gpgme_verify_result_t gpgme_verify_result;
vb@24
   348
            char *_buffer = NULL;
vb@24
   349
            size_t reading;
vb@62
   350
            size_t length = session->gpg->gpgme_data_seek(plain, 0, SEEK_END);
vb@24
   351
            gpgme_signature_t gpgme_signature;
vb@24
   352
vb@24
   353
            assert(length != -1);
vb@62
   354
            session->gpg->gpgme_data_seek(plain, 0, SEEK_SET);
vb@24
   355
vb@24
   356
            // TODO: make things less memory consuming
vb@24
   357
            // the following algorithm allocates memory for the complete
vb@24
   358
            // text
vb@24
   359
vb@24
   360
            _buffer = malloc(length + 1);
vb@24
   361
            assert(_buffer);
vb@24
   362
            if (_buffer == NULL) {
vb@62
   363
                session->gpg->gpgme_data_release(plain);
vb@62
   364
                session->gpg->gpgme_data_release(cipher);
vb@24
   365
                return PEP_OUT_OF_MEMORY;
vb@24
   366
            }
vb@24
   367
vb@62
   368
            reading = session->gpg->gpgme_data_read(plain, _buffer, length);
vb@24
   369
            assert(length == reading);
vb@24
   370
vb@24
   371
            gpgme_verify_result =
vb@62
   372
                session->gpg->gpgme_op_verify_result(session->ctx);
vb@24
   373
            assert(gpgme_verify_result);
vb@24
   374
            gpgme_signature = gpgme_verify_result->signatures;
vb@24
   375
vb@24
   376
            if (gpgme_signature) {
vb@24
   377
                stringlist_t *k;
vb@24
   378
                _keylist = new_stringlist(NULL);
vb@24
   379
                assert(_keylist);
vb@24
   380
                if (_keylist == NULL) {
vb@62
   381
                    session->gpg->gpgme_data_release(plain);
vb@62
   382
                    session->gpg->gpgme_data_release(cipher);
vb@24
   383
                    free(_buffer);
vb@24
   384
                    return PEP_OUT_OF_MEMORY;
vb@24
   385
                }
vb@24
   386
                k = _keylist;
vb@24
   387
vb@24
   388
                result = PEP_DECRYPTED_AND_VERIFIED;
vb@24
   389
                do {
vb@24
   390
                    switch (gpgme_signature->status) {
vb@24
   391
                    case GPG_ERR_NO_ERROR:
vb@24
   392
                        k = stringlist_add(k, gpgme_signature->fpr);
vb@24
   393
                        break;
vb@24
   394
                    case GPG_ERR_CERT_REVOKED:
vb@24
   395
                    case GPG_ERR_BAD_SIGNATURE:
vb@24
   396
                        result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@24
   397
                        break;
vb@24
   398
                    case GPG_ERR_SIG_EXPIRED:
vb@24
   399
                    case GPG_ERR_KEY_EXPIRED:
vb@24
   400
                    case GPG_ERR_NO_PUBKEY:
vb@24
   401
                        k = stringlist_add(k, gpgme_signature->fpr);
vb@24
   402
                        if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@24
   403
                            result = PEP_DECRYPTED;
vb@24
   404
                        break;
vb@24
   405
                    case GPG_ERR_GENERAL:
vb@24
   406
                        break;
vb@24
   407
                    default:
vb@24
   408
                        if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@24
   409
                            result = PEP_DECRYPTED;
vb@24
   410
                        break;
vb@24
   411
                    }
vb@24
   412
                } while ((gpgme_signature = gpgme_signature->next));
vb@24
   413
            }
vb@24
   414
            else {
vb@24
   415
                result = PEP_DECRYPTED;
vb@24
   416
            }
vb@24
   417
vb@24
   418
            if (result == PEP_DECRYPTED_AND_VERIFIED
vb@24
   419
                || result == PEP_DECRYPTED) {
vb@24
   420
                *ptext = _buffer;
vb@24
   421
                *psize = reading;
vb@24
   422
                (*ptext)[*psize] = 0; // safeguard for naive users
vb@24
   423
                *keylist = _keylist;
vb@24
   424
            }
vb@24
   425
            else {
vb@24
   426
                free_stringlist(_keylist);
vb@24
   427
                free(_buffer);
vb@24
   428
            }
vb@24
   429
            break;
vb@24
   430
        }
vb@24
   431
        case GPG_ERR_DECRYPT_FAILED:
vb@24
   432
            result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   433
            break;
vb@24
   434
        case GPG_ERR_BAD_PASSPHRASE:
vb@24
   435
            NOT_IMPLEMENTED;
vb@24
   436
        default:
vb@24
   437
        {
vb@62
   438
            gpgme_decrypt_result_t gpgme_decrypt_result = session->gpg->gpgme_op_decrypt_result(session->ctx);
vb@24
   439
            result = PEP_DECRYPT_NO_KEY;
vb@24
   440
vb@24
   441
            if (gpgme_decrypt_result != NULL) {
vb@24
   442
                if (gpgme_decrypt_result->unsupported_algorithm)
vb@24
   443
                    *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
vb@24
   444
                else
vb@24
   445
                    *keylist = new_stringlist("");
vb@24
   446
                assert(*keylist);
vb@24
   447
                if (*keylist == NULL) {
vb@24
   448
                    result = PEP_OUT_OF_MEMORY;
vb@24
   449
                    break;
vb@24
   450
                }
vb@24
   451
                stringlist_t *_keylist = *keylist;
vb@24
   452
                for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
vb@24
   453
                    _keylist = stringlist_add(_keylist, r->keyid);
vb@24
   454
                    assert(_keylist);
vb@24
   455
                    if (_keylist == NULL) {
vb@24
   456
                        free_stringlist(*keylist);
vb@24
   457
                        *keylist = NULL;
vb@24
   458
                        result = PEP_OUT_OF_MEMORY;
vb@24
   459
                        break;
vb@24
   460
                    }
vb@24
   461
                }
vb@24
   462
                if (result == PEP_OUT_OF_MEMORY)
vb@24
   463
                    break;
vb@24
   464
            }
vb@24
   465
        }
vb@24
   466
        }
vb@24
   467
        break;
vb@24
   468
vb@24
   469
    default:
vb@24
   470
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   471
    }
vb@24
   472
vb@62
   473
    session->gpg->gpgme_data_release(plain);
vb@62
   474
    session->gpg->gpgme_data_release(cipher);
vb@24
   475
    return result;
vb@24
   476
}
vb@24
   477
vb@24
   478
PEP_STATUS pgp_verify_text(
vb@24
   479
    PEP_SESSION session, const char *text, size_t size,
vb@24
   480
    const char *signature, size_t sig_size, stringlist_t **keylist
vb@24
   481
    )
vb@24
   482
{
vb@24
   483
    PEP_STATUS result;
vb@24
   484
    gpgme_error_t gpgme_error;
vb@24
   485
    gpgme_data_t d_text, d_sig;
vb@24
   486
    stringlist_t *_keylist;
vb@24
   487
vb@24
   488
    assert(session);
vb@24
   489
    assert(text);
vb@24
   490
    assert(size);
vb@24
   491
    assert(signature);
vb@24
   492
    assert(sig_size);
vb@24
   493
    assert(keylist);
vb@24
   494
vb@24
   495
    *keylist = NULL;
vb@24
   496
vb@62
   497
    gpgme_error = session->gpg->gpgme_data_new_from_mem(&d_text, text, size, 0);
vb@45
   498
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   499
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   500
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   501
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   502
            return PEP_OUT_OF_MEMORY;
vb@24
   503
        else
vb@24
   504
            return PEP_UNKNOWN_ERROR;
vb@24
   505
    }
vb@24
   506
vb@62
   507
    gpgme_error = session->gpg->gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
vb@45
   508
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   509
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   510
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@62
   511
        session->gpg->gpgme_data_release(d_text);
vb@24
   512
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   513
            return PEP_OUT_OF_MEMORY;
vb@24
   514
        else
vb@24
   515
            return PEP_UNKNOWN_ERROR;
vb@24
   516
    }
vb@24
   517
vb@62
   518
    gpgme_error = session->gpg->gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
vb@45
   519
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   520
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
   521
vb@24
   522
    switch (gpgme_error) {
vb@24
   523
    case GPG_ERR_NO_ERROR:
vb@24
   524
    {
vb@24
   525
        gpgme_verify_result_t gpgme_verify_result;
vb@24
   526
        gpgme_signature_t gpgme_signature;
vb@24
   527
vb@24
   528
        gpgme_verify_result =
vb@62
   529
            session->gpg->gpgme_op_verify_result(session->ctx);
vb@24
   530
        assert(gpgme_verify_result);
vb@24
   531
        gpgme_signature = gpgme_verify_result->signatures;
vb@24
   532
vb@24
   533
        if (gpgme_signature) {
vb@24
   534
            stringlist_t *k;
vb@24
   535
            _keylist = new_stringlist(NULL);
vb@24
   536
            assert(_keylist);
vb@24
   537
            if (_keylist == NULL) {
vb@62
   538
                session->gpg->gpgme_data_release(d_text);
vb@62
   539
                session->gpg->gpgme_data_release(d_sig);
vb@24
   540
                return PEP_OUT_OF_MEMORY;
vb@24
   541
            }
vb@24
   542
            k = _keylist;
vb@24
   543
vb@24
   544
            result = PEP_VERIFIED;
vb@24
   545
            do {
vb@24
   546
                k = stringlist_add(k, gpgme_signature->fpr);
vb@24
   547
                if (k == NULL) {
vb@24
   548
                    free_stringlist(_keylist);
vb@62
   549
                    session->gpg->gpgme_data_release(d_text);
vb@62
   550
                    session->gpg->gpgme_data_release(d_sig);
vb@24
   551
                    return PEP_OUT_OF_MEMORY;
vb@24
   552
                }
vb@24
   553
                if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
vb@24
   554
                    if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
vb@24
   555
                        || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
vb@24
   556
                        if (result == PEP_VERIFIED
vb@24
   557
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
   558
                            result = PEP_UNENCRYPTED;
vb@24
   559
                    }
vb@24
   560
                    else {
vb@24
   561
                        result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@24
   562
                        break;
vb@24
   563
                    }
vb@24
   564
                }
vb@24
   565
                else {
vb@24
   566
                    if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
vb@24
   567
                        if (result == PEP_VERIFIED)
vb@24
   568
                            result = PEP_VERIFIED_AND_TRUSTED;
vb@24
   569
                    }
vb@24
   570
                    if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
vb@24
   571
                        // good
vb@24
   572
                    }
vb@24
   573
                    else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
vb@24
   574
                        result = PEP_VERIFY_NO_KEY;
vb@24
   575
                    }
vb@24
   576
                    else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
vb@24
   577
                        if (result == PEP_VERIFIED
vb@24
   578
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
   579
                            result = PEP_UNENCRYPTED;
vb@24
   580
                    }
vb@24
   581
                    else {
vb@24
   582
                        // do nothing
vb@24
   583
                    }
vb@24
   584
                }
vb@24
   585
            } while ((gpgme_signature = gpgme_signature->next));
vb@24
   586
            *keylist = _keylist;
vb@24
   587
        }
vb@24
   588
        else {
vb@24
   589
            result = PEP_UNENCRYPTED;
vb@24
   590
        }
vb@24
   591
        break;
vb@24
   592
    }
vb@24
   593
        break;
vb@24
   594
    case GPG_ERR_NO_DATA:
vb@24
   595
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   596
        break;
vb@24
   597
    case GPG_ERR_INV_VALUE:
vb@24
   598
    default:
vb@24
   599
        result = PEP_UNKNOWN_ERROR;
vb@24
   600
        break;
vb@24
   601
    }
vb@24
   602
vb@62
   603
    session->gpg->gpgme_data_release(d_text);
vb@62
   604
    session->gpg->gpgme_data_release(d_sig);
vb@24
   605
vb@24
   606
    return result;
vb@24
   607
}
vb@24
   608
vb@24
   609
PEP_STATUS pgp_encrypt_and_sign(
vb@24
   610
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
vb@24
   611
    size_t psize, char **ctext, size_t *csize
vb@24
   612
    )
vb@24
   613
{
vb@24
   614
    PEP_STATUS result;
vb@24
   615
    gpgme_error_t gpgme_error;
vb@24
   616
    gpgme_data_t plain, cipher;
vb@24
   617
    gpgme_key_t *rcpt;
vb@24
   618
    gpgme_encrypt_flags_t flags;
vb@24
   619
    const stringlist_t *_keylist;
vb@24
   620
    int i, j;
vb@24
   621
vb@46
   622
    assert(session);
vb@24
   623
    assert(keylist);
vb@24
   624
    assert(ptext);
vb@24
   625
    assert(psize);
vb@24
   626
    assert(ctext);
vb@24
   627
    assert(csize);
vb@24
   628
vb@24
   629
    *ctext = NULL;
vb@24
   630
    *csize = 0;
vb@24
   631
vb@62
   632
    gpgme_error = session->gpg->gpgme_data_new_from_mem(&plain, ptext, psize, 0);
vb@45
   633
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   634
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   635
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   636
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   637
            return PEP_OUT_OF_MEMORY;
vb@24
   638
        else
vb@24
   639
            return PEP_UNKNOWN_ERROR;
vb@24
   640
    }
vb@24
   641
vb@62
   642
    gpgme_error = session->gpg->gpgme_data_new(&cipher);
vb@45
   643
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   644
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   645
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@62
   646
        session->gpg->gpgme_data_release(plain);
vb@24
   647
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   648
            return PEP_OUT_OF_MEMORY;
vb@24
   649
        else
vb@24
   650
            return PEP_UNKNOWN_ERROR;
vb@24
   651
    }
vb@24
   652
vb@24
   653
    rcpt = (gpgme_key_t *) calloc(stringlist_length(keylist) + 1,
vb@24
   654
        sizeof(gpgme_key_t));
vb@24
   655
    assert(rcpt);
vb@24
   656
    if (rcpt == NULL) {
vb@62
   657
        session->gpg->gpgme_data_release(plain);
vb@62
   658
        session->gpg->gpgme_data_release(cipher);
vb@24
   659
        return PEP_OUT_OF_MEMORY;
vb@24
   660
    }
vb@24
   661
vb@62
   662
    session->gpg->gpgme_signers_clear(session->ctx);
vb@24
   663
vb@24
   664
    for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
vb@24
   665
        assert(_keylist->value);
vb@62
   666
        gpgme_error = session->gpg->gpgme_get_key(session->ctx, _keylist->value,
vb@24
   667
            &rcpt[i], 0);
vb@45
   668
        gpgme_error = _GPGERR(gpgme_error);
vb@24
   669
        assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
   670
vb@24
   671
        switch (gpgme_error) {
vb@24
   672
        case GPG_ERR_ENOMEM:
vb@24
   673
            for (j = 0; j<i; j++)
vb@62
   674
                session->gpg->gpgme_key_unref(rcpt[j]);
vb@24
   675
            free(rcpt);
vb@62
   676
            session->gpg->gpgme_data_release(plain);
vb@62
   677
            session->gpg->gpgme_data_release(cipher);
vb@24
   678
            return PEP_OUT_OF_MEMORY;
vb@24
   679
        case GPG_ERR_NO_ERROR:
vb@24
   680
            if (i == 0) {
vb@62
   681
                gpgme_error_t _gpgme_error = session->gpg->gpgme_signers_add(session->ctx, rcpt[0]);
vb@45
   682
                _gpgme_error = _GPGERR(_gpgme_error);
vb@24
   683
                assert(_gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   684
            }
vb@24
   685
            break;
vb@24
   686
        case GPG_ERR_EOF:
vb@24
   687
            for (j = 0; j<i; j++)
vb@62
   688
                session->gpg->gpgme_key_unref(rcpt[j]);
vb@24
   689
            free(rcpt);
vb@62
   690
            session->gpg->gpgme_data_release(plain);
vb@62
   691
            session->gpg->gpgme_data_release(cipher);
vb@24
   692
            return PEP_KEY_NOT_FOUND;
vb@24
   693
        case GPG_ERR_AMBIGUOUS_NAME:
vb@24
   694
            for (j = 0; j<i; j++)
vb@62
   695
                session->gpg->gpgme_key_unref(rcpt[j]);
vb@24
   696
            free(rcpt);
vb@62
   697
            session->gpg->gpgme_data_release(plain);
vb@62
   698
            session->gpg->gpgme_data_release(cipher);
vb@24
   699
            return PEP_KEY_HAS_AMBIG_NAME;
vb@24
   700
        default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
vb@24
   701
            // FPR is not a fingerprint or key ID
vb@24
   702
            for (j = 0; j<i; j++)
vb@62
   703
                session->gpg->gpgme_key_unref(rcpt[j]);
vb@24
   704
            free(rcpt);
vb@62
   705
            session->gpg->gpgme_data_release(plain);
vb@62
   706
            session->gpg->gpgme_data_release(cipher);
vb@24
   707
            return PEP_GET_KEY_FAILED;
vb@24
   708
        }
vb@24
   709
    }
vb@24
   710
vb@24
   711
    // TODO: remove that and replace with proper key management
vb@24
   712
    flags = GPGME_ENCRYPT_ALWAYS_TRUST;
vb@24
   713
vb@62
   714
    gpgme_error = session->gpg->gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
vb@24
   715
        plain, cipher);
vb@45
   716
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   717
    switch (gpgme_error) {
vb@24
   718
    case GPG_ERR_NO_ERROR:
vb@24
   719
    {
vb@24
   720
        char *_buffer = NULL;
vb@24
   721
        size_t reading;
vb@62
   722
        size_t length = session->gpg->gpgme_data_seek(cipher, 0, SEEK_END);
vb@24
   723
        assert(length != -1);
vb@62
   724
        session->gpg->gpgme_data_seek(cipher, 0, SEEK_SET);
vb@24
   725
vb@24
   726
        // TODO: make things less memory consuming
vb@24
   727
        // the following algorithm allocates a buffer for the complete text
vb@24
   728
vb@24
   729
        _buffer = (char *) malloc(length + 1);
vb@24
   730
        assert(_buffer);
vb@24
   731
        if (_buffer == NULL) {
vb@24
   732
            for (j = 0; j<stringlist_length(keylist); j++)
vb@62
   733
                session->gpg->gpgme_key_unref(rcpt[j]);
vb@24
   734
            free(rcpt);
vb@62
   735
            session->gpg->gpgme_data_release(plain);
vb@62
   736
            session->gpg->gpgme_data_release(cipher);
vb@24
   737
            return PEP_OUT_OF_MEMORY;
vb@24
   738
        }
vb@24
   739
vb@62
   740
        reading = session->gpg->gpgme_data_read(cipher, _buffer, length);
vb@24
   741
        assert(length == reading);
vb@24
   742
vb@24
   743
        *ctext = _buffer;
vb@24
   744
        *csize = reading;
vb@24
   745
        (*ctext)[*csize] = 0; // safeguard for naive users
vb@24
   746
        result = PEP_STATUS_OK;
vb@24
   747
        break;
vb@24
   748
    }
vb@24
   749
    default:
vb@24
   750
        result = PEP_UNKNOWN_ERROR;
vb@24
   751
    }
vb@24
   752
vb@24
   753
    for (j = 0; j<stringlist_length(keylist); j++)
vb@62
   754
        session->gpg->gpgme_key_unref(rcpt[j]);
vb@24
   755
    free(rcpt);
vb@62
   756
    session->gpg->gpgme_data_release(plain);
vb@62
   757
    session->gpg->gpgme_data_release(cipher);
vb@24
   758
    return result;
vb@24
   759
}
vb@24
   760
vb@24
   761
PEP_STATUS pgp_generate_keypair(
vb@24
   762
    PEP_SESSION session, pEp_identity *identity
vb@24
   763
    )
vb@24
   764
{
vb@24
   765
    gpgme_error_t gpgme_error;
vb@24
   766
    char *parms;
vb@24
   767
    const char *template =
vb@24
   768
        "<GnupgKeyParms format=\"internal\">\n"
vb@24
   769
        "Key-Type: RSA\n"
vb@24
   770
        "Key-Length: 4096\n"
vb@24
   771
        "Name-Real: %s\n"
vb@24
   772
        "Name-Email: %s\n"
vb@24
   773
        /* "Passphrase: %s\n" */
vb@24
   774
        "Expire-Date: 1y\n"
vb@24
   775
        "</GnupgKeyParms>\n";
vb@24
   776
    int result;
vb@24
   777
    gpgme_genkey_result_t gpgme_genkey_result;
vb@24
   778
vb@24
   779
    assert(session);
vb@24
   780
    assert(identity);
vb@24
   781
    assert(identity->address);
vb@24
   782
    assert(identity->fpr == NULL);
vb@24
   783
    assert(identity->username);
vb@24
   784
vb@24
   785
    parms = calloc(1, PARMS_MAX);
vb@24
   786
    assert(parms);
vb@24
   787
    if (parms == NULL)
vb@24
   788
        return PEP_OUT_OF_MEMORY;
vb@24
   789
vb@24
   790
    result = snprintf(parms, PARMS_MAX, template, identity->username,
vb@46
   791
        identity->address); // , session->passphrase);
vb@24
   792
    assert(result < PARMS_MAX);
vb@24
   793
    if (result >= PARMS_MAX) {
vb@24
   794
        free(parms);
vb@24
   795
        return PEP_BUFFER_TOO_SMALL;
vb@24
   796
    }
vb@24
   797
vb@62
   798
    gpgme_error = session->gpg->gpgme_op_genkey(session->ctx, parms, NULL, NULL);
vb@45
   799
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   800
    free(parms);
vb@24
   801
vb@24
   802
    switch (gpgme_error) {
vb@24
   803
    case GPG_ERR_NO_ERROR:
vb@24
   804
        break;
vb@24
   805
    case GPG_ERR_INV_VALUE:
vb@24
   806
        return PEP_ILLEGAL_VALUE;
vb@24
   807
    case GPG_ERR_GENERAL:
vb@24
   808
        return PEP_CANNOT_CREATE_KEY;
vb@24
   809
    default:
vb@24
   810
        assert(0);
vb@24
   811
        return PEP_UNKNOWN_ERROR;
vb@24
   812
    }
vb@24
   813
vb@62
   814
    gpgme_genkey_result = session->gpg->gpgme_op_genkey_result(session->ctx);
vb@24
   815
    assert(gpgme_genkey_result);
vb@24
   816
    assert(gpgme_genkey_result->fpr);
vb@24
   817
vb@24
   818
    identity->fpr = strdup(gpgme_genkey_result->fpr);
vb@24
   819
vb@24
   820
    return PEP_STATUS_OK;
vb@24
   821
}
vb@24
   822
vb@24
   823
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
vb@24
   824
{
vb@24
   825
    gpgme_error_t gpgme_error;
vb@24
   826
    gpgme_key_t key;
vb@24
   827
vb@24
   828
    assert(session);
vb@24
   829
    assert(fpr);
vb@24
   830
vb@62
   831
    gpgme_error = session->gpg->gpgme_get_key(session->ctx, fpr, &key, 0);
vb@45
   832
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   833
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
   834
    switch (gpgme_error) {
vb@24
   835
    case GPG_ERR_NO_ERROR:
vb@24
   836
        break;
vb@24
   837
    case GPG_ERR_EOF:
vb@24
   838
        return PEP_KEY_NOT_FOUND;
vb@24
   839
    case GPG_ERR_INV_VALUE:
vb@24
   840
        return PEP_ILLEGAL_VALUE;
vb@24
   841
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
   842
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
   843
    case GPG_ERR_ENOMEM:
vb@24
   844
        return PEP_OUT_OF_MEMORY;
vb@24
   845
    default:
vb@24
   846
        assert(0);
vb@24
   847
        return PEP_UNKNOWN_ERROR;
vb@24
   848
    }
vb@24
   849
vb@62
   850
    gpgme_error = session->gpg->gpgme_op_delete(session->ctx, key, 1);
vb@45
   851
    gpgme_error = _GPGERR(gpgme_error);
vb@62
   852
    session->gpg->gpgme_key_unref(key);
vb@24
   853
    switch (gpgme_error) {
vb@24
   854
    case GPG_ERR_NO_ERROR:
vb@24
   855
        break;
vb@24
   856
    case GPG_ERR_INV_VALUE:
vb@24
   857
        assert(0);
vb@24
   858
        return PEP_UNKNOWN_ERROR;
vb@24
   859
    case GPG_ERR_NO_PUBKEY:
vb@24
   860
        assert(0);
vb@24
   861
        return PEP_KEY_NOT_FOUND;
vb@24
   862
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
   863
        assert(0);
vb@24
   864
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
   865
    default:
vb@24
   866
        assert(0);
vb@24
   867
        return PEP_UNKNOWN_ERROR;
vb@24
   868
    }
vb@24
   869
vb@24
   870
    return PEP_STATUS_OK;
vb@24
   871
}
vb@24
   872
vb@24
   873
PEP_STATUS pgp_import_key(PEP_SESSION session, const char *key_data, size_t size)
vb@24
   874
{
vb@24
   875
    gpgme_error_t gpgme_error;
vb@24
   876
    gpgme_data_t dh;
vb@24
   877
vb@24
   878
    assert(session);
vb@24
   879
    assert(key_data);
vb@24
   880
vb@62
   881
    gpgme_error = session->gpg->gpgme_data_new_from_mem(&dh, key_data, size, 0);
vb@45
   882
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   883
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
   884
    switch (gpgme_error) {
vb@24
   885
    case GPG_ERR_NO_ERROR:
vb@24
   886
        break;
vb@24
   887
    case GPG_ERR_ENOMEM:
vb@24
   888
        return PEP_OUT_OF_MEMORY;
vb@24
   889
    case GPG_ERR_INV_VALUE:
vb@24
   890
        assert(0);
vb@24
   891
        return PEP_UNKNOWN_ERROR;
vb@24
   892
    default:
vb@24
   893
        assert(0);
vb@24
   894
        return PEP_UNKNOWN_ERROR;
vb@24
   895
    }
vb@24
   896
vb@62
   897
    gpgme_error = session->gpg->gpgme_op_import(session->ctx, dh);
vb@45
   898
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   899
    switch (gpgme_error) {
vb@24
   900
    case GPG_ERR_NO_ERROR:
vb@24
   901
        break;
vb@24
   902
    case GPG_ERR_INV_VALUE:
vb@24
   903
        assert(0);
vb@62
   904
        session->gpg->gpgme_data_release(dh);
vb@24
   905
        return PEP_UNKNOWN_ERROR;
vb@24
   906
    case GPG_ERR_NO_DATA:
vb@62
   907
        session->gpg->gpgme_data_release(dh);
vb@24
   908
        return PEP_ILLEGAL_VALUE;
vb@24
   909
    default:
vb@24
   910
        assert(0);
vb@62
   911
        session->gpg->gpgme_data_release(dh);
vb@24
   912
        return PEP_UNKNOWN_ERROR;
vb@24
   913
    }
vb@24
   914
vb@62
   915
    session->gpg->gpgme_data_release(dh);
vb@24
   916
    return PEP_STATUS_OK;
vb@24
   917
}
vb@24
   918
vb@24
   919
PEP_STATUS pgp_export_key(
vb@24
   920
    PEP_SESSION session, const char *fpr, char **key_data, size_t *size
vb@24
   921
    )
vb@24
   922
{
vb@24
   923
    gpgme_error_t gpgme_error;
vb@24
   924
    gpgme_data_t dh;
vb@24
   925
    size_t _size;
vb@24
   926
    char *buffer;
vb@24
   927
    int reading;
vb@24
   928
vb@24
   929
    assert(session);
vb@24
   930
    assert(fpr);
vb@24
   931
    assert(key_data);
vb@24
   932
    assert(size);
vb@24
   933
vb@62
   934
    gpgme_error = session->gpg->gpgme_data_new(&dh);
vb@45
   935
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   936
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
   937
    switch (gpgme_error) {
vb@24
   938
    case GPG_ERR_NO_ERROR:
vb@24
   939
        break;
vb@24
   940
    case GPG_ERR_ENOMEM:
vb@24
   941
        return PEP_OUT_OF_MEMORY;
vb@24
   942
    case GPG_ERR_INV_VALUE:
vb@24
   943
        assert(0);
vb@24
   944
        return PEP_UNKNOWN_ERROR;
vb@24
   945
    default:
vb@24
   946
        assert(0);
vb@24
   947
        return PEP_UNKNOWN_ERROR;
vb@24
   948
    }
vb@24
   949
vb@62
   950
    gpgme_error = session->gpg->gpgme_op_export(session->ctx, fpr,
vb@24
   951
        GPGME_EXPORT_MODE_MINIMAL, dh);
vb@45
   952
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   953
    switch (gpgme_error) {
vb@24
   954
    case GPG_ERR_NO_ERROR:
vb@24
   955
        break;
vb@24
   956
    case GPG_ERR_EOF:
vb@62
   957
        session->gpg->gpgme_data_release(dh);
vb@24
   958
        return PEP_KEY_NOT_FOUND;
vb@24
   959
    case GPG_ERR_INV_VALUE:
vb@24
   960
        assert(0);
vb@62
   961
        session->gpg->gpgme_data_release(dh);
vb@24
   962
        return PEP_UNKNOWN_ERROR;
vb@24
   963
    default:
vb@24
   964
        assert(0);
vb@62
   965
        session->gpg->gpgme_data_release(dh);
vb@24
   966
        return PEP_UNKNOWN_ERROR;
vb@24
   967
    };
vb@24
   968
vb@62
   969
    _size = session->gpg->gpgme_data_seek(dh, 0, SEEK_END);
vb@24
   970
    assert(_size != -1);
vb@62
   971
    session->gpg->gpgme_data_seek(dh, 0, SEEK_SET);
vb@24
   972
vb@24
   973
    buffer = malloc(_size + 1);
vb@24
   974
    assert(buffer);
vb@24
   975
    if (buffer == NULL) {
vb@62
   976
        session->gpg->gpgme_data_release(dh);
vb@24
   977
        return PEP_OUT_OF_MEMORY;
vb@24
   978
    }
vb@24
   979
vb@62
   980
    reading = session->gpg->gpgme_data_read(dh, buffer, _size);
vb@24
   981
    assert(_size == reading);
vb@24
   982
vb@24
   983
    // safeguard for the naive user
vb@24
   984
    buffer[_size] = 0;
vb@24
   985
vb@24
   986
    *key_data = buffer;
vb@24
   987
    *size = _size;
vb@24
   988
vb@62
   989
    session->gpg->gpgme_data_release(dh);
vb@24
   990
    return PEP_STATUS_OK;
vb@24
   991
}
vb@24
   992
vb@46
   993
static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
vb@24
   994
    gpgme_keylist_mode_t add_mode)
vb@24
   995
{
vb@24
   996
    gpgme_error_t gpgme_error;
vb@24
   997
    gpgme_keylist_mode_t mode;
vb@24
   998
vb@62
   999
    mode = session->gpg->gpgme_get_keylist_mode(session->ctx);
vb@24
  1000
vb@24
  1001
    mode &= ~remove_mode;
vb@24
  1002
    mode |= add_mode;
vb@24
  1003
vb@62
  1004
    gpgme_error = session->gpg->gpgme_set_keylist_mode(session->ctx, mode);
vb@45
  1005
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1006
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1007
}
vb@24
  1008
vb@24
  1009
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
vb@24
  1010
{
vb@24
  1011
    gpgme_error_t gpgme_error;
vb@24
  1012
    gpgme_key_t key;
vb@24
  1013
vb@24
  1014
    assert(session);
vb@24
  1015
    assert(pattern);
vb@24
  1016
vb@46
  1017
    _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
vb@24
  1018
vb@62
  1019
    gpgme_error = session->gpg->gpgme_op_keylist_start(session->ctx, pattern, 0);
vb@45
  1020
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1021
    switch (gpgme_error) {
vb@24
  1022
    case GPG_ERR_NO_ERROR:
vb@24
  1023
        break;
vb@24
  1024
    case GPG_ERR_INV_VALUE:
vb@24
  1025
        assert(0);
vb@47
  1026
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1027
        return PEP_UNKNOWN_ERROR;
vb@24
  1028
    default:
vb@47
  1029
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1030
        return PEP_GET_KEY_FAILED;
vb@24
  1031
    };
vb@24
  1032
vb@47
  1033
    gpgme_ctx_t import_ctx;
vb@62
  1034
    gpgme_error = session->gpg->gpgme_new(&import_ctx);
vb@47
  1035
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@47
  1036
vb@24
  1037
    do {
vb@62
  1038
        gpgme_error = session->gpg->gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1039
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1040
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1041
        switch (gpgme_error) {
vb@24
  1042
        case GPG_ERR_EOF:
vb@24
  1043
            break;
vb@24
  1044
        case GPG_ERR_NO_ERROR:
vb@24
  1045
        {
vb@24
  1046
            gpgme_error_t gpgme_error;
vb@24
  1047
            gpgme_key_t keys[2];
vb@24
  1048
vb@24
  1049
            keys[0] = key;
vb@24
  1050
            keys[1] = NULL;
vb@24
  1051
vb@62
  1052
            gpgme_error = session->gpg->gpgme_op_import_keys(import_ctx, keys);
vb@45
  1053
            gpgme_error = _GPGERR(gpgme_error);
vb@62
  1054
            session->gpg->gpgme_key_unref(key);
vb@24
  1055
            assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1056
            assert(gpgme_error != GPG_ERR_CONFLICT);
vb@24
  1057
        }
vb@24
  1058
            break;
vb@24
  1059
        case GPG_ERR_ENOMEM:
vb@62
  1060
            session->gpg->gpgme_op_keylist_end(session->ctx);
vb@62
  1061
            session->gpg->gpgme_release(import_ctx);
vb@47
  1062
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1063
            return PEP_OUT_OF_MEMORY;
vb@24
  1064
        default:
vb@62
  1065
            session->gpg->gpgme_op_keylist_end(session->ctx);
vb@62
  1066
            session->gpg->gpgme_release(import_ctx);
vb@47
  1067
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@46
  1068
            return PEP_UNKNOWN_ERROR;
vb@24
  1069
        };
vb@24
  1070
    } while (gpgme_error != GPG_ERR_EOF);
vb@24
  1071
vb@62
  1072
    session->gpg->gpgme_op_keylist_end(session->ctx);
vb@62
  1073
    session->gpg->gpgme_release(import_ctx);
vb@47
  1074
    _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1075
    return PEP_STATUS_OK;
vb@24
  1076
}
vb@24
  1077
vb@24
  1078
PEP_STATUS pgp_find_keys(
vb@24
  1079
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
vb@24
  1080
    )
vb@24
  1081
{
vb@24
  1082
    gpgme_error_t gpgme_error;
vb@24
  1083
    gpgme_key_t key;
vb@24
  1084
    stringlist_t *_keylist;
vb@24
  1085
    char *fpr;
vb@24
  1086
vb@24
  1087
    assert(session);
vb@24
  1088
    assert(pattern);
vb@24
  1089
    assert(keylist);
vb@24
  1090
vb@24
  1091
    *keylist = NULL;
vb@24
  1092
vb@62
  1093
    gpgme_error = session->gpg->gpgme_op_keylist_start(session->ctx, pattern, 0);
vb@45
  1094
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1095
    switch (gpgme_error) {
vb@24
  1096
    case GPG_ERR_NO_ERROR:
vb@24
  1097
        break;
vb@24
  1098
    case GPG_ERR_INV_VALUE:
vb@24
  1099
        assert(0);
vb@24
  1100
        return PEP_UNKNOWN_ERROR;
vb@24
  1101
    default:
vb@62
  1102
        session->gpg->gpgme_op_keylist_end(session->ctx);
vb@24
  1103
        return PEP_GET_KEY_FAILED;
vb@24
  1104
    };
vb@24
  1105
vb@24
  1106
    _keylist = new_stringlist(NULL);
vb@24
  1107
    stringlist_t *_k = _keylist;
vb@24
  1108
vb@24
  1109
    do {
vb@62
  1110
        gpgme_error = session->gpg->gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1111
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1112
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1113
        switch (gpgme_error) {
vb@24
  1114
        case GPG_ERR_EOF:
vb@24
  1115
            break;
vb@24
  1116
        case GPG_ERR_NO_ERROR:
vb@24
  1117
            assert(key);
vb@24
  1118
            assert(key->subkeys);
vb@24
  1119
            fpr = key->subkeys->fpr;
vb@24
  1120
            assert(fpr);
vb@24
  1121
            _k = stringlist_add(_k, fpr);
vb@24
  1122
            assert(_k);
vb@24
  1123
            if (_k != NULL)
vb@24
  1124
                break;
vb@24
  1125
        case GPG_ERR_ENOMEM:
vb@24
  1126
            free_stringlist(_keylist);
vb@62
  1127
            session->gpg->gpgme_op_keylist_end(session->ctx);
vb@24
  1128
            return PEP_OUT_OF_MEMORY;
vb@24
  1129
        default:
vb@62
  1130
            session->gpg->gpgme_op_keylist_end(session->ctx);
vb@46
  1131
            return PEP_UNKNOWN_ERROR;
vb@24
  1132
        };
vb@24
  1133
    } while (gpgme_error != GPG_ERR_EOF);
vb@24
  1134
vb@62
  1135
    session->gpg->gpgme_op_keylist_end(session->ctx);
vb@24
  1136
    *keylist = _keylist;
vb@24
  1137
    return PEP_STATUS_OK;
vb@24
  1138
}
vb@24
  1139
vb@24
  1140
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
vb@24
  1141
{
vb@24
  1142
    gpgme_error_t gpgme_error;
vb@24
  1143
vb@24
  1144
    assert(session);
vb@24
  1145
    assert(pattern);
vb@24
  1146
vb@62
  1147
    gpgme_error = session->gpg->gpgme_op_export(session->ctx, pattern,
vb@24
  1148
        GPGME_EXPORT_MODE_EXTERN, NULL);
vb@45
  1149
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1150
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1151
    if (gpgme_error == GPG_ERR_NO_ERROR)
vb@24
  1152
        return PEP_STATUS_OK;
vb@24
  1153
    else
vb@24
  1154
        return PEP_CANNOT_SEND_KEY;
vb@24
  1155
}
vb@24
  1156
vb@24
  1157
vb@24
  1158
PEP_STATUS pgp_get_key_rating(
vb@24
  1159
    PEP_SESSION session,
vb@24
  1160
    const char *fpr,
vb@24
  1161
    PEP_comm_type *comm_type
vb@24
  1162
    )
vb@24
  1163
{
vb@24
  1164
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
  1165
    gpgme_error_t gpgme_error;
vb@24
  1166
    gpgme_key_t key;
vb@24
  1167
vb@24
  1168
    assert(session);
vb@24
  1169
    assert(fpr);
vb@24
  1170
    assert(comm_type);
vb@24
  1171
vb@24
  1172
    *comm_type = PEP_ct_unknown;
vb@24
  1173
vb@62
  1174
    gpgme_error = session->gpg->gpgme_op_keylist_start(session->ctx, fpr, 0);
vb@45
  1175
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1176
    switch (gpgme_error) {
vb@24
  1177
    case GPG_ERR_NO_ERROR:
vb@24
  1178
        break;
vb@24
  1179
    case GPG_ERR_INV_VALUE:
vb@24
  1180
        assert(0);
vb@24
  1181
        return PEP_UNKNOWN_ERROR;
vb@24
  1182
    default:
vb@24
  1183
        return PEP_GET_KEY_FAILED;
vb@24
  1184
    };
vb@24
  1185
vb@62
  1186
    gpgme_error = session->gpg->gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1187
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1188
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1189
vb@24
  1190
    if (key == NULL) {
vb@62
  1191
        session->gpg->gpgme_op_keylist_end(session->ctx);
vb@24
  1192
        return PEP_KEY_NOT_FOUND;
vb@24
  1193
    }
vb@24
  1194
vb@24
  1195
    switch (key->protocol) {
vb@24
  1196
    case GPGME_PROTOCOL_OpenPGP:
vb@24
  1197
    case GPGME_PROTOCOL_DEFAULT:
vb@24
  1198
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
vb@24
  1199
        break;
vb@24
  1200
    case GPGME_PROTOCOL_CMS:
vb@24
  1201
        *comm_type = PEP_ct_CMS_unconfirmed;
vb@24
  1202
        break;
vb@24
  1203
    default:
vb@24
  1204
        *comm_type = PEP_ct_unknown;
vb@62
  1205
        session->gpg->gpgme_op_keylist_end(session->ctx);
vb@24
  1206
        return PEP_STATUS_OK;
vb@24
  1207
    }
vb@24
  1208
vb@24
  1209
    switch (gpgme_error) {
vb@24
  1210
    case GPG_ERR_EOF:
vb@24
  1211
        break;
vb@24
  1212
    case GPG_ERR_NO_ERROR:
vb@24
  1213
        assert(key);
vb@24
  1214
        assert(key->subkeys);
vb@24
  1215
        for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
vb@24
  1216
            if (sk->length < 1024)
vb@24
  1217
                *comm_type = PEP_ct_key_too_short;
vb@24
  1218
            else if (
vb@24
  1219
                (
vb@24
  1220
                (sk->pubkey_algo == GPGME_PK_RSA)
vb@24
  1221
                || (sk->pubkey_algo == GPGME_PK_RSA_E)
vb@24
  1222
                || (sk->pubkey_algo == GPGME_PK_RSA_S)
vb@24
  1223
                )
vb@24
  1224
                && sk->length == 1024
vb@24
  1225
                )
vb@24
  1226
                *comm_type = PEP_ct_OpenPGP_1024_RSA_unconfirmed;
vb@24
  1227
vb@24
  1228
            if (sk->invalid) {
vb@24
  1229
                *comm_type = PEP_ct_key_b0rken;
vb@24
  1230
                break;
vb@24
  1231
            }
vb@24
  1232
            if (sk->expired) {
vb@24
  1233
                *comm_type = PEP_ct_key_expired;
vb@24
  1234
                break;
vb@24
  1235
            }
vb@24
  1236
            if (sk->revoked) {
vb@24
  1237
                *comm_type = PEP_ct_key_revoked;
vb@24
  1238
                break;
vb@24
  1239
            }
vb@24
  1240
        }
vb@24
  1241
        break;
vb@24
  1242
    case GPG_ERR_ENOMEM:
vb@62
  1243
        session->gpg->gpgme_op_keylist_end(session->ctx);
vb@24
  1244
        *comm_type = PEP_ct_unknown;
vb@24
  1245
        return PEP_OUT_OF_MEMORY;
vb@24
  1246
    default:
vb@62
  1247
        session->gpg->gpgme_op_keylist_end(session->ctx);
vb@46
  1248
        return PEP_UNKNOWN_ERROR;
vb@24
  1249
    };
vb@24
  1250
vb@62
  1251
    session->gpg->gpgme_op_keylist_end(session->ctx);
vb@24
  1252
vb@24
  1253
    return status;
vb@24
  1254
}