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