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