src/pgp_gpg.c
author Krista Bennett <krista@pep-project.org>
Tue, 21 Aug 2018 12:19:04 +0200
branchENGINE-455
changeset 2860 978b009c17fa
parent 2859 53694809c009
permissions -rw-r--r--
ENGINE-455: abandoning and/or shelving for now; it appears gpgme only supports gpgconf's limited options. I don't think there's a way for us to insert additional options this way, so the clean solution isn't clean after all. Will talk to neal.
vb@1513
     1
// This file is under GNU General Public License 3.0
vb@1513
     2
// see LICENSE.txt
vb@1513
     3
vb@219
     4
#include "platform.h"
vb@130
     5
#include "pEp_internal.h"
vb@24
     6
#include "pgp_gpg.h"
vb@24
     7
vb@78
     8
#include <limits.h>
vb@78
     9
vb@62
    10
#include "wrappers.h"
vb@62
    11
vb@45
    12
#define _GPGERR(X) ((X) & 0xffffL)
vb@45
    13
vb@76
    14
static void *gpgme;
vb@76
    15
static struct gpg_s gpg;
vb@74
    16
krista@2858
    17
bloblist_t* make_conf_val(gpgme_conf_type_t type, const void* value) {    
krista@2858
    18
    char* strval = NULL;
krista@2858
    19
    void* otherval = NULL;
krista@2858
    20
    switch(type) {
krista@2858
    21
        case GPGME_CONF_NONE:
krista@2858
    22
            strval = (char*)calloc(1,1);
krista@2858
    23
            return new_bloblist(strval, 1, NULL, NULL); // BL placeholder 
krista@2858
    24
        case GPGME_CONF_STRING:
krista@2858
    25
        case GPGME_CONF_FILENAME:
krista@2858
    26
        case GPGME_CONF_LDAP_SERVER:
krista@2858
    27
        case GPGME_CONF_KEY_FPR:
krista@2858
    28
        case GPGME_CONF_PUB_KEY:
krista@2858
    29
        case GPGME_CONF_SEC_KEY:
krista@2858
    30
        case GPGME_CONF_ALIAS_LIST:
krista@2858
    31
            strval = strdup((const char*)value);
krista@2858
    32
            if (!strval)
krista@2858
    33
                return NULL;
krista@2858
    34
            return new_bloblist(strval, strlen(strval), NULL, NULL);
krista@2858
    35
        case GPGME_CONF_INT32:
krista@2858
    36
        case GPGME_CONF_UINT32:
krista@2858
    37
            otherval = calloc(1,4);
krista@2858
    38
            if (!memcpy(otherval, value, 4))
krista@2858
    39
                return NULL;
krista@2858
    40
            return new_bloblist(otherval, 4, NULL, NULL);
krista@2858
    41
        default:
krista@2858
    42
            return NULL;
krista@2858
    43
    }
krista@2858
    44
}
krista@2858
    45
krista@2858
    46
static bool ensure_config_values(PEP_SESSION session,
krista@2858
    47
                                 gpgme_conf_comp_t configs, 
krista@2858
    48
                                 const char* conf_name, 
krista@2858
    49
                                 stringlist_t *keys, 
krista@2858
    50
                                 bloblist_t *values)
krista@2858
    51
{    
krista@2860
    52
    gpgme_conf_comp_t curr_conf;
krista@2858
    53
    gpgme_conf_opt_t opt;
krista@2858
    54
    gpgme_error_t gpgme_error;
vb@78
    55
    stringlist_t *_k;
krista@2858
    56
    bloblist_t *_v;
krista@2858
    57
     
krista@2860
    58
    for (curr_conf = configs; curr_conf; curr_conf = curr_conf->next) {
krista@2858
    59
        if (strcmp(curr_conf->name, conf_name) == 0) {
krista@2858
    60
            for (_k = keys, _v = values; _k != NULL; _k = _k->next, _v = _v->next) {
krista@2858
    61
                for (opt = curr_conf->options; opt; opt = opt->next) {
krista@2858
    62
                    if (!(opt->flags & GPGME_CONF_GROUP) && strcmp(opt->name, _k->value) == 0) {
krista@2858
    63
                        if (!opt->value) {
krista@2858
    64
                            // Option has *not* been *explicitly* set. So we can set it.
krista@2858
    65
                            gpgme_conf_arg_t new_val;
krista@2858
    66
                            if (opt->type == GPGME_CONF_NONE)
krista@2859
    67
                                gpgme_error = gpg.gpgme_conf_arg_new(&new_val, opt->type, NULL);    
krista@2858
    68
                            else     
krista@2859
    69
                                gpgme_error = gpg.gpgme_conf_arg_new(&new_val, opt->type, _v->value);
krista@2858
    70
                                
krista@2858
    71
                            if (gpgme_error != GPG_ERR_NO_ERROR)
krista@2858
    72
                                return false;
krista@2858
    73
                                
krista@2859
    74
                            gpgme_error = gpg.gpgme_conf_opt_change(opt, 0, new_val);    
krista@2858
    75
                            if (gpgme_error != GPG_ERR_NO_ERROR)
krista@2858
    76
                                return false;
krista@2858
    77
                        }
krista@2858
    78
                        break;
krista@2858
    79
                    }
vb@24
    80
                }
vb@24
    81
            }
krista@2859
    82
            gpgme_error_t gpgme_err = gpg.gpgme_op_conf_save(session->ctx, curr_conf);
krista@2858
    83
            if (gpgme_err != GPG_ERR_NO_ERROR)
edouard@1803
    84
                return false;
krista@2858
    85
            return true;
vb@78
    86
        }
vb@78
    87
    }
krista@2858
    88
    return false;    
vb@24
    89
}
vb@24
    90
krista@2057
    91
char* _undot_address(const char* address) {
krista@2057
    92
    if (!address)
krista@2057
    93
        return NULL;
krista@2057
    94
    
krista@2057
    95
    int addr_len = strlen(address);
krista@2057
    96
    const char* at = strstr(address, "@");
krista@2057
    97
    
krista@2057
    98
    if (!at)
krista@2057
    99
        at = address + addr_len;
krista@2057
   100
        
krista@2066
   101
    char* retval = calloc(1, addr_len + 1);
krista@2057
   102
krista@2057
   103
    const char* addr_curr = address;
krista@2057
   104
    char* retval_curr = retval;
krista@2057
   105
    
krista@2057
   106
    while (addr_curr < at) {
krista@2057
   107
        if (*addr_curr == '.') {
krista@2057
   108
            addr_curr++;
krista@2057
   109
            continue;
krista@2057
   110
        }
krista@2057
   111
        *retval_curr = *addr_curr;
krista@2057
   112
        retval_curr++;
krista@2057
   113
        addr_curr++;
krista@2057
   114
    }
krista@2057
   115
    if (*addr_curr == '@')
krista@2057
   116
        strcat(retval_curr, addr_curr);
krista@2057
   117
    
krista@2057
   118
    return retval;
krista@2057
   119
}
krista@2057
   120
krista@2057
   121
static bool _email_heuristic_match(const char* str1, const char* str2) {
krista@2057
   122
    if (!str1 || !str2)
krista@2057
   123
        return false;
krista@2057
   124
        
krista@2057
   125
    if (strcasecmp(str1, str2) == 0)
krista@2057
   126
        return true;
krista@2057
   127
    
krista@2057
   128
    int len1 = strlen(str1);
krista@2057
   129
    int len2 = strlen(str2);
krista@2057
   130
    
krista@2057
   131
    // otherwise, we work against dotted usernames
krista@2057
   132
    const char* at1 = strstr(str1, "@");
krista@2057
   133
    const char* at2 = strstr(str2, "@");
krista@2057
   134
    
krista@2057
   135
    if (!at1)
krista@2057
   136
        at1 = str1 + len1;
krista@2057
   137
    
krista@2057
   138
    if (!at2)
krista@2057
   139
        at2 = str2 + len2;
krista@2057
   140
        
krista@2057
   141
    // This sucks. And is expensive. Here we go.
krista@2057
   142
    const char* str1_curr = str1;
krista@2057
   143
    const char* str2_curr = str2;
krista@2057
   144
    
krista@2057
   145
    while (str1_curr > at1 && str2_curr > at2) {
krista@2057
   146
        if (*str1_curr == '.') {
krista@2057
   147
            str1_curr++;
krista@2057
   148
            continue;
krista@2057
   149
        }
krista@2057
   150
krista@2057
   151
        if (*str2_curr == '.') {
krista@2057
   152
            str2_curr++;
krista@2057
   153
            continue;
krista@2057
   154
        }
krista@2057
   155
        
krista@2057
   156
        if (tolower(*str1_curr) != tolower(*str2_curr))
krista@2057
   157
            return false;
krista@2057
   158
        
krista@2057
   159
        str1_curr++;
krista@2057
   160
        str2_curr++;
krista@2057
   161
    }
krista@2057
   162
    if (str1_curr == at1 && str2_curr == at2)
krista@2057
   163
        return true;
krista@2057
   164
    
krista@2057
   165
    return false;
krista@2057
   166
}
krista@763
   167
krista@2461
   168
static PEP_STATUS _version_test(const char *s)
krista@2461
   169
{
krista@2461
   170
    char *_s = strdup(s);
krista@2461
   171
    if (!_s)
krista@2461
   172
        return PEP_OUT_OF_MEMORY;
krista@2461
   173
krista@2461
   174
    int major;
krista@2461
   175
    int minor;
krista@2461
   176
    int revision;
krista@2461
   177
krista@2461
   178
    char *lasts = NULL;
krista@2461
   179
    char *p = strtok_r(_s, ".", &lasts);
krista@2461
   180
    if (!p)
krista@2461
   181
        goto unsupported;
krista@2461
   182
    else
krista@2461
   183
        major = atoi(p);
krista@2461
   184
krista@2461
   185
    p = strtok_r(NULL, ".", &lasts);
krista@2461
   186
    if (!p)
krista@2461
   187
        goto unsupported;
krista@2461
   188
    else
krista@2461
   189
        minor = atoi(p);
krista@2461
   190
krista@2461
   191
    p = strtok_r(NULL, ".", &lasts);
krista@2461
   192
    if (!p)
krista@2461
   193
        goto unsupported;
krista@2461
   194
    else
krista@2461
   195
        revision = atoi(p);
krista@2461
   196
krista@2461
   197
    free(_s);
krista@2461
   198
    _s = NULL;
krista@2461
   199
krista@2461
   200
    if (major > 2)
krista@2461
   201
        return PEP_STATUS_OK;
krista@2461
   202
krista@2461
   203
    if (major == 2 && minor > 1)
krista@2461
   204
        return PEP_STATUS_OK;
krista@2461
   205
krista@2461
   206
    if (major == 2 && minor == 0 && revision == 30)
krista@2461
   207
        return PEP_STATUS_OK;
krista@2461
   208
krista@2461
   209
    if (major == 2 && minor == 1 && revision >= 17)
krista@2461
   210
        return PEP_STATUS_OK;
krista@2461
   211
krista@2461
   212
unsupported:
krista@2461
   213
    free(_s);
krista@2461
   214
    return PEP_INIT_UNSUPPORTED_GPG_VERSION;
krista@2461
   215
}
krista@2461
   216
vb@62
   217
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
vb@24
   218
{
vb@66
   219
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
   220
    gpgme_error_t gpgme_error;
vb@62
   221
    bool bResult;
krista@1426
   222
vb@62
   223
    if (in_first) {
krista@2858
   224
        
vb@62
   225
        gpgme = dlopen(LIBGPGME, RTLD_LAZY);
vb@62
   226
        if (gpgme == NULL) {
vb@66
   227
            status = PEP_INIT_CANNOT_LOAD_GPGME;
vb@66
   228
            goto pep_error;
vb@62
   229
        }
vb@62
   230
vb@62
   231
        memset(&gpg, 0, sizeof(struct gpg_s));
vb@62
   232
krista@2461
   233
        gpg.gpgme_get_engine_info
krista@2461
   234
            = (gpgme_get_engine_info_t) (intptr_t) dlsym(gpgme,
krista@2461
   235
            "gpgme_get_engine_info");
krista@2461
   236
        assert(gpg.gpgme_get_engine_info);
krista@2461
   237
krista@2461
   238
        gpgme_engine_info_t info;
krista@2461
   239
        int err = gpg.gpgme_get_engine_info(&info);
krista@2461
   240
        assert(err == GPG_ERR_NO_ERROR);
krista@2461
   241
        if (err != GPG_ERR_NO_ERROR)
krista@2461
   242
            return PEP_OUT_OF_MEMORY;
krista@2461
   243
krista@2461
   244
        assert(info->version);
krista@2461
   245
        if (!info->version)
krista@2461
   246
            return PEP_INIT_CANNOT_DETERMINE_GPG_VERSION;
krista@2461
   247
krista@2461
   248
        status = _version_test(info->version);
krista@2461
   249
        if (status != PEP_STATUS_OK)
krista@2461
   250
            return status;
krista@2461
   251
vb@62
   252
        gpg.gpgme_set_locale
vb@62
   253
            = (gpgme_set_locale_t) (intptr_t) dlsym(gpgme,
vb@62
   254
            "gpgme_set_locale");
vb@62
   255
        assert(gpg.gpgme_set_locale);
vb@62
   256
vb@62
   257
        gpg.gpgme_check
vb@62
   258
            = (gpgme_check_version_t) (intptr_t) dlsym(gpgme,
vb@62
   259
            "gpgme_check_version");
vb@62
   260
        assert(gpg.gpgme_check);
vb@62
   261
vb@62
   262
        gpg.gpgme_new
vb@62
   263
            = (gpgme_new_t) (intptr_t) dlsym(gpgme, "gpgme_new");
vb@62
   264
        assert(gpg.gpgme_new);
vb@62
   265
vb@62
   266
        gpg.gpgme_release
vb@62
   267
            = (gpgme_release_t) (intptr_t) dlsym(gpgme, "gpgme_release");
vb@62
   268
        assert(gpg.gpgme_release);
vb@62
   269
vb@62
   270
        gpg.gpgme_set_protocol
vb@62
   271
            = (gpgme_set_protocol_t) (intptr_t) dlsym(gpgme,
vb@62
   272
            "gpgme_set_protocol");
vb@62
   273
        assert(gpg.gpgme_set_protocol);
vb@62
   274
vb@62
   275
        gpg.gpgme_set_armor
vb@62
   276
            = (gpgme_set_armor_t) (intptr_t) dlsym(gpgme,
vb@62
   277
            "gpgme_set_armor");
vb@62
   278
        assert(gpg.gpgme_set_armor);
vb@62
   279
vb@62
   280
        gpg.gpgme_data_new
vb@62
   281
            = (gpgme_data_new_t) (intptr_t) dlsym(gpgme,
vb@62
   282
            "gpgme_data_new");
vb@62
   283
        assert(gpg.gpgme_data_new);
vb@62
   284
vb@62
   285
        gpg.gpgme_data_new_from_mem
vb@62
   286
            = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(gpgme,
vb@62
   287
            "gpgme_data_new_from_mem");
vb@62
   288
        assert(gpg.gpgme_data_new_from_mem);
vb@62
   289
vb@221
   290
        gpg.gpgme_data_new_from_cbs
vb@221
   291
            = (gpgme_data_new_from_cbs_t) (intptr_t) dlsym(gpgme,
vb@221
   292
            "gpgme_data_new_from_cbs");
vb@221
   293
        assert(gpg.gpgme_data_new_from_cbs);
vb@221
   294
vb@62
   295
        gpg.gpgme_data_release
vb@62
   296
            = (gpgme_data_release_t) (intptr_t) dlsym(gpgme,
vb@62
   297
            "gpgme_data_release");
vb@62
   298
        assert(gpg.gpgme_data_release);
vb@62
   299
vb@62
   300
        gpg.gpgme_data_identify
vb@62
   301
            = (gpgme_data_identify_t) (intptr_t) dlsym(gpgme,
vb@62
   302
            "gpgme_data_identify");
vb@62
   303
        assert(gpg.gpgme_data_identify);
vb@62
   304
vb@62
   305
        gpg.gpgme_data_seek
vb@62
   306
            = (gpgme_data_seek_t) (intptr_t) dlsym(gpgme,
vb@62
   307
            "gpgme_data_seek");
vb@62
   308
        assert(gpg.gpgme_data_seek);
vb@62
   309
vb@62
   310
        gpg.gpgme_data_read
vb@62
   311
            = (gpgme_data_read_t) (intptr_t) dlsym(gpgme,
vb@62
   312
            "gpgme_data_read");
vb@62
   313
        assert(gpg.gpgme_data_read);
vb@62
   314
vb@62
   315
        gpg.gpgme_op_decrypt
vb@62
   316
            = (gpgme_op_decrypt_t) (intptr_t) dlsym(gpgme,
vb@62
   317
            "gpgme_op_decrypt");
vb@62
   318
        assert(gpg.gpgme_op_decrypt);
vb@62
   319
vb@62
   320
        gpg.gpgme_op_verify
vb@62
   321
            = (gpgme_op_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   322
            "gpgme_op_verify");
vb@62
   323
        assert(gpg.gpgme_op_verify);
vb@62
   324
vb@62
   325
        gpg.gpgme_op_decrypt_verify
vb@62
   326
            = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   327
            "gpgme_op_decrypt_verify");
vb@62
   328
        assert(gpg.gpgme_op_decrypt_verify);
vb@62
   329
vb@62
   330
        gpg.gpgme_op_decrypt_result
vb@62
   331
            = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(gpgme,
vb@62
   332
            "gpgme_op_decrypt_result");
vb@62
   333
        assert(gpg.gpgme_op_decrypt_result);
vb@62
   334
vb@62
   335
        gpg.gpgme_op_encrypt_sign
vb@62
   336
            = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(gpgme,
vb@62
   337
            "gpgme_op_encrypt_sign");
vb@62
   338
        assert(gpg.gpgme_op_encrypt_sign);
vb@62
   339
krista@1639
   340
        gpg.gpgme_op_encrypt
krista@1639
   341
            = (gpgme_op_encrypt_t) (intptr_t) dlsym(gpgme,
krista@1639
   342
            "gpgme_op_encrypt");
krista@1639
   343
        assert(gpg.gpgme_op_encrypt);
krista@1639
   344
vb@62
   345
        gpg.gpgme_op_verify_result
vb@62
   346
            = (gpgme_op_verify_result_t) (intptr_t) dlsym(gpgme,
vb@62
   347
            "gpgme_op_verify_result");
vb@62
   348
        assert(gpg.gpgme_op_verify_result);
vb@62
   349
vb@62
   350
        gpg.gpgme_signers_clear
vb@62
   351
            = (gpgme_signers_clear_t) (intptr_t) dlsym(gpgme,
vb@62
   352
            "gpgme_signers_clear");
vb@62
   353
        assert(gpg.gpgme_signers_clear);
vb@62
   354
vb@62
   355
        gpg.gpgme_signers_add
vb@62
   356
            = (gpgme_signers_add_t) (intptr_t) dlsym(gpgme,
vb@62
   357
            "gpgme_signers_add");
vb@62
   358
        assert(gpg.gpgme_signers_add);
vb@62
   359
kgrothoff@1926
   360
        gpg.gpgme_set_passphrase_cb
kgrothoff@1926
   361
            = (gpgme_set_passphrase_cb_t) (intptr_t) dlsym(gpgme,
kgrothoff@1926
   362
            "gpgme_set_passphrase_cb");
kgrothoff@1926
   363
        assert(gpg.gpgme_set_passphrase_cb);
kgrothoff@1926
   364
vb@62
   365
        gpg.gpgme_get_key
vb@62
   366
            = (gpgme_get_key_t) (intptr_t) dlsym(gpgme, "gpgme_get_key");
vb@62
   367
        assert(gpg.gpgme_get_key);
krista@1920
   368
        
roker@2055
   369
        #ifdef GPGME_VERSION_NUMBER
krista@1921
   370
        #if (GPGME_VERSION_NUMBER >= 0x010700)
krista@1921
   371
                gpg.gpgme_op_createkey
krista@1921
   372
                    = (gpgme_op_createkey_t) (intptr_t) dlsym(gpgme,
krista@1921
   373
                    "gpgme_op_createkey");
krista@1921
   374
                assert(gpg.gpgme_op_createkey);
krista@1925
   375
                
krista@1925
   376
                gpg.gpgme_op_createsubkey
krista@1925
   377
                    = (gpgme_op_createsubkey_t) (intptr_t) dlsym(gpgme,
krista@1925
   378
                    "gpgme_op_createsubkey");
krista@1925
   379
                assert(gpg.gpgme_op_createsubkey);
krista@1925
   380
krista@1921
   381
        #endif
krista@1921
   382
        #endif
krista@1921
   383
        
vb@62
   384
        gpg.gpgme_op_genkey
vb@62
   385
            = (gpgme_op_genkey_t) (intptr_t) dlsym(gpgme,
vb@62
   386
            "gpgme_op_genkey");
vb@62
   387
        assert(gpg.gpgme_op_genkey);
vb@62
   388
vb@62
   389
        gpg.gpgme_op_genkey_result
vb@62
   390
            = (gpgme_op_genkey_result_t) (intptr_t) dlsym(gpgme,
vb@62
   391
            "gpgme_op_genkey_result");
vb@62
   392
        assert(gpg.gpgme_op_genkey_result);
vb@62
   393
vb@62
   394
        gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
vb@62
   395
            dlsym(gpgme, "gpgme_op_delete");
vb@62
   396
        assert(gpg.gpgme_op_delete);
vb@62
   397
vb@62
   398
        gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
vb@62
   399
            dlsym(gpgme, "gpgme_op_import");
vb@62
   400
        assert(gpg.gpgme_op_import);
vb@62
   401
Edouard@728
   402
        gpg.gpgme_op_import_result
Edouard@728
   403
            = (gpgme_op_import_result_t) (intptr_t) dlsym(gpgme,
Edouard@728
   404
            "gpgme_op_import_result");
Edouard@728
   405
        assert(gpg.gpgme_op_import_result);
Edouard@728
   406
vb@62
   407
        gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
vb@62
   408
            dlsym(gpgme, "gpgme_op_export");
vb@62
   409
        assert(gpg.gpgme_op_export);
vb@62
   410
vb@62
   411
        gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
vb@62
   412
            dlsym(gpgme, "gpgme_set_keylist_mode");
vb@62
   413
        assert(gpg.gpgme_set_keylist_mode);
vb@62
   414
vb@62
   415
        gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
vb@62
   416
            dlsym(gpgme, "gpgme_get_keylist_mode");
vb@62
   417
        assert(gpg.gpgme_get_keylist_mode);
vb@62
   418
vb@62
   419
        gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
vb@62
   420
            dlsym(gpgme, "gpgme_op_keylist_start");
vb@62
   421
        assert(gpg.gpgme_op_keylist_start);
vb@62
   422
vb@62
   423
        gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
vb@62
   424
            dlsym(gpgme, "gpgme_op_keylist_next");
vb@62
   425
        assert(gpg.gpgme_op_keylist_next);
vb@62
   426
vb@62
   427
        gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
vb@62
   428
            dlsym(gpgme, "gpgme_op_keylist_end");
vb@62
   429
        assert(gpg.gpgme_op_keylist_end);
vb@62
   430
vb@62
   431
        gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
vb@62
   432
            dlsym(gpgme, "gpgme_op_import_keys");
vb@62
   433
        assert(gpg.gpgme_op_import_keys);
vb@62
   434
vb@62
   435
        gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
vb@62
   436
            dlsym(gpgme, "gpgme_key_ref");
vb@62
   437
        assert(gpg.gpgme_key_ref);
vb@62
   438
vb@62
   439
        gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
vb@62
   440
            dlsym(gpgme, "gpgme_key_unref");
vb@62
   441
        assert(gpg.gpgme_key_unref);
vb@62
   442
vb@1387
   443
		gpg.gpgme_key_release = (gpgme_key_release_t)(intptr_t)
vb@1387
   444
			dlsym(gpgme, "gpgme_key_release");
vb@1387
   445
		assert(gpg.gpgme_key_release);
vb@1387
   446
vb@221
   447
        gpg.gpgme_op_edit = (gpgme_op_edit_t) (intptr_t)
vb@221
   448
            dlsym(gpgme, "gpgme_op_edit");
vb@221
   449
        assert(gpg.gpgme_op_edit);
vb@221
   450
vb@223
   451
        gpg.gpgme_io_write = (gpgme_io_write_t) (intptr_t)
vb@223
   452
            dlsym(gpgme, "gpgme_io_write");
vb@223
   453
        assert(gpg.gpgme_io_write);
vb@223
   454
krista@2859
   455
        gpg.gpgme_conf_arg_new = (gpgme_conf_arg_new_t) (intptr_t)
krista@2859
   456
            dlsym(gpgme, "gpgme_conf_arg_new");
krista@2859
   457
        assert(gpg.gpgme_conf_arg_new);
krista@2859
   458
krista@2859
   459
        gpg.gpgme_op_conf_load = (gpgme_op_conf_load_t) (intptr_t)
krista@2859
   460
            dlsym(gpgme, "gpgme_op_conf_load");
krista@2859
   461
        assert(gpg.gpgme_op_conf_load);
krista@2859
   462
krista@2859
   463
        gpg.gpgme_op_conf_save = (gpgme_op_conf_save_t) (intptr_t)
krista@2859
   464
            dlsym(gpgme, "gpgme_op_conf_save");
krista@2859
   465
        assert(gpg.gpgme_op_conf_save);
krista@2859
   466
krista@2859
   467
        gpg.gpgme_conf_opt_change = (gpgme_conf_opt_change_t) (intptr_t)
krista@2859
   468
            dlsym(gpgme, "gpgme_conf_opt_change");
krista@2859
   469
        assert(gpg.gpgme_conf_opt_change);
krista@2859
   470
krista@2859
   471
vb@62
   472
        gpg.version = gpg.gpgme_check(NULL);
krista@1426
   473
roker@876
   474
        const char * const cLocal = setlocale(LC_ALL, NULL);
Edouard@348
   475
        if (!cLocal || (strcmp(cLocal, "C") == 0))
vb@62
   476
            setlocale(LC_ALL, "");
vb@62
   477
vb@62
   478
        gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
vb@62
   479
#ifdef LC_MESSAGES // Windoze
vb@62
   480
        gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
vb@62
   481
#endif
krista@2859
   482
krista@2860
   483
    }
krista@2860
   484
krista@2860
   485
    gpg.gpgme_check(NULL);
krista@2860
   486
    gpgme_error = gpg.gpgme_new(&session->ctx);
krista@2860
   487
    gpgme_error = _GPGERR(gpgme_error);
krista@2860
   488
    if (gpgme_error != GPG_ERR_NO_ERROR) {
krista@2860
   489
        status = PEP_INIT_GPGME_INIT_FAILED;
krista@2860
   490
        goto pep_error;
krista@2860
   491
    }
krista@2860
   492
    assert(session->ctx);
krista@2860
   493
krista@2860
   494
    gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
krista@2860
   495
    gpgme_error = _GPGERR(gpgme_error);
krista@2860
   496
    assert(gpgme_error == GPG_ERR_NO_ERROR);
krista@2860
   497
krista@2860
   498
    gpg.gpgme_set_armor(session->ctx, 1);
krista@2860
   499
krista@2860
   500
    // Set up gpg and gpg-agent configs
krista@2860
   501
    if (in_first) {
krista@2859
   502
        gpgme_conf_comp_t configs; 
krista@2859
   503
krista@2859
   504
        gpgme_error = gpg.gpgme_op_conf_load(session->ctx, &configs);
krista@2859
   505
        if (gpgme_error != GPG_ERR_NO_ERROR) {
krista@2859
   506
            status = PEP_INIT_GPGME_INIT_FAILED;
krista@2859
   507
            goto pep_error;
krista@2859
   508
        }
krista@2859
   509
        
krista@2859
   510
        stringlist_t *conf_keys   = new_stringlist("keyserver");
krista@2859
   511
        bloblist_t   *conf_values = make_conf_val(GPGME_CONF_STRING,
krista@2859
   512
                                                  "hkp://keys.gnupg.net");
krista@2859
   513
krista@2859
   514
        bloblist_t** nextval = &(conf_values->next);
krista@2859
   515
                                                          
krista@2859
   516
        stringlist_add(conf_keys, "cert-digest-algo");
krista@2859
   517
        *nextval = make_conf_val(GPGME_CONF_STRING, "SHA256");
krista@2859
   518
        nextval = &((*nextval)->next);
krista@2859
   519
krista@2859
   520
        stringlist_add(conf_keys, "no-emit-version");
krista@2859
   521
        *nextval = make_conf_val(GPGME_CONF_NONE, NULL); // placeholder
krista@2859
   522
        nextval = &((*nextval)->next);
krista@2859
   523
        
krista@2859
   524
        stringlist_add(conf_keys, "no-comments");
krista@2859
   525
        *nextval = make_conf_val(GPGME_CONF_NONE, NULL); // placeholder
krista@2859
   526
        nextval = &((*nextval)->next);
krista@2859
   527
krista@2859
   528
        stringlist_add(conf_keys, "personal-cipher-preferences");
krista@2859
   529
        *nextval = make_conf_val(GPGME_CONF_STRING, "AES AES256 AES192 CAST5");
krista@2859
   530
        nextval = &((*nextval)->next);
krista@2859
   531
krista@2859
   532
        stringlist_add(conf_keys, "personal-digest-preferences");
krista@2859
   533
        *nextval = make_conf_val(GPGME_CONF_STRING, "SHA256 SHA512 SHA384 SHA224");
krista@2859
   534
        nextval = &((*nextval)->next);
krista@2859
   535
krista@2859
   536
        stringlist_add(conf_keys, "ignore-time-conflict");
krista@2859
   537
        *nextval = make_conf_val(GPGME_CONF_NONE, NULL); // placeholder
krista@2859
   538
        nextval = &((*nextval)->next);
krista@2859
   539
krista@2859
   540
        stringlist_add(conf_keys, "allow-freeform-uid");
krista@2859
   541
        *nextval = make_conf_val(GPGME_CONF_NONE, NULL); // placeholder
krista@2859
   542
        nextval = &((*nextval)->next);
krista@2859
   543
krista@2859
   544
        bResult = ensure_config_values(session, configs, 
krista@2859
   545
                                       "gpg", conf_keys, 
krista@2859
   546
                                       conf_values);
krista@2859
   547
        
krista@2859
   548
        free_stringlist(conf_keys);
krista@2859
   549
        free_bloblist(conf_values);
krista@2859
   550
krista@2859
   551
        assert(bResult);
krista@2859
   552
        if (!bResult) {
krista@2859
   553
            status = PEP_INIT_NO_GPG_HOME;
krista@2859
   554
            goto pep_error;
krista@2859
   555
        }
krista@2859
   556
krista@2859
   557
        uint32_t temp_uint = 300;
krista@2859
   558
        conf_keys = new_stringlist("default-cache-ttl");
krista@2859
   559
        conf_values = make_conf_val(GPGME_CONF_UINT32, &temp_uint);
krista@2859
   560
        nextval = &(conf_values->next);
krista@2859
   561
krista@2859
   562
        temp_uint = 1200;
krista@2859
   563
        stringlist_add(conf_keys, "max-cache-ttl");
krista@2859
   564
        *nextval = make_conf_val(GPGME_CONF_UINT32, &temp_uint);        
krista@2859
   565
        nextval = &((*nextval)->next);
krista@2859
   566
krista@2859
   567
        bResult = ensure_config_values(session, configs, 
krista@2859
   568
                                       "gpg-agent", conf_keys, 
krista@2859
   569
                                       conf_values);
krista@2859
   570
        
krista@2859
   571
        free_stringlist(conf_keys);
krista@2859
   572
        free_bloblist(conf_values);
krista@2859
   573
krista@2859
   574
        assert(bResult);
krista@2859
   575
        if (!bResult) {
krista@2859
   576
            status = PEP_INIT_CANNOT_CONFIG_GPG_AGENT;
krista@2859
   577
            goto pep_error;
krista@2859
   578
        }
vb@24
   579
    }
vb@24
   580
vb@24
   581
vb@24
   582
    return PEP_STATUS_OK;
vb@66
   583
vb@66
   584
pep_error:
vb@66
   585
    pgp_release(session, in_first);
vb@66
   586
    return status;
vb@24
   587
}
vb@24
   588
vb@62
   589
void pgp_release(PEP_SESSION session, bool out_last)
vb@24
   590
{
vb@62
   591
    if (session->ctx) {
vb@74
   592
        gpg.gpgme_release(session->ctx);
vb@62
   593
        session->ctx = NULL;
vb@62
   594
    }
vb@62
   595
vb@74
   596
    if (out_last)
vb@74
   597
        if (gpgme)
vb@74
   598
            dlclose(gpgme);
vb@24
   599
}
vb@24
   600
vb@24
   601
PEP_STATUS pgp_decrypt_and_verify(
vb@24
   602
    PEP_SESSION session, const char *ctext, size_t csize,
krista@1397
   603
    const char *dsigtext, size_t dsigsize,
vb@24
   604
    char **ptext, size_t *psize, stringlist_t **keylist
vb@24
   605
    )
vb@24
   606
{
vb@24
   607
    PEP_STATUS result;
vb@24
   608
    gpgme_error_t gpgme_error;
vb@24
   609
    gpgme_data_t cipher, plain;
vb@24
   610
    gpgme_data_type_t dt;
krista@1579
   611
    gpgme_decrypt_result_t gpgme_decrypt_result = NULL;
vb@24
   612
vb@24
   613
    stringlist_t *_keylist = NULL;
roker@723
   614
    //int i_key = 0;
vb@24
   615
vb@46
   616
    assert(session);
vb@24
   617
    assert(ctext);
vb@24
   618
    assert(csize);
vb@24
   619
    assert(ptext);
vb@24
   620
    assert(psize);
vb@24
   621
    assert(keylist);
vb@24
   622
vb@24
   623
    *ptext = NULL;
vb@24
   624
    *psize = 0;
vb@24
   625
    *keylist = NULL;
vb@24
   626
vb@74
   627
    gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
vb@45
   628
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   629
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   630
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   631
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   632
            return PEP_OUT_OF_MEMORY;
vb@24
   633
        else
vb@24
   634
            return PEP_UNKNOWN_ERROR;
vb@24
   635
    }
vb@24
   636
vb@74
   637
    gpgme_error = gpg.gpgme_data_new(&plain);
vb@45
   638
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   639
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   640
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   641
        gpg.gpgme_data_release(cipher);
vb@24
   642
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   643
            return PEP_OUT_OF_MEMORY;
vb@24
   644
        else
vb@24
   645
            return PEP_UNKNOWN_ERROR;
vb@24
   646
    }
vb@24
   647
krista@1579
   648
vb@74
   649
    dt = gpg.gpgme_data_identify(cipher);
vb@24
   650
    switch (dt) {
edouard@1421
   651
#if GPGME_VERSION_NUMBER > 0x010600
vb@1419
   652
    case GPGME_DATA_TYPE_PGP_ENCRYPTED:
edouard@1420
   653
#endif
vb@24
   654
    case GPGME_DATA_TYPE_PGP_SIGNED:
vb@24
   655
    case GPGME_DATA_TYPE_PGP_OTHER:
krista@1426
   656
        if (dsigtext) {
krista@1426
   657
            gpgme_error = gpg.gpgme_op_decrypt(session->ctx, cipher, plain);
krista@1426
   658
        }
krista@1426
   659
        else {
krista@1426
   660
            gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
krista@1426
   661
                plain);
krista@1426
   662
        }
vb@45
   663
        gpgme_error = _GPGERR(gpgme_error);
vb@24
   664
        assert(gpgme_error != GPG_ERR_INV_VALUE);
krista@2681
   665
//        assert(gpgme_error != GPG_ERR_NO_DATA);
vb@24
   666
vb@24
   667
        switch (gpgme_error) {
vb@344
   668
            case GPG_ERR_NO_ERROR:
vb@344
   669
            {
krista@2681
   670
                // EFail: We should get an MDC warning if there were modifications
krista@2681
   671
                //        and never make it here. So the decrypted text is not
krista@2681
   672
                //        returned regardless.
krista@1579
   673
                gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
krista@1591
   674
                /* NOW is when we have to process the decrypt_result, period.
krista@1591
   675
                   it is only valid until the next call on the context. */
krista@1591
   676
                   
krista@1591
   677
                gpgme_key_t key;
krista@1591
   678
                memset(&key,0,sizeof(key));
krista@1591
   679
                stringlist_t* recipient_keylist = new_stringlist(NULL);
krista@1592
   680
                if (!recipient_keylist) {
krista@1592
   681
                    gpg.gpgme_data_release(plain);
krista@1592
   682
                    gpg.gpgme_data_release(cipher);
krista@1592
   683
                    if (recipient_keylist)
krista@1592
   684
                        free_stringlist(recipient_keylist);
krista@1591
   685
                    return PEP_OUT_OF_MEMORY;
krista@1592
   686
                }
krista@1591
   687
               
krista@1591
   688
                if (gpgme_decrypt_result != NULL) {
krista@1591
   689
                    stringlist_t* _keylist = recipient_keylist;
krista@1591
   690
                    for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
krista@1591
   691
                        // GPGME may give subkey's fpr instead of primary key's fpr.
krista@1591
   692
                        // Therefore we ask for the primary fingerprint instead
krista@1591
   693
                        // we assume that gpgme_get_key can find key by subkey's fpr
krista@1591
   694
                        gpgme_error = gpg.gpgme_get_key(session->ctx,
krista@1591
   695
                            r->keyid, &key, 0);
krista@1591
   696
                        gpgme_error = _GPGERR(gpgme_error);
krista@1591
   697
                        assert(gpgme_error != GPG_ERR_ENOMEM);
krista@1591
   698
                        if (gpgme_error == GPG_ERR_ENOMEM) {
krista@1591
   699
                            free_stringlist(_keylist);
krista@1591
   700
                            result = PEP_OUT_OF_MEMORY;
krista@1591
   701
                        }
krista@1591
   702
                        // Primary key is given as the first subkey
krista@1591
   703
                        if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1591
   704
                            key && key->subkeys && key->subkeys->fpr
krista@1591
   705
                            && key->subkeys->fpr[0]) {
krista@1591
   706
                            _keylist = stringlist_add(_keylist, key->subkeys->fpr);
krista@1591
   707
 
krista@1591
   708
                            gpg.gpgme_key_unref(key);
krista@1591
   709
 
krista@1591
   710
                        }
krista@1591
   711
                    }
krista@1591
   712
                    assert(_keylist);
krista@1591
   713
                    if (_keylist == NULL) {
krista@1591
   714
                        free_stringlist(recipient_keylist);
krista@1591
   715
                        if (*keylist)
krista@1591
   716
                            free_stringlist(*keylist);
krista@1591
   717
                        *keylist = NULL;
krista@1591
   718
                        result = PEP_OUT_OF_MEMORY;
krista@1591
   719
                    }
krista@1591
   720
                } /* Ok, so now we have any recipients it was encrypted for
krista@1591
   721
                     in recipient_keylist */
krista@1591
   722
            
krista@1591
   723
                   
vb@344
   724
                gpgme_verify_result_t gpgme_verify_result;
vb@344
   725
                char *_buffer = NULL;
vb@344
   726
                size_t reading;
vb@344
   727
                size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
vb@344
   728
                gpgme_signature_t gpgme_signature;
vb@24
   729
vb@344
   730
                assert(length != -1);
vb@344
   731
                gpg.gpgme_data_seek(plain, 0, SEEK_SET);
vb@24
   732
vb@344
   733
                // TODO: make things less memory consuming
vb@344
   734
                // the following algorithm allocates memory for the complete
vb@344
   735
                // text
vb@24
   736
vb@344
   737
                _buffer = malloc(length + 1);
vb@344
   738
                assert(_buffer);
vb@344
   739
                if (_buffer == NULL) {
vb@74
   740
                    gpg.gpgme_data_release(plain);
vb@74
   741
                    gpg.gpgme_data_release(cipher);
krista@1591
   742
                    if (recipient_keylist)
krista@1591
   743
                        free_stringlist(recipient_keylist);
vb@24
   744
                    return PEP_OUT_OF_MEMORY;
vb@24
   745
                }
vb@24
   746
vb@344
   747
                reading = gpg.gpgme_data_read(plain, _buffer, length);
vb@344
   748
                assert(length == reading);
vb@24
   749
krista@1427
   750
                if (dsigtext) {  // Is this safe to do?
krista@1427
   751
                    gpgme_data_t sigdata;
krista@1427
   752
                    gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
krista@1427
   753
                                                dsigsize, 0);
vb@1434
   754
                    gpg.gpgme_op_verify(session->ctx, sigdata, plain, NULL);
krista@1431
   755
                    gpg.gpgme_data_release(sigdata);
krista@1427
   756
                }
krista@1426
   757
vb@344
   758
                gpgme_verify_result =
vb@344
   759
                    gpg.gpgme_op_verify_result(session->ctx);
vb@344
   760
                assert(gpgme_verify_result);
vb@344
   761
                gpgme_signature = gpgme_verify_result->signatures;
krista@1426
   762
krista@1584
   763
                if (!gpgme_signature) {
krista@1584
   764
                    // try cleartext sig verification
krista@1584
   765
                    gpg.gpgme_op_verify(session->ctx, plain, NULL, plain);
krista@1584
   766
                    gpgme_verify_result =
krista@1584
   767
                        gpg.gpgme_op_verify_result(session->ctx);
krista@1584
   768
                            assert(gpgme_verify_result);
roker@2055
   769
                    gpgme_signature = gpgme_verify_result->signatures;
krista@1584
   770
                }
krista@1584
   771
vb@344
   772
                if (gpgme_signature) {
vb@344
   773
                    stringlist_t *k;
vb@344
   774
                    _keylist = new_stringlist(NULL);
vb@24
   775
                    assert(_keylist);
vb@24
   776
                    if (_keylist == NULL) {
vb@344
   777
                        gpg.gpgme_data_release(plain);
vb@344
   778
                        gpg.gpgme_data_release(cipher);
vb@344
   779
                        free(_buffer);
vb@344
   780
                        return PEP_OUT_OF_MEMORY;
vb@344
   781
                    }
vb@344
   782
                    k = _keylist;
vb@344
   783
vb@344
   784
                    result = PEP_DECRYPTED_AND_VERIFIED;
krista@1427
   785
                    gpg.gpgme_check(NULL);
krista@1591
   786
                    do { /* get all signers and put them at the front off
krista@1591
   787
                            the keylist (likely only one) */
vb@344
   788
                        switch (_GPGERR(gpgme_signature->status)) {
vb@344
   789
                        case GPG_ERR_NO_ERROR:
Edouard@505
   790
                        {
krista@1426
   791
                            // Some versions of gpg returns signer's
Edouard@674
   792
                            // signing subkey fingerprint instead of
Edouard@674
   793
                            // signer's primary key fingerprint.
krista@1426
   794
                            // This is meant to get signer's primary
Edouard@674
   795
                            // key fingerprint, using subkey's.
Edouard@674
   796
Edouard@728
   797
                            gpgme_key_t key = NULL;
Edouard@505
   798
Edouard@505
   799
                            gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@505
   800
                                gpgme_signature->fpr, &key, 0);
Edouard@505
   801
                            gpgme_error = _GPGERR(gpgme_error);
Edouard@505
   802
                            assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@505
   803
                            if (gpgme_error == GPG_ERR_ENOMEM) {
Edouard@505
   804
                                free_stringlist(_keylist);
Edouard@505
   805
                                gpg.gpgme_data_release(plain);
Edouard@505
   806
                                gpg.gpgme_data_release(cipher);
Edouard@505
   807
                                free(_buffer);
Edouard@505
   808
                                return PEP_OUT_OF_MEMORY;
Edouard@505
   809
                            }
Edouard@505
   810
                            // Primary key is given as the first subkey
krista@1426
   811
                            if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1426
   812
                                key && key->subkeys && key->subkeys->fpr
Edouard@674
   813
                                && key->subkeys->fpr[0])
Edouard@674
   814
                            {
Edouard@505
   815
                                k = stringlist_add(k, key->subkeys->fpr);
Edouard@677
   816
Edouard@674
   817
                                gpg.gpgme_key_unref(key);
Edouard@677
   818
Edouard@677
   819
                                if (k == NULL) {
Edouard@677
   820
                                    free_stringlist(_keylist);
krista@1591
   821
                                    if (recipient_keylist)
krista@1591
   822
                                        free (recipient_keylist);
Edouard@677
   823
                                    gpg.gpgme_data_release(plain);
Edouard@677
   824
                                    gpg.gpgme_data_release(cipher);
Edouard@677
   825
                                    free(_buffer);
Edouard@677
   826
                                    return PEP_OUT_OF_MEMORY;
Edouard@677
   827
                                }
Edouard@674
   828
                            }
krista@1426
   829
                            else
Edouard@674
   830
                            {
Edouard@505
   831
                                result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@505
   832
                                break;
Edouard@505
   833
                            }
vb@344
   834
                            break;
Edouard@505
   835
                        }
vb@344
   836
                        case GPG_ERR_CERT_REVOKED:
vb@344
   837
                        case GPG_ERR_BAD_SIGNATURE:
krista@2703
   838
			    result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
krista@2703
   839
                            //result = PEP_DECRYPT_BAD_SIGNATURE;
vb@344
   840
                            break;
vb@344
   841
                        case GPG_ERR_SIG_EXPIRED:
vb@344
   842
                        case GPG_ERR_KEY_EXPIRED:
vb@344
   843
                        case GPG_ERR_NO_PUBKEY:
vb@344
   844
                            k = stringlist_add(k, gpgme_signature->fpr);
Edouard@674
   845
                            if (k == NULL) {
Edouard@674
   846
                                free_stringlist(_keylist);
krista@1591
   847
                                if (recipient_keylist)
krista@1591
   848
                                    free_stringlist(recipient_keylist);
Edouard@674
   849
                                gpg.gpgme_data_release(plain);
Edouard@674
   850
                                gpg.gpgme_data_release(cipher);
Edouard@674
   851
                                free(_buffer);
Edouard@674
   852
                                return PEP_OUT_OF_MEMORY;
Edouard@674
   853
                            }
vb@344
   854
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@344
   855
                                result = PEP_DECRYPTED;
vb@344
   856
                            break;
vb@344
   857
                        case GPG_ERR_GENERAL:
vb@344
   858
                            break;
vb@344
   859
                        default:
vb@344
   860
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@344
   861
                                result = PEP_DECRYPTED;
vb@344
   862
                            break;
vb@344
   863
                        }
vb@344
   864
                    } while ((gpgme_signature = gpgme_signature->next));
vb@344
   865
                }
vb@344
   866
                else {
vb@344
   867
                    result = PEP_DECRYPTED;
vb@344
   868
                }
vb@344
   869
vb@344
   870
                if (result == PEP_DECRYPTED_AND_VERIFIED
vb@344
   871
                    || result == PEP_DECRYPTED) {
vb@344
   872
                    *ptext = _buffer;
vb@344
   873
                    *psize = reading;
vb@344
   874
                    (*ptext)[*psize] = 0; // safeguard for naive users
vb@344
   875
                    *keylist = _keylist;
edouard@1933
   876
                    if (recipient_keylist) {
krista@1591
   877
                        if (!_keylist)
roker@2055
   878
                            *keylist = new_stringlist(""); // no sig
krista@1591
   879
                        if (!(*keylist)) {
krista@1591
   880
                            free_stringlist(_keylist);
krista@1591
   881
                            if (recipient_keylist)
krista@1591
   882
                                free_stringlist(recipient_keylist);
krista@1591
   883
                            gpg.gpgme_data_release(plain);
krista@1591
   884
                            gpg.gpgme_data_release(cipher);
krista@1591
   885
                            free(_buffer);
krista@1591
   886
                            return PEP_OUT_OF_MEMORY;
roker@2055
   887
                        }
krista@1591
   888
                        stringlist_append(*keylist, recipient_keylist);
edouard@1933
   889
                    }
vb@344
   890
                }
vb@344
   891
                else {
vb@344
   892
                    free_stringlist(_keylist);
krista@1591
   893
                    if (recipient_keylist)
krista@1591
   894
                        free_stringlist(recipient_keylist);
vb@344
   895
                    free(_buffer);
vb@344
   896
                }
vb@344
   897
                break;
vb@344
   898
            }
vb@344
   899
            case GPG_ERR_BAD_PASSPHRASE:
krista@2681
   900
            case GPG_ERR_NO_DATA:
Edouard@725
   901
                result = PEP_DECRYPT_NO_KEY;
Edouard@725
   902
                break;
vb@344
   903
            case GPG_ERR_DECRYPT_FAILED:
vb@344
   904
            default:
vb@344
   905
            {
krista@1579
   906
                gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
vb@344
   907
                result = PEP_DECRYPT_NO_KEY;
vb@344
   908
vb@344
   909
                if (gpgme_decrypt_result != NULL) {
vb@344
   910
                    if (gpgme_decrypt_result->unsupported_algorithm)
vb@344
   911
                        *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
vb@344
   912
                    else
vb@344
   913
                        *keylist = new_stringlist("");
vb@344
   914
                    assert(*keylist);
vb@344
   915
                    if (*keylist == NULL) {
vb@24
   916
                        result = PEP_OUT_OF_MEMORY;
vb@24
   917
                        break;
vb@24
   918
                    }
vb@24
   919
                }
vb@24
   920
            }
vb@24
   921
        }
vb@24
   922
        break;
vb@24
   923
vb@24
   924
    default:
vb@24
   925
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
   926
    }
vb@24
   927
vb@74
   928
    gpg.gpgme_data_release(plain);
vb@74
   929
    gpg.gpgme_data_release(cipher);
vb@24
   930
    return result;
vb@24
   931
}
vb@24
   932
vb@24
   933
PEP_STATUS pgp_verify_text(
vb@24
   934
    PEP_SESSION session, const char *text, size_t size,
vb@24
   935
    const char *signature, size_t sig_size, stringlist_t **keylist
vb@24
   936
    )
vb@24
   937
{
vb@24
   938
    PEP_STATUS result;
vb@24
   939
    gpgme_error_t gpgme_error;
vb@24
   940
    gpgme_data_t d_text, d_sig;
vb@24
   941
    stringlist_t *_keylist;
vb@24
   942
vb@24
   943
    assert(session);
vb@24
   944
    assert(text);
vb@24
   945
    assert(size);
vb@24
   946
    assert(signature);
vb@24
   947
    assert(sig_size);
vb@24
   948
    assert(keylist);
vb@24
   949
vb@24
   950
    *keylist = NULL;
vb@24
   951
vb@74
   952
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
vb@45
   953
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   954
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   955
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   956
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   957
            return PEP_OUT_OF_MEMORY;
vb@24
   958
        else
vb@24
   959
            return PEP_UNKNOWN_ERROR;
vb@24
   960
    }
vb@24
   961
vb@74
   962
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
vb@45
   963
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   964
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   965
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   966
        gpg.gpgme_data_release(d_text);
vb@24
   967
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   968
            return PEP_OUT_OF_MEMORY;
vb@24
   969
        else
vb@24
   970
            return PEP_UNKNOWN_ERROR;
vb@24
   971
    }
vb@24
   972
vb@74
   973
    gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
vb@45
   974
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   975
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
   976
vb@24
   977
    switch (gpgme_error) {
vb@24
   978
    case GPG_ERR_NO_ERROR:
vb@24
   979
    {
vb@24
   980
        gpgme_verify_result_t gpgme_verify_result;
vb@24
   981
        gpgme_signature_t gpgme_signature;
vb@24
   982
vb@24
   983
        gpgme_verify_result =
vb@74
   984
            gpg.gpgme_op_verify_result(session->ctx);
vb@24
   985
        assert(gpgme_verify_result);
vb@24
   986
        gpgme_signature = gpgme_verify_result->signatures;
vb@24
   987
vb@24
   988
        if (gpgme_signature) {
vb@24
   989
            stringlist_t *k;
vb@24
   990
            _keylist = new_stringlist(NULL);
vb@24
   991
            assert(_keylist);
vb@24
   992
            if (_keylist == NULL) {
vb@74
   993
                gpg.gpgme_data_release(d_text);
vb@74
   994
                gpg.gpgme_data_release(d_sig);
vb@24
   995
                return PEP_OUT_OF_MEMORY;
vb@24
   996
            }
vb@24
   997
            k = _keylist;
vb@24
   998
vb@24
   999
            result = PEP_VERIFIED;
vb@24
  1000
            do {
Edouard@502
  1001
                gpgme_key_t key;
Edouard@502
  1002
                memset(&key,0,sizeof(key));
Edouard@502
  1003
krista@1426
  1004
                // GPGME may give subkey's fpr instead of primary key's fpr.
Edouard@502
  1005
                // Therefore we ask for the primary fingerprint instead
Edouard@502
  1006
                // we assume that gpgme_get_key can find key by subkey's fpr
Edouard@502
  1007
                gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@502
  1008
                    gpgme_signature->fpr, &key, 0);
Edouard@502
  1009
                gpgme_error = _GPGERR(gpgme_error);
Edouard@502
  1010
                assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@502
  1011
                if (gpgme_error == GPG_ERR_ENOMEM) {
vb@24
  1012
                    free_stringlist(_keylist);
Edouard@505
  1013
                    gpg.gpgme_data_release(d_text);
Edouard@505
  1014
                    gpg.gpgme_data_release(d_sig);
vb@24
  1015
                    return PEP_OUT_OF_MEMORY;
vb@24
  1016
                }
Edouard@502
  1017
                // Primary key is given as the first subkey
krista@1426
  1018
                if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1426
  1019
                    key && key->subkeys && key->subkeys->fpr
Edouard@674
  1020
                    && key->subkeys->fpr[0])
Edouard@674
  1021
                {
Edouard@504
  1022
                    k = stringlist_add(k, key->subkeys->fpr);
Edouard@677
  1023
Edouard@674
  1024
                    gpg.gpgme_key_unref(key);
Edouard@677
  1025
Edouard@677
  1026
                    if (k == NULL) {
Edouard@677
  1027
                        free_stringlist(_keylist);
Edouard@677
  1028
                        gpg.gpgme_data_release(d_text);
Edouard@677
  1029
                        gpg.gpgme_data_release(d_sig);
Edouard@677
  1030
                        return PEP_OUT_OF_MEMORY;
Edouard@677
  1031
                    }
Edouard@502
  1032
                }
Edouard@502
  1033
                else {
Edouard@502
  1034
                    result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@502
  1035
                    break;
Edouard@502
  1036
                }
Edouard@502
  1037
vb@24
  1038
                if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
vb@24
  1039
                    if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
vb@24
  1040
                        || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
vb@24
  1041
                        if (result == PEP_VERIFIED
vb@24
  1042
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
  1043
                            result = PEP_UNENCRYPTED;
vb@24
  1044
                    }
vb@24
  1045
                    else {
vb@24
  1046
                        result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@24
  1047
                        break;
vb@24
  1048
                    }
vb@24
  1049
                }
vb@24
  1050
                else {
vb@24
  1051
                    if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
vb@24
  1052
                        if (result == PEP_VERIFIED)
vb@24
  1053
                            result = PEP_VERIFIED_AND_TRUSTED;
vb@24
  1054
                    }
vb@24
  1055
                    if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
vb@24
  1056
                        // good
vb@24
  1057
                    }
vb@24
  1058
                    else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
vb@24
  1059
                        result = PEP_VERIFY_NO_KEY;
vb@24
  1060
                    }
vb@24
  1061
                    else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
vb@24
  1062
                        if (result == PEP_VERIFIED
vb@24
  1063
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
  1064
                            result = PEP_UNENCRYPTED;
vb@24
  1065
                    }
vb@24
  1066
                    else {
vb@24
  1067
                        // do nothing
vb@24
  1068
                    }
vb@24
  1069
                }
vb@24
  1070
            } while ((gpgme_signature = gpgme_signature->next));
vb@24
  1071
            *keylist = _keylist;
vb@24
  1072
        }
vb@24
  1073
        else {
vb@24
  1074
            result = PEP_UNENCRYPTED;
vb@24
  1075
        }
vb@24
  1076
        break;
vb@24
  1077
    }
vb@24
  1078
        break;
vb@24
  1079
    case GPG_ERR_NO_DATA:
vb@24
  1080
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
  1081
        break;
vb@24
  1082
    case GPG_ERR_INV_VALUE:
vb@24
  1083
    default:
vb@24
  1084
        result = PEP_UNKNOWN_ERROR;
vb@24
  1085
        break;
vb@24
  1086
    }
vb@24
  1087
vb@74
  1088
    gpg.gpgme_data_release(d_text);
vb@74
  1089
    gpg.gpgme_data_release(d_sig);
vb@24
  1090
vb@24
  1091
    return result;
vb@24
  1092
}
vb@24
  1093
krista@1639
  1094
krista@1639
  1095
static PEP_STATUS pgp_encrypt_sign_optional(    
vb@24
  1096
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1639
  1097
    size_t psize, char **ctext, size_t *csize, bool sign
krista@1639
  1098
)
roker@2055
  1099
{
vb@24
  1100
    PEP_STATUS result;
vb@24
  1101
    gpgme_error_t gpgme_error;
vb@24
  1102
    gpgme_data_t plain, cipher;
vb@24
  1103
    gpgme_key_t *rcpt;
vb@24
  1104
    gpgme_encrypt_flags_t flags;
vb@24
  1105
    const stringlist_t *_keylist;
vb@24
  1106
    int i, j;
vb@24
  1107
vb@46
  1108
    assert(session);
vb@24
  1109
    assert(keylist);
vb@24
  1110
    assert(ptext);
vb@24
  1111
    assert(psize);
vb@24
  1112
    assert(ctext);
vb@24
  1113
    assert(csize);
vb@24
  1114
vb@24
  1115
    *ctext = NULL;
vb@24
  1116
    *csize = 0;
vb@24
  1117
vb@74
  1118
    gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
vb@45
  1119
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1120
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1121
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
  1122
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
  1123
            return PEP_OUT_OF_MEMORY;
vb@24
  1124
        else
vb@24
  1125
            return PEP_UNKNOWN_ERROR;
vb@24
  1126
    }
vb@24
  1127
vb@74
  1128
    gpgme_error = gpg.gpgme_data_new(&cipher);
vb@45
  1129
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1130
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1131
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
  1132
        gpg.gpgme_data_release(plain);
vb@24
  1133
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
  1134
            return PEP_OUT_OF_MEMORY;
vb@24
  1135
        else
vb@24
  1136
            return PEP_UNKNOWN_ERROR;
vb@24
  1137
    }
vb@24
  1138
vb@109
  1139
    rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
vb@24
  1140
    assert(rcpt);
vb@24
  1141
    if (rcpt == NULL) {
vb@74
  1142
        gpg.gpgme_data_release(plain);
vb@74
  1143
        gpg.gpgme_data_release(cipher);
vb@24
  1144
        return PEP_OUT_OF_MEMORY;
vb@24
  1145
    }
vb@24
  1146
vb@74
  1147
    gpg.gpgme_signers_clear(session->ctx);
vb@24
  1148
vb@24
  1149
    for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
vb@24
  1150
        assert(_keylist->value);
vb@74
  1151
        gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
vb@24
  1152
            &rcpt[i], 0);
vb@45
  1153
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1154
        assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1155
vb@24
  1156
        switch (gpgme_error) {
vb@24
  1157
        case GPG_ERR_ENOMEM:
vb@24
  1158
            for (j = 0; j<i; j++)
vb@74
  1159
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1160
            free(rcpt);
vb@74
  1161
            gpg.gpgme_data_release(plain);
vb@74
  1162
            gpg.gpgme_data_release(cipher);
vb@24
  1163
            return PEP_OUT_OF_MEMORY;
vb@24
  1164
        case GPG_ERR_NO_ERROR:
krista@1639
  1165
            if (i == 0 && sign) {
vb@74
  1166
                gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
vb@45
  1167
                _gpgme_error = _GPGERR(_gpgme_error);
vb@24
  1168
                assert(_gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1169
            }
vb@24
  1170
            break;
vb@24
  1171
        case GPG_ERR_EOF:
vb@24
  1172
            for (j = 0; j<i; j++)
vb@74
  1173
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1174
            free(rcpt);
vb@74
  1175
            gpg.gpgme_data_release(plain);
vb@74
  1176
            gpg.gpgme_data_release(cipher);
vb@24
  1177
            return PEP_KEY_NOT_FOUND;
vb@24
  1178
        case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1179
            for (j = 0; j<i; j++)
vb@74
  1180
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1181
            free(rcpt);
vb@74
  1182
            gpg.gpgme_data_release(plain);
vb@74
  1183
            gpg.gpgme_data_release(cipher);
vb@24
  1184
            return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1185
        default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
vb@24
  1186
            // FPR is not a fingerprint or key ID
vb@24
  1187
            for (j = 0; j<i; j++)
vb@74
  1188
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1189
            free(rcpt);
vb@74
  1190
            gpg.gpgme_data_release(plain);
vb@74
  1191
            gpg.gpgme_data_release(cipher);
vb@24
  1192
            return PEP_GET_KEY_FAILED;
vb@24
  1193
        }
vb@24
  1194
    }
vb@24
  1195
vb@24
  1196
    // TODO: remove that and replace with proper key management
vb@24
  1197
    flags = GPGME_ENCRYPT_ALWAYS_TRUST;
krista@1639
  1198
    
krista@1639
  1199
    if (sign) {
krista@1639
  1200
        gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
krista@1639
  1201
            plain, cipher);
krista@1639
  1202
    }
krista@1639
  1203
    else {
krista@1639
  1204
        gpgme_error = gpg.gpgme_op_encrypt(session->ctx, rcpt, flags,
krista@1639
  1205
            plain, cipher);
krista@1639
  1206
    }
krista@1639
  1207
    
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
    {
vb@24
  1212
        char *_buffer = NULL;
vb@24
  1213
        size_t reading;
vb@74
  1214
        size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
vb@24
  1215
        assert(length != -1);
vb@74
  1216
        gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
vb@24
  1217
vb@24
  1218
        // TODO: make things less memory consuming
vb@24
  1219
        // the following algorithm allocates a buffer for the complete text
vb@24
  1220
vb@112
  1221
        _buffer = malloc(length + 1);
vb@24
  1222
        assert(_buffer);
vb@24
  1223
        if (_buffer == NULL) {
vb@24
  1224
            for (j = 0; j<stringlist_length(keylist); j++)
vb@74
  1225
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1226
            free(rcpt);
vb@74
  1227
            gpg.gpgme_data_release(plain);
vb@74
  1228
            gpg.gpgme_data_release(cipher);
vb@24
  1229
            return PEP_OUT_OF_MEMORY;
vb@24
  1230
        }
vb@24
  1231
vb@74
  1232
        reading = gpg.gpgme_data_read(cipher, _buffer, length);
vb@24
  1233
        assert(length == reading);
vb@24
  1234
vb@24
  1235
        *ctext = _buffer;
vb@24
  1236
        *csize = reading;
vb@24
  1237
        (*ctext)[*csize] = 0; // safeguard for naive users
vb@24
  1238
        result = PEP_STATUS_OK;
vb@24
  1239
        break;
vb@24
  1240
    }
vb@24
  1241
    default:
vb@24
  1242
        result = PEP_UNKNOWN_ERROR;
vb@24
  1243
    }
vb@24
  1244
vb@24
  1245
    for (j = 0; j<stringlist_length(keylist); j++)
vb@74
  1246
        gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1247
    free(rcpt);
vb@74
  1248
    gpg.gpgme_data_release(plain);
vb@74
  1249
    gpg.gpgme_data_release(cipher);
vb@24
  1250
    return result;
vb@24
  1251
}
vb@24
  1252
krista@1639
  1253
PEP_STATUS pgp_encrypt_only(
krista@1639
  1254
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1639
  1255
    size_t psize, char **ctext, size_t *csize
krista@1639
  1256
    )
krista@1639
  1257
{
krista@1639
  1258
    return pgp_encrypt_sign_optional(session, keylist, ptext,
krista@1639
  1259
        psize, ctext, csize, false);
krista@1639
  1260
}
krista@1639
  1261
krista@1639
  1262
PEP_STATUS pgp_encrypt_and_sign(
krista@1639
  1263
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1639
  1264
    size_t psize, char **ctext, size_t *csize
krista@1639
  1265
    )
krista@1639
  1266
{
krista@1639
  1267
    return pgp_encrypt_sign_optional(session, keylist, ptext,
krista@1639
  1268
        psize, ctext, csize, true);
krista@1639
  1269
}
krista@1639
  1270
krista@1925
  1271
krista@1925
  1272
static PEP_STATUS find_single_key(
krista@1925
  1273
        PEP_SESSION session,
krista@1925
  1274
        const char *fpr,
krista@1925
  1275
        gpgme_key_t *key
krista@1925
  1276
    )
krista@1925
  1277
{
krista@1925
  1278
    gpgme_error_t gpgme_error;
krista@1925
  1279
krista@1925
  1280
    *key = NULL;
krista@1925
  1281
kgrothoff@1926
  1282
//    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
kgrothoff@1926
  1283
kgrothoff@1926
  1284
    gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, key, 0);
kgrothoff@1926
  1285
krista@1925
  1286
    gpgme_error = _GPGERR(gpgme_error);
krista@1925
  1287
    switch (gpgme_error) {
krista@1925
  1288
    case GPG_ERR_NO_ERROR:
krista@1925
  1289
        break;
krista@1925
  1290
    case GPG_ERR_INV_VALUE:
krista@1925
  1291
        assert(0);
krista@1925
  1292
        return PEP_UNKNOWN_ERROR;
krista@1925
  1293
    default:
krista@1925
  1294
        return PEP_GET_KEY_FAILED;
krista@1925
  1295
    };
krista@1925
  1296
kgrothoff@1926
  1297
//    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
kgrothoff@1926
  1298
//    gpgme_error = _GPGERR(gpgme_error);
kgrothoff@1926
  1299
//    assert(gpgme_error != GPG_ERR_INV_VALUE);
krista@1925
  1300
kgrothoff@1926
  1301
//    gpg.gpgme_op_keylist_end(session->ctx);
krista@1925
  1302
krista@1925
  1303
    return PEP_STATUS_OK;
krista@1925
  1304
}
krista@1925
  1305
krista@1925
  1306
krista@1914
  1307
static PEP_STATUS _pgp_createkey(PEP_SESSION session, pEp_identity *identity) {
krista@1914
  1308
    PEP_STATUS status = PEP_VERSION_MISMATCH;
krista@1914
  1309
roker@2055
  1310
    if (identity && identity->address) {
krista@1914
  1311
#ifdef GPGME_VERSION_NUMBER 
krista@1914
  1312
#if (GPGME_VERSION_NUMBER >= 0x010700)
krista@1920
  1313
        gpgme_error_t gpgme_error;
kgrothoff@1926
  1314
        int userid_size = strlen(identity->address) + 1;
krista@1921
  1315
        char* userid = (char*)(calloc(1, userid_size));
krista@1921
  1316
        if (!userid)
krista@1921
  1317
            return PEP_OUT_OF_MEMORY;
kgrothoff@1926
  1318
        strlcpy(userid, identity->address, userid_size);
krista@1921
  1319
        gpgme_error = gpg.gpgme_op_createkey(session->ctx, userid, "RSA", 
krista@1924
  1320
                                             0, 31536000, NULL, 
krista@1927
  1321
                                             GPGME_CREATE_NOPASSWD | GPGME_CREATE_FORCE);
krista@1920
  1322
        gpgme_error = _GPGERR(gpgme_error);
krista@1921
  1323
krista@1921
  1324
        free(userid);
krista@1921
  1325
krista@1920
  1326
        if (gpgme_error != GPG_ERR_NOT_SUPPORTED) {
krista@1920
  1327
            switch (gpgme_error) {
krista@1924
  1328
                case GPG_ERR_NO_ERROR:
roker@2055
  1329
                    break;
krista@1924
  1330
                case GPG_ERR_INV_VALUE:
krista@1924
  1331
                    return PEP_ILLEGAL_VALUE;
vb@2801
  1332
                default:
krista@1924
  1333
                    return PEP_CANNOT_CREATE_KEY;
roker@2055
  1334
            }
krista@1924
  1335
krista@1924
  1336
            /* This is the same regardless of whether we got it from genkey or createkey */
krista@1924
  1337
            gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
krista@1924
  1338
            assert(gpgme_genkey_result);
krista@1924
  1339
            assert(gpgme_genkey_result->fpr);
krista@1924
  1340
kgrothoff@1926
  1341
            char* fpr = strdup(gpgme_genkey_result->fpr);
krista@1925
  1342
            gpgme_key_t key;
krista@1925
  1343
            PEP_STATUS key_status = find_single_key(session, fpr, &key);
krista@1925
  1344
            if (!key || key_status != PEP_STATUS_OK)
krista@1925
  1345
                return PEP_CANNOT_CREATE_KEY;
roker@2055
  1346
            
krista@1925
  1347
            gpgme_error = gpg.gpgme_op_createsubkey(session->ctx, key, 
krista@1925
  1348
                                                    "RSA", 0, 
krista@1925
  1349
                                                    31536000, GPGME_CREATE_NOPASSWD 
krista@1925
  1350
                                                    | GPGME_CREATE_ENCR);
krista@1925
  1351
krista@1925
  1352
            switch (gpgme_error) {
krista@1925
  1353
                case GPG_ERR_NO_ERROR:
roker@2055
  1354
                    break;
krista@1925
  1355
                case GPG_ERR_INV_VALUE:
krista@1925
  1356
                    return PEP_ILLEGAL_VALUE;
krista@1925
  1357
                case GPG_ERR_GENERAL:
krista@1925
  1358
                    return PEP_CANNOT_CREATE_KEY;
krista@1925
  1359
                default:
krista@1925
  1360
                    assert(0);
krista@1925
  1361
                    return PEP_UNKNOWN_ERROR;
roker@2055
  1362
            }
krista@1925
  1363
            
krista@1924
  1364
            free(identity->fpr);
kgrothoff@1926
  1365
            identity->fpr = fpr;
krista@1924
  1366
            if (identity->fpr == NULL)
krista@1924
  1367
                return PEP_OUT_OF_MEMORY;
krista@1924
  1368
kgrothoff@1926
  1369
//            gpg.gpgme_key_unref(key);
krista@1925
  1370
            
kgrothoff@1926
  1371
            status = pgp_replace_only_uid(session, fpr,
roker@2055
  1372
                        identity->username, identity->address);
krista@1920
  1373
        }
krista@1914
  1374
#endif
krista@1914
  1375
#endif
krista@1914
  1376
    }
krista@1914
  1377
    
krista@1914
  1378
    return status;
krista@1914
  1379
}
krista@1914
  1380
vb@24
  1381
PEP_STATUS pgp_generate_keypair(
vb@24
  1382
    PEP_SESSION session, pEp_identity *identity
vb@24
  1383
    )
vb@24
  1384
{
vb@24
  1385
    assert(session);
vb@24
  1386
    assert(identity);
vb@24
  1387
    assert(identity->address);
vb@298
  1388
    assert(identity->fpr == NULL || identity->fpr[0] == 0);
vb@24
  1389
    assert(identity->username);
vb@24
  1390
krista@1914
  1391
    PEP_STATUS status = _pgp_createkey(session, identity);
krista@1914
  1392
    
krista@1924
  1393
    if (status != PEP_VERSION_MISMATCH)
krista@1914
  1394
        return status;
krista@1924
  1395
        
krista@1924
  1396
    gpgme_error_t gpgme_error;
krista@1924
  1397
    char *parms;
krista@1924
  1398
    const char *template =
krista@1924
  1399
        "<GnupgKeyParms format=\"internal\">\n"
krista@1924
  1400
        "Key-Type: RSA\n"
krista@1924
  1401
        "Key-Length: 4096\n"
krista@1924
  1402
        "Subkey-Type: RSA\n"
krista@1924
  1403
        "Subkey-Length: 4096\n"
krista@1924
  1404
        "Name-Real: %s\n"
krista@1924
  1405
        "Name-Email: %s\n"
krista@1924
  1406
        /* "Passphrase: %s\n" */
krista@1924
  1407
        "Expire-Date: 1y\n"
krista@1924
  1408
        "</GnupgKeyParms>\n";
krista@1924
  1409
    int result;
vb@24
  1410
krista@1924
  1411
    parms = calloc(1, PARMS_MAX);
krista@1924
  1412
    assert(parms);
krista@1924
  1413
    if (parms == NULL)
krista@1924
  1414
        return PEP_OUT_OF_MEMORY;
krista@1914
  1415
krista@1924
  1416
    result = snprintf(parms, PARMS_MAX, template, identity->username,
krista@1924
  1417
        identity->address); // , session->passphrase);
krista@1924
  1418
    assert(result < PARMS_MAX);
krista@1924
  1419
    if (result >= PARMS_MAX) {
vb@24
  1420
        free(parms);
krista@1924
  1421
        return PEP_BUFFER_TOO_SMALL;
vb@24
  1422
    }
vb@24
  1423
krista@1924
  1424
    gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
krista@1924
  1425
    gpgme_error = _GPGERR(gpgme_error);
krista@1924
  1426
    free(parms);
krista@1924
  1427
krista@1924
  1428
    switch (gpgme_error) {
krista@1924
  1429
    case GPG_ERR_NO_ERROR:
krista@1924
  1430
        break;
krista@1924
  1431
    case GPG_ERR_INV_VALUE:
krista@1924
  1432
        return PEP_ILLEGAL_VALUE;
krista@1924
  1433
    case GPG_ERR_GENERAL:
krista@1924
  1434
        return PEP_CANNOT_CREATE_KEY;
krista@1924
  1435
    default:
krista@1924
  1436
        assert(0);
krista@1924
  1437
        return PEP_UNKNOWN_ERROR;
krista@1924
  1438
    }
krista@1924
  1439
krista@1914
  1440
    gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
vb@24
  1441
    assert(gpgme_genkey_result);
vb@24
  1442
    assert(gpgme_genkey_result->fpr);
vb@24
  1443
vb@298
  1444
    free(identity->fpr);
vb@24
  1445
    identity->fpr = strdup(gpgme_genkey_result->fpr);
vb@298
  1446
    if (identity->fpr == NULL)
vb@298
  1447
        return PEP_OUT_OF_MEMORY;
vb@24
  1448
vb@24
  1449
    return PEP_STATUS_OK;
vb@24
  1450
}
vb@24
  1451
vb@24
  1452
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
vb@24
  1453
{
vb@24
  1454
    gpgme_error_t gpgme_error;
vb@24
  1455
    gpgme_key_t key;
vb@24
  1456
vb@24
  1457
    assert(session);
vb@24
  1458
    assert(fpr);
vb@24
  1459
vb@74
  1460
    gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
vb@45
  1461
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1462
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1463
    switch (gpgme_error) {
vb@24
  1464
    case GPG_ERR_NO_ERROR:
vb@24
  1465
        break;
vb@24
  1466
    case GPG_ERR_EOF:
vb@24
  1467
        return PEP_KEY_NOT_FOUND;
vb@24
  1468
    case GPG_ERR_INV_VALUE:
vb@24
  1469
        return PEP_ILLEGAL_VALUE;
vb@24
  1470
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1471
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1472
    case GPG_ERR_ENOMEM:
vb@24
  1473
        return PEP_OUT_OF_MEMORY;
vb@24
  1474
    default:
vb@24
  1475
        assert(0);
vb@24
  1476
        return PEP_UNKNOWN_ERROR;
vb@24
  1477
    }
vb@24
  1478
vb@74
  1479
    gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
vb@45
  1480
    gpgme_error = _GPGERR(gpgme_error);
vb@74
  1481
    gpg.gpgme_key_unref(key);
vb@24
  1482
    switch (gpgme_error) {
vb@24
  1483
    case GPG_ERR_NO_ERROR:
vb@24
  1484
        break;
vb@24
  1485
    case GPG_ERR_INV_VALUE:
vb@24
  1486
        assert(0);
vb@24
  1487
        return PEP_UNKNOWN_ERROR;
vb@24
  1488
    case GPG_ERR_NO_PUBKEY:
vb@24
  1489
        assert(0);
vb@24
  1490
        return PEP_KEY_NOT_FOUND;
vb@24
  1491
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1492
        assert(0);
vb@24
  1493
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1494
    default:
vb@24
  1495
        assert(0);
vb@24
  1496
        return PEP_UNKNOWN_ERROR;
vb@24
  1497
    }
vb@24
  1498
vb@24
  1499
    return PEP_STATUS_OK;
vb@24
  1500
}
vb@24
  1501
Edouard@728
  1502
PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
Edouard@728
  1503
                              size_t size, identity_list **private_idents)
vb@24
  1504
{
vb@24
  1505
    gpgme_error_t gpgme_error;
vb@24
  1506
    gpgme_data_t dh;
vb@24
  1507
vb@24
  1508
    assert(session);
vb@24
  1509
    assert(key_data);
krista@1426
  1510
krista@1426
  1511
    if(private_idents)
Edouard@728
  1512
        *private_idents = NULL;
vb@24
  1513
vb@74
  1514
    gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
vb@45
  1515
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1516
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1517
    switch (gpgme_error) {
vb@24
  1518
    case GPG_ERR_NO_ERROR:
vb@24
  1519
        break;
vb@24
  1520
    case GPG_ERR_ENOMEM:
vb@24
  1521
        return PEP_OUT_OF_MEMORY;
vb@24
  1522
    case GPG_ERR_INV_VALUE:
vb@24
  1523
        assert(0);
vb@24
  1524
        return PEP_UNKNOWN_ERROR;
vb@24
  1525
    default:
vb@24
  1526
        assert(0);
vb@24
  1527
        return PEP_UNKNOWN_ERROR;
vb@24
  1528
    }
vb@24
  1529
Edouard@728
  1530
    gpgme_import_result_t gpgme_import_result;
Edouard@728
  1531
vb@74
  1532
    gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
vb@45
  1533
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1534
    switch (gpgme_error) {
vb@24
  1535
    case GPG_ERR_NO_ERROR:
krista@1426
  1536
        if(private_idents)
Edouard@728
  1537
        {
Edouard@728
  1538
            gpgme_import_result =
Edouard@728
  1539
                gpg.gpgme_op_import_result(session->ctx);
Edouard@728
  1540
            assert(gpgme_import_result);
vb@1302
  1541
            if (!gpgme_import_result) {
vb@1302
  1542
                gpg.gpgme_data_release(dh);
vb@1302
  1543
                return PEP_UNKNOWN_ERROR;
vb@1302
  1544
            }
vb@1302
  1545
Edouard@728
  1546
            gpgme_import_status_t import;
krista@1426
  1547
            for (import = gpgme_import_result->imports;
krista@1426
  1548
                 import;
Edouard@728
  1549
                 import = import->next)
Edouard@728
  1550
             {
Edouard@728
  1551
                if (import &&
Edouard@728
  1552
                    import->result == GPG_ERR_NO_ERROR &&
Edouard@728
  1553
                    import->status & GPGME_IMPORT_SECRET )
Edouard@728
  1554
                {
Edouard@728
  1555
                    gpgme_key_t key = NULL;
Edouard@728
  1556
Edouard@728
  1557
                    gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@728
  1558
                        import->fpr, &key, 0);
Edouard@728
  1559
                    gpgme_error = _GPGERR(gpgme_error);
Edouard@728
  1560
                    assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@728
  1561
                    if (gpgme_error == GPG_ERR_ENOMEM) {
Edouard@728
  1562
                        gpg.gpgme_data_release(dh);
Edouard@728
  1563
                        return PEP_OUT_OF_MEMORY;
Edouard@728
  1564
                    }
krista@1426
  1565
krista@1426
  1566
                    if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1426
  1567
                        key && key->uids &&
Edouard@728
  1568
                        key->uids->email && key->uids->name)
Edouard@728
  1569
                    {
Edouard@728
  1570
                        pEp_identity *ident = new_identity(
Edouard@728
  1571
                             key->uids->email, import->fpr, NULL, key->uids->name);
Edouard@728
  1572
Edouard@728
  1573
                        gpg.gpgme_key_unref(key);
Edouard@728
  1574
Edouard@728
  1575
                        if (ident == NULL) {
Edouard@728
  1576
                            gpg.gpgme_data_release(dh);
Edouard@728
  1577
                            return PEP_OUT_OF_MEMORY;
Edouard@728
  1578
                        }
Edouard@728
  1579
Edouard@728
  1580
                        *private_idents = identity_list_add(*private_idents, ident);
Edouard@728
  1581
Edouard@728
  1582
                        if (*private_idents == NULL) {
Edouard@728
  1583
                            gpg.gpgme_data_release(dh);
Edouard@728
  1584
                            return PEP_OUT_OF_MEMORY;
Edouard@728
  1585
                        }
Edouard@728
  1586
                    }
krista@1426
  1587
                    else
Edouard@728
  1588
                    {
Edouard@728
  1589
                        gpg.gpgme_key_unref(key);
Edouard@728
  1590
                        gpg.gpgme_data_release(dh);
Edouard@728
  1591
                        return PEP_UNKNOWN_ERROR;
Edouard@728
  1592
                    }
Edouard@728
  1593
                }
Edouard@728
  1594
            }
Edouard@728
  1595
        }
vb@24
  1596
        break;
vb@24
  1597
    case GPG_ERR_INV_VALUE:
vb@24
  1598
        assert(0);
vb@74
  1599
        gpg.gpgme_data_release(dh);
vb@24
  1600
        return PEP_UNKNOWN_ERROR;
vb@24
  1601
    case GPG_ERR_NO_DATA:
vb@74
  1602
        gpg.gpgme_data_release(dh);
vb@24
  1603
        return PEP_ILLEGAL_VALUE;
vb@24
  1604
    default:
vb@24
  1605
        assert(0);
vb@74
  1606
        gpg.gpgme_data_release(dh);
vb@24
  1607
        return PEP_UNKNOWN_ERROR;
vb@24
  1608
    }
vb@24
  1609
vb@74
  1610
    gpg.gpgme_data_release(dh);
vb@24
  1611
    return PEP_STATUS_OK;
vb@24
  1612
}
vb@24
  1613
Edouard@170
  1614
PEP_STATUS pgp_export_keydata(
vb@1103
  1615
        PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
vb@1103
  1616
        bool secret
vb@24
  1617
    )
vb@24
  1618
{
vb@24
  1619
    gpgme_error_t gpgme_error;
vb@24
  1620
    gpgme_data_t dh;
vb@24
  1621
    size_t _size;
vb@24
  1622
    char *buffer;
vb@24
  1623
    int reading;
vb@24
  1624
vb@24
  1625
    assert(session);
vb@24
  1626
    assert(fpr);
vb@24
  1627
    assert(key_data);
vb@24
  1628
    assert(size);
vb@24
  1629
vb@74
  1630
    gpgme_error = gpg.gpgme_data_new(&dh);
vb@45
  1631
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1632
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1633
    switch (gpgme_error) {
vb@24
  1634
    case GPG_ERR_NO_ERROR:
vb@24
  1635
        break;
vb@24
  1636
    case GPG_ERR_ENOMEM:
vb@24
  1637
        return PEP_OUT_OF_MEMORY;
vb@24
  1638
    case GPG_ERR_INV_VALUE:
vb@24
  1639
        assert(0);
vb@24
  1640
        return PEP_UNKNOWN_ERROR;
vb@24
  1641
    default:
vb@24
  1642
        assert(0);
vb@24
  1643
        return PEP_UNKNOWN_ERROR;
vb@24
  1644
    }
vb@24
  1645
vb@1103
  1646
    if (secret)
vb@1103
  1647
        gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
edouard@1163
  1648
            GPGME_EXPORT_MODE_SECRET, dh);
vb@1103
  1649
    else
vb@1103
  1650
        gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
vb@1103
  1651
            GPGME_EXPORT_MODE_MINIMAL, dh);
vb@45
  1652
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1653
    switch (gpgme_error) {
vb@24
  1654
    case GPG_ERR_NO_ERROR:
vb@24
  1655
        break;
vb@24
  1656
    case GPG_ERR_EOF:
vb@74
  1657
        gpg.gpgme_data_release(dh);
vb@24
  1658
        return PEP_KEY_NOT_FOUND;
vb@24
  1659
    case GPG_ERR_INV_VALUE:
vb@24
  1660
        assert(0);
vb@74
  1661
        gpg.gpgme_data_release(dh);
vb@24
  1662
        return PEP_UNKNOWN_ERROR;
vb@24
  1663
    default:
vb@24
  1664
        assert(0);
vb@74
  1665
        gpg.gpgme_data_release(dh);
vb@24
  1666
        return PEP_UNKNOWN_ERROR;
vb@24
  1667
    };
vb@24
  1668
vb@74
  1669
    _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
vb@24
  1670
    assert(_size != -1);
vb@74
  1671
    gpg.gpgme_data_seek(dh, 0, SEEK_SET);
vb@24
  1672
vb@24
  1673
    buffer = malloc(_size + 1);
vb@24
  1674
    assert(buffer);
vb@24
  1675
    if (buffer == NULL) {
vb@74
  1676
        gpg.gpgme_data_release(dh);
vb@24
  1677
        return PEP_OUT_OF_MEMORY;
vb@24
  1678
    }
vb@24
  1679
vb@74
  1680
    reading = gpg.gpgme_data_read(dh, buffer, _size);
vb@24
  1681
    assert(_size == reading);
edouard@1803
  1682
    if(_size != reading)
edouard@1803
  1683
        return PEP_CANNOT_EXPORT_KEY;
vb@24
  1684
vb@24
  1685
    // safeguard for the naive user
vb@24
  1686
    buffer[_size] = 0;
vb@24
  1687
vb@24
  1688
    *key_data = buffer;
vb@24
  1689
    *size = _size;
vb@24
  1690
vb@74
  1691
    gpg.gpgme_data_release(dh);
vb@24
  1692
    return PEP_STATUS_OK;
vb@24
  1693
}
vb@24
  1694
krista@1426
  1695
PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern,
krista@1031
  1696
                            stringpair_list_t** keyinfo_list)
krista@1426
  1697
{
krista@1005
  1698
    gpgme_error_t gpgme_error;
krista@1005
  1699
    assert(session);
krista@1031
  1700
    assert(keyinfo_list);
krista@1426
  1701
krista@1031
  1702
    if (!session || !keyinfo_list)
krista@1005
  1703
        return PEP_ILLEGAL_VALUE;
krista@1426
  1704
krista@1031
  1705
    *keyinfo_list = NULL;
krista@1426
  1706
krista@1031
  1707
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
krista@1005
  1708
    gpgme_error = _GPGERR(gpgme_error);
krista@1426
  1709
krista@1005
  1710
    switch(gpgme_error) {
krista@1005
  1711
        case GPG_ERR_NO_ERROR:
krista@1005
  1712
            break;
krista@1005
  1713
        case GPG_ERR_INV_VALUE:
krista@1005
  1714
            assert(0);
krista@1005
  1715
            return PEP_UNKNOWN_ERROR;
krista@1005
  1716
        default:
krista@1005
  1717
            gpg.gpgme_op_keylist_end(session->ctx);
krista@1426
  1718
            return PEP_GET_KEY_FAILED;
krista@1005
  1719
    };
krista@1426
  1720
krista@1005
  1721
    gpgme_key_t key;
krista@1031
  1722
    stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
krista@1031
  1723
    stringpair_list_t* list_curr = _keyinfo_list;
krista@1031
  1724
    stringpair_t* pair = NULL;
krista@1426
  1725
krista@1426
  1726
    do {
krista@1005
  1727
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
krista@1005
  1728
        gpgme_error = _GPGERR(gpgme_error);
krista@1426
  1729
krista@1005
  1730
        switch(gpgme_error) {
krista@1005
  1731
            case GPG_ERR_EOF:
krista@1005
  1732
                break;
krista@1005
  1733
            case GPG_ERR_NO_ERROR:
krista@1005
  1734
                assert(key);
krista@1005
  1735
                assert(key->subkeys);
krista@1005
  1736
                if (!key || !key->subkeys)
krista@1005
  1737
                    return PEP_GET_KEY_FAILED;
krista@1040
  1738
krista@1005
  1739
                // first subkey is primary key
krista@1005
  1740
                char* fpr = key->subkeys->fpr;
roker@1199
  1741
                char* uid = key->uids->uid;
krista@1187
  1742
krista@1005
  1743
                assert(fpr);
roker@1199
  1744
                assert(uid);
krista@1031
  1745
                if (!fpr)
krista@1005
  1746
                    return PEP_GET_KEY_FAILED;
krista@1426
  1747
krista@1050
  1748
                if (key->subkeys->revoked)
krista@1040
  1749
                    continue;
krista@1426
  1750
krista@1031
  1751
                pair = new_stringpair(fpr, uid);
krista@1019
  1752
krista@1031
  1753
                assert(pair);
krista@1426
  1754
krista@1031
  1755
                if (pair) {
krista@1031
  1756
                    list_curr = stringpair_list_add(list_curr, pair);
krista@1031
  1757
                    pair = NULL;
krista@1426
  1758
krista@1005
  1759
                    assert(list_curr);
krista@1005
  1760
                    if (list_curr != NULL)
krista@1005
  1761
                        break;
krista@1005
  1762
                    else
krista@1031
  1763
                        free_stringpair(pair);
krista@1005
  1764
                }
krista@1031
  1765
                // else fallthrough (list_curr or pair wasn't allocateable)
krista@1005
  1766
            case GPG_ERR_ENOMEM:
krista@1031
  1767
                free_stringpair_list(_keyinfo_list);
krista@1005
  1768
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1005
  1769
                return PEP_OUT_OF_MEMORY;
krista@1005
  1770
            default:
krista@1005
  1771
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1005
  1772
                return PEP_UNKNOWN_ERROR;
krista@1005
  1773
        }
krista@1005
  1774
    } while (gpgme_error != GPG_ERR_EOF);
krista@1426
  1775
krista@1032
  1776
    if (_keyinfo_list->value == NULL) {
krista@1031
  1777
        free_stringpair_list(_keyinfo_list);
krista@1031
  1778
        _keyinfo_list = NULL;
krista@1005
  1779
    }
krista@1426
  1780
krista@1031
  1781
    *keyinfo_list = _keyinfo_list;
krista@1426
  1782
krista@1005
  1783
    return PEP_STATUS_OK;
krista@1005
  1784
}
krista@1005
  1785
vb@46
  1786
static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
vb@24
  1787
    gpgme_keylist_mode_t add_mode)
vb@24
  1788
{
vb@24
  1789
    gpgme_error_t gpgme_error;
vb@24
  1790
    gpgme_keylist_mode_t mode;
vb@24
  1791
vb@74
  1792
    mode = gpg.gpgme_get_keylist_mode(session->ctx);
vb@24
  1793
vb@24
  1794
    mode &= ~remove_mode;
vb@24
  1795
    mode |= add_mode;
vb@24
  1796
vb@74
  1797
    gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
vb@45
  1798
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1799
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1800
}
vb@24
  1801
vb@24
  1802
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
vb@24
  1803
{
vb@24
  1804
    gpgme_error_t gpgme_error;
vb@24
  1805
    gpgme_key_t key;
vb@24
  1806
vb@24
  1807
    assert(session);
vb@24
  1808
    assert(pattern);
vb@24
  1809
vb@46
  1810
    _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
vb@24
  1811
vb@74
  1812
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
vb@45
  1813
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1814
    switch (gpgme_error) {
vb@24
  1815
    case GPG_ERR_NO_ERROR:
vb@24
  1816
        break;
vb@24
  1817
    case GPG_ERR_INV_VALUE:
vb@24
  1818
        assert(0);
vb@47
  1819
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1820
        return PEP_UNKNOWN_ERROR;
vb@24
  1821
    default:
vb@47
  1822
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1823
        return PEP_GET_KEY_FAILED;
vb@24
  1824
    };
vb@24
  1825
vb@47
  1826
    gpgme_ctx_t import_ctx;
vb@74
  1827
    gpgme_error = gpg.gpgme_new(&import_ctx);
vb@47
  1828
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@47
  1829
vb@24
  1830
    do {
vb@74
  1831
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1832
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1833
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1834
        switch (gpgme_error) {
vb@24
  1835
        case GPG_ERR_EOF:
vb@24
  1836
            break;
vb@24
  1837
        case GPG_ERR_NO_ERROR:
vb@24
  1838
        {
vb@24
  1839
            gpgme_error_t gpgme_error;
vb@24
  1840
            gpgme_key_t keys[2];
vb@24
  1841
vb@24
  1842
            keys[0] = key;
vb@24
  1843
            keys[1] = NULL;
vb@24
  1844
vb@74
  1845
            gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
vb@45
  1846
            gpgme_error = _GPGERR(gpgme_error);
vb@74
  1847
            gpg.gpgme_key_unref(key);
vb@24
  1848
            assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1849
            assert(gpgme_error != GPG_ERR_CONFLICT);
vb@24
  1850
        }
vb@24
  1851
            break;
vb@24
  1852
        case GPG_ERR_ENOMEM:
vb@74
  1853
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1854
            gpg.gpgme_release(import_ctx);
vb@47
  1855
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1856
            return PEP_OUT_OF_MEMORY;
vb@24
  1857
        default:
vb@74
  1858
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1859
            gpg.gpgme_release(import_ctx);
vb@47
  1860
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@46
  1861
            return PEP_UNKNOWN_ERROR;
vb@24
  1862
        };
vb@24
  1863
    } while (gpgme_error != GPG_ERR_EOF);
vb@24
  1864
vb@74
  1865
    gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  1866
    gpg.gpgme_release(import_ctx);
vb@47
  1867
    _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  1868
    return PEP_STATUS_OK;
vb@24
  1869
}
vb@24
  1870
krista@1357
  1871
static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
krista@1357
  1872
                            stringlist_t** keylist,
krista@1357
  1873
                            int private_only) {
vb@24
  1874
    gpgme_error_t gpgme_error;
vb@24
  1875
    gpgme_key_t key;
krista@1426
  1876
vb@24
  1877
    assert(session);
vb@24
  1878
    assert(keylist);
krista@1426
  1879
vb@24
  1880
    *keylist = NULL;
krista@1426
  1881
krista@1357
  1882
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
vb@45
  1883
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1884
    switch (gpgme_error) {
krista@1357
  1885
        case GPG_ERR_NO_ERROR:
krista@1357
  1886
            break;
krista@1357
  1887
        case GPG_ERR_INV_VALUE:
krista@1357
  1888
            assert(0);
krista@1357
  1889
            return PEP_UNKNOWN_ERROR;
krista@1357
  1890
        default:
krista@1357
  1891
            gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  1892
            return PEP_GET_KEY_FAILED;
vb@24
  1893
    };
krista@1426
  1894
roker@877
  1895
    stringlist_t *_keylist = new_stringlist(NULL);
vb@24
  1896
    stringlist_t *_k = _keylist;
krista@1426
  1897
vb@24
  1898
    do {
vb@74
  1899
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  1900
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1901
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1902
        switch (gpgme_error) {
krista@1357
  1903
            case GPG_ERR_EOF:
vb@24
  1904
                break;
krista@1357
  1905
            case GPG_ERR_NO_ERROR:
krista@1357
  1906
                assert(key);
krista@1357
  1907
                assert(key->subkeys);
edouard@1525
  1908
                if(!key->subkeys)
krista@1357
  1909
                    break;
edouard@1525
  1910
                assert(key->uids);
edouard@1525
  1911
                gpgme_user_id_t kuid = key->uids;
krista@2057
  1912
                // check that at least one uid's email matches pattern exactly,
krista@2057
  1913
                // modulo the email-diff heuristic
edouard@1525
  1914
                while(kuid) {
krista@2681
  1915
                    if((pattern == NULL) ||
krista@2681
  1916
                       (strstr(pattern, "@") == NULL) || // not an email
krista@2681
  1917
                       (kuid->email && _email_heuristic_match(kuid->email, pattern)))
edouard@1760
  1918
                    { 
edouard@1525
  1919
                        char *fpr = key->subkeys->fpr;
edouard@1525
  1920
                        assert(fpr);
edouard@1525
  1921
                        _k = stringlist_add(_k, fpr);
edouard@1525
  1922
                        assert(_k);
edouard@1525
  1923
                        if (_k == NULL){
edouard@1525
  1924
                            free_stringlist(_keylist);
edouard@1525
  1925
                            gpg.gpgme_op_keylist_end(session->ctx);
edouard@1525
  1926
                            return PEP_OUT_OF_MEMORY;
edouard@1525
  1927
                        }
edouard@1525
  1928
                        break;
edouard@1525
  1929
                    }
edouard@1525
  1930
                    kuid = kuid->next;
edouard@1525
  1931
                }
edouard@1525
  1932
                break;
krista@1357
  1933
            case GPG_ERR_ENOMEM:
krista@1357
  1934
                free_stringlist(_keylist);
krista@1357
  1935
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  1936
                return PEP_OUT_OF_MEMORY;
krista@1357
  1937
            default:
krista@1357
  1938
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  1939
                return PEP_UNKNOWN_ERROR;
vb@24
  1940
        };
vb@24
  1941
    } while (gpgme_error != GPG_ERR_EOF);
krista@1426
  1942
vb@74
  1943
    gpg.gpgme_op_keylist_end(session->ctx);
krista@2098
  1944
    if (_keylist->value == NULL) {
vb@523
  1945
        free_stringlist(_keylist);
vb@523
  1946
        _keylist = NULL;
krista@2057
  1947
        
krista@2098
  1948
        if (pattern != NULL) {
krista@2098
  1949
            // If match failed, check to see if we've got a dotted address in the pattern.
krista@2098
  1950
            // (last chance of the heuristic, really)
krista@2098
  1951
            // If so, try again without any dots.
krista@2098
  1952
            const char* dotpos = strstr(pattern, ".");
krista@2098
  1953
            const char* atpos = strstr(pattern, "@");
krista@2098
  1954
            if (dotpos && atpos && (dotpos < atpos)) {
krista@2098
  1955
                char* undotted = _undot_address(pattern);
krista@2098
  1956
                if (undotted) {
krista@2098
  1957
                    PEP_STATUS status = _pgp_search_keys(session, undotted,
krista@2098
  1958
                                                         keylist, private_only);
krista@2098
  1959
                    free(undotted);
krista@2098
  1960
                    return status;
krista@2098
  1961
                }
krista@2057
  1962
            }
krista@2057
  1963
        }
krista@2057
  1964
    }    
krista@2057
  1965
    
vb@24
  1966
    *keylist = _keylist;
vb@24
  1967
    return PEP_STATUS_OK;
vb@24
  1968
}
vb@24
  1969
krista@1357
  1970
PEP_STATUS pgp_find_keys(
krista@1357
  1971
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
krista@1357
  1972
    )
krista@1357
  1973
{
krista@1357
  1974
    return _pgp_search_keys(session, pattern, keylist, 0);
krista@1426
  1975
}
krista@1357
  1976
krista@1357
  1977
PEP_STATUS pgp_find_private_keys(
krista@1357
  1978
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
krista@1357
  1979
)
krista@1357
  1980
{
krista@1357
  1981
    return _pgp_search_keys(session, pattern, keylist, 1);
krista@1357
  1982
}
krista@1357
  1983
vb@2539
  1984
// this function is delivering a list of triples with fpr, email, name of all
vb@2539
  1985
// ultimatedly trusted private keys
vb@2539
  1986
vb@2539
  1987
PEP_STATUS pgp_find_trusted_private_keys(
vb@2539
  1988
        PEP_SESSION session, stringlist_t **keylist
vb@2539
  1989
    )
vb@2539
  1990
{
vb@2539
  1991
    assert(session && keylist);
vb@2539
  1992
    if (!session || !keylist)
krista@2458
  1993
        return PEP_ILLEGAL_VALUE;
krista@2458
  1994
vb@2539
  1995
    *keylist = NULL;
vb@2539
  1996
krista@2416
  1997
    gpgme_key_t key;
krista@2458
  1998
    gpgme_error_t gpgme_error;
vb@2539
  1999
vb@2539
  2000
    stringlist_t *private_keylist = NULL;
vb@2539
  2001
    PEP_STATUS status = pgp_find_private_keys(session, NULL, &private_keylist);
vb@2539
  2002
    if (status)
vb@2539
  2003
        return status;
vb@2539
  2004
    if (!private_keylist || !private_keylist->value)
vb@2539
  2005
        return status;
vb@2539
  2006
vb@2539
  2007
    stringlist_t *result_list = new_stringlist(NULL);
vb@2539
  2008
    if (!result_list)
vb@2539
  2009
        return PEP_OUT_OF_MEMORY;
vb@2539
  2010
    stringlist_t *_result_list = result_list;
vb@2539
  2011
vb@2539
  2012
    stringlist_t *keylist_curr;
vb@2539
  2013
    for (keylist_curr = private_keylist; keylist_curr && keylist_curr->value; keylist_curr = keylist_curr->next) {
vb@2539
  2014
        // a. get key data
vb@2539
  2015
        gpgme_error = gpg.gpgme_get_key(session->ctx, keylist_curr->value, &key, 1);
vb@2539
  2016
        gpgme_error = _GPGERR(gpgme_error);
vb@2539
  2017
        assert(gpgme_error != GPG_ERR_ENOMEM);
vb@2539
  2018
        switch (gpgme_error) {
vb@2539
  2019
            case GPG_ERR_NO_ERROR:
vb@2539
  2020
                break;
vb@2539
  2021
            case GPG_ERR_EOF:
vb@2539
  2022
                status = PEP_KEY_NOT_FOUND;
vb@2539
  2023
                break;
vb@2539
  2024
            case GPG_ERR_INV_VALUE:
vb@2539
  2025
                status = PEP_ILLEGAL_VALUE;
vb@2539
  2026
                break;
vb@2539
  2027
            case GPG_ERR_AMBIGUOUS_NAME:
vb@2539
  2028
                status = PEP_KEY_HAS_AMBIG_NAME;
vb@2539
  2029
                break;
vb@2539
  2030
            case GPG_ERR_ENOMEM:
vb@2539
  2031
                free_stringlist(result_list);
vb@2539
  2032
                free_stringlist(private_keylist);
vb@2539
  2033
                return PEP_OUT_OF_MEMORY;
vb@2539
  2034
            default:
vb@2539
  2035
                assert(0);
vb@2539
  2036
                status = PEP_UNKNOWN_ERROR;
vb@2539
  2037
        }
vb@2539
  2038
        if (key && gpgme_error == GPG_ERR_NO_ERROR) {
vb@2539
  2039
            if (key->revoked || key->disabled) {
vb@2539
  2040
                status = PEP_KEY_UNSUITABLE;
krista@2416
  2041
            }
vb@2539
  2042
            else {
vb@2539
  2043
                if (key->fpr && key->secret && key->can_encrypt && key->can_sign) {
vb@2539
  2044
                    if (key->owner_trust == GPGME_VALIDITY_ULTIMATE &&
vb@2539
  2045
                            key->uids && key->uids->email && key->uids->name) { 
vb@2539
  2046
                        _result_list = stringlist_add(_result_list, key->fpr);
vb@2539
  2047
                        if (!_result_list) {
vb@2539
  2048
                            free_stringlist(result_list);
vb@2539
  2049
                            free_stringlist(private_keylist);
vb@2539
  2050
                            return PEP_OUT_OF_MEMORY;
vb@2539
  2051
                        }
vb@2539
  2052
                        _result_list = stringlist_add(_result_list, key->uids->email);
vb@2539
  2053
                        if (!_result_list) {
vb@2539
  2054
                            free_stringlist(result_list);
vb@2539
  2055
                            free_stringlist(private_keylist);
vb@2539
  2056
                            return PEP_OUT_OF_MEMORY;
vb@2539
  2057
                        }
vb@2539
  2058
                        _result_list = stringlist_add(_result_list, key->uids->name);
vb@2539
  2059
                        if (!_result_list) {
vb@2539
  2060
                            free_stringlist(result_list);
vb@2539
  2061
                            free_stringlist(private_keylist);
vb@2539
  2062
                            return PEP_OUT_OF_MEMORY;
krista@2457
  2063
                        }
krista@2457
  2064
                    }
krista@2457
  2065
                }
krista@2416
  2066
            }
krista@2416
  2067
        }
krista@2416
  2068
    }
vb@2539
  2069
vb@2539
  2070
    free_stringlist(private_keylist);
vb@2539
  2071
    *keylist = result_list;
vb@2539
  2072
    return PEP_STATUS_OK;
krista@2416
  2073
}
krista@2416
  2074
vb@24
  2075
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
vb@24
  2076
{
vb@24
  2077
    gpgme_error_t gpgme_error;
vb@24
  2078
vb@24
  2079
    assert(session);
vb@24
  2080
    assert(pattern);
vb@24
  2081
vb@74
  2082
    gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
vb@24
  2083
        GPGME_EXPORT_MODE_EXTERN, NULL);
vb@45
  2084
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2085
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  2086
    if (gpgme_error == GPG_ERR_NO_ERROR)
vb@24
  2087
        return PEP_STATUS_OK;
vb@24
  2088
    else
vb@24
  2089
        return PEP_CANNOT_SEND_KEY;
vb@24
  2090
}
vb@24
  2091
vb@24
  2092
PEP_STATUS pgp_get_key_rating(
vb@24
  2093
    PEP_SESSION session,
vb@24
  2094
    const char *fpr,
vb@24
  2095
    PEP_comm_type *comm_type
vb@24
  2096
    )
vb@24
  2097
{
vb@24
  2098
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
  2099
    gpgme_error_t gpgme_error;
vb@24
  2100
    gpgme_key_t key;
vb@24
  2101
vb@24
  2102
    assert(session);
vb@24
  2103
    assert(fpr);
vb@24
  2104
    assert(comm_type);
vb@24
  2105
vb@24
  2106
    *comm_type = PEP_ct_unknown;
vb@24
  2107
vb@74
  2108
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
vb@45
  2109
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2110
    switch (gpgme_error) {
vb@24
  2111
    case GPG_ERR_NO_ERROR:
vb@24
  2112
        break;
vb@24
  2113
    case GPG_ERR_INV_VALUE:
vb@24
  2114
        assert(0);
vb@24
  2115
        return PEP_UNKNOWN_ERROR;
vb@24
  2116
    default:
vb@24
  2117
        return PEP_GET_KEY_FAILED;
vb@24
  2118
    };
vb@24
  2119
vb@74
  2120
    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  2121
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2122
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  2123
vb@24
  2124
    if (key == NULL) {
vb@74
  2125
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2126
        return PEP_KEY_NOT_FOUND;
vb@24
  2127
    }
vb@24
  2128
vb@24
  2129
    switch (key->protocol) {
vb@24
  2130
    case GPGME_PROTOCOL_OpenPGP:
vb@24
  2131
    case GPGME_PROTOCOL_DEFAULT:
vb@24
  2132
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
vb@24
  2133
        break;
vb@24
  2134
    case GPGME_PROTOCOL_CMS:
vb@24
  2135
        *comm_type = PEP_ct_CMS_unconfirmed;
vb@24
  2136
        break;
vb@24
  2137
    default:
vb@24
  2138
        *comm_type = PEP_ct_unknown;
vb@74
  2139
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2140
        return PEP_STATUS_OK;
vb@24
  2141
    }
vb@24
  2142
vb@24
  2143
    switch (gpgme_error) {
vb@24
  2144
    case GPG_ERR_EOF:
vb@24
  2145
        break;
vb@24
  2146
    case GPG_ERR_NO_ERROR:
vb@24
  2147
        assert(key);
vb@24
  2148
        assert(key->subkeys);
vb@24
  2149
        for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
vb@24
  2150
            if (sk->length < 1024)
vb@24
  2151
                *comm_type = PEP_ct_key_too_short;
vb@24
  2152
            else if (
vb@24
  2153
                (
vb@24
  2154
                (sk->pubkey_algo == GPGME_PK_RSA)
vb@24
  2155
                || (sk->pubkey_algo == GPGME_PK_RSA_E)
vb@24
  2156
                || (sk->pubkey_algo == GPGME_PK_RSA_S)
vb@24
  2157
                )
vb@24
  2158
                && sk->length == 1024
vb@24
  2159
                )
vb@122
  2160
                *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
vb@24
  2161
vb@24
  2162
            if (sk->invalid) {
vb@24
  2163
                *comm_type = PEP_ct_key_b0rken;
vb@24
  2164
                break;
vb@24
  2165
            }
vb@24
  2166
            if (sk->expired) {
vb@24
  2167
                *comm_type = PEP_ct_key_expired;
vb@24
  2168
                break;
vb@24
  2169
            }
vb@24
  2170
            if (sk->revoked) {
vb@24
  2171
                *comm_type = PEP_ct_key_revoked;
vb@24
  2172
                break;
vb@24
  2173
            }
vb@24
  2174
        }
vb@24
  2175
        break;
vb@24
  2176
    case GPG_ERR_ENOMEM:
vb@74
  2177
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2178
        *comm_type = PEP_ct_unknown;
vb@24
  2179
        return PEP_OUT_OF_MEMORY;
vb@24
  2180
    default:
vb@74
  2181
        gpg.gpgme_op_keylist_end(session->ctx);
vb@46
  2182
        return PEP_UNKNOWN_ERROR;
vb@24
  2183
    };
vb@24
  2184
vb@74
  2185
    gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2186
vb@24
  2187
    return status;
vb@24
  2188
}
vb@200
  2189
vb@200
  2190
krista@1924
  2191
static ssize_t _nullwriter(
krista@1924
  2192
        void *_handle,
krista@1924
  2193
        const void *buffer,
krista@1924
  2194
        size_t size
krista@1924
  2195
    )
krista@1924
  2196
{
krista@1924
  2197
    return size;
krista@1924
  2198
}
krista@1924
  2199
krista@1924
  2200
typedef struct _replace_only_uid_state {
krista@1924
  2201
    enum {
krista@1924
  2202
        replace_uid_command = 0,
krista@1924
  2203
        replace_uid_realname,
krista@1924
  2204
        replace_uid_email,
kgrothoff@1926
  2205
        replace_uid_comment,
krista@1924
  2206
        replace_uid_adduid_ok,
krista@1924
  2207
        replace_uid_select_for_delete,
krista@1924
  2208
        replace_uid_delete,
krista@1924
  2209
        replace_uid_delete_confirm,
krista@1924
  2210
        replace_uid_select_for_trust,
krista@1924
  2211
        replace_uid_trust,
krista@1924
  2212
        replace_uid_trust_ultimate,
krista@1924
  2213
        replace_uid_trust_ultimate_confirm,
krista@1924
  2214
        replace_uid_quit,
krista@1924
  2215
        replace_uid_save_okay,
krista@1924
  2216
        replace_uid_exit,
krista@1924
  2217
        replace_uid_error = -1
krista@1924
  2218
    } state;
krista@1924
  2219
const char *realname;
krista@1924
  2220
const char *email;
krista@1924
  2221
} replace_only_uid_state;
krista@1924
  2222
kgrothoff@1926
  2223
krista@1924
  2224
static gpgme_error_t replace_only_uid_fsm(
krista@1924
  2225
    void *_handle,
krista@1924
  2226
    gpgme_status_code_t statuscode,
krista@1924
  2227
    const char *args,
krista@1924
  2228
    int fd
krista@1924
  2229
)
krista@1924
  2230
{
krista@1924
  2231
    replace_only_uid_state *handle = _handle;
krista@1924
  2232
        
krista@1924
  2233
    switch (handle->state) {
krista@1924
  2234
        case replace_uid_command:
krista@1924
  2235
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2236
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2237
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2238
                    handle->state = replace_uid_error;
krista@1924
  2239
                    return GPG_ERR_GENERAL;
krista@1924
  2240
                }
krista@1924
  2241
                gpg.gpgme_io_write(fd, "adduid\n", 7);
krista@1924
  2242
                handle->state = replace_uid_realname;
krista@1924
  2243
            }
krista@1924
  2244
            break;
krista@1924
  2245
            
krista@1924
  2246
        case replace_uid_realname:
krista@1924
  2247
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2248
                assert(strcmp(args, "keygen.name") == 0);
krista@1924
  2249
                assert(handle->realname);
krista@1924
  2250
                if (strcmp(args, "keygen.name") || !handle->realname) {
krista@1924
  2251
                    handle->state = replace_uid_error;
krista@1924
  2252
                    return GPG_ERR_GENERAL;
krista@1924
  2253
                }
krista@1924
  2254
                size_t realname_strlen = strlen(handle->realname);
krista@1924
  2255
                char* realname = (char*)calloc(1, realname_strlen + 2); // \n + \0
krista@1924
  2256
                if (!realname) {
krista@1924
  2257
                    handle->state = replace_uid_error;
krista@1924
  2258
                    return GPG_ERR_ENOMEM;
krista@1924
  2259
                }
kgrothoff@1926
  2260
                strlcpy(realname, handle->realname, realname_strlen + 1);
roker@2055
  2261
                realname[realname_strlen] = '\n';
krista@1924
  2262
                gpg.gpgme_io_write(fd, realname, realname_strlen + 1);
krista@1924
  2263
                handle->state = replace_uid_email;
krista@1924
  2264
                free(realname);
krista@1924
  2265
            }
krista@1924
  2266
            break;
krista@1924
  2267
            
krista@1924
  2268
        case replace_uid_email:
krista@1924
  2269
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2270
                assert(strcmp(args, "keygen.email") == 0);
krista@1924
  2271
                assert(handle->email);
krista@1924
  2272
                if (strcmp(args, "keygen.email") || !handle->email) {
krista@1924
  2273
                    handle->state = replace_uid_error;
krista@1924
  2274
                    return GPG_ERR_GENERAL;
krista@1924
  2275
                }
krista@1924
  2276
                size_t email_strlen = strlen(handle->email);
krista@1924
  2277
                char* email = (char*)calloc(1, email_strlen + 2); // \n + \0
krista@1924
  2278
                if (!email) {
krista@1924
  2279
                    handle->state = replace_uid_error;
krista@1924
  2280
                    return GPG_ERR_ENOMEM;
krista@1924
  2281
                }
kgrothoff@1926
  2282
                strlcpy(email, handle->email, email_strlen + 1);
roker@2055
  2283
                email[email_strlen] = '\n';
krista@1924
  2284
                gpg.gpgme_io_write(fd, email, email_strlen + 1);
kgrothoff@1926
  2285
                handle->state = replace_uid_comment;
krista@1924
  2286
                free(email);
krista@1924
  2287
            }
krista@1924
  2288
            break;
krista@1924
  2289
kgrothoff@1926
  2290
        case replace_uid_comment:
kgrothoff@1926
  2291
            if (statuscode == GPGME_STATUS_GET_LINE) {
kgrothoff@1926
  2292
                assert(strcmp(args, "keygen.comment") == 0);
kgrothoff@1926
  2293
                if (strcmp(args, "keygen.comment") || !handle->email) {
kgrothoff@1926
  2294
                    handle->state = replace_uid_error;
kgrothoff@1926
  2295
                    return GPG_ERR_GENERAL;
kgrothoff@1926
  2296
                }
kgrothoff@1926
  2297
                gpg.gpgme_io_write(fd, "\n", 1);
kgrothoff@1926
  2298
                //handle->state = replace_uid_adduid_ok;
kgrothoff@1926
  2299
                handle->state = replace_uid_select_for_delete;
kgrothoff@1926
  2300
            }
kgrothoff@1926
  2301
            break;
kgrothoff@1926
  2302
/*
krista@1924
  2303
        case replace_uid_adduid_ok:
krista@1924
  2304
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2305
                assert(strcmp(args, "keygen.userid.cmd") == 0);
krista@1924
  2306
                if (strcmp(args, "keygen.userid.cmd")) {
krista@1924
  2307
                    handle->state = replace_uid_error;
krista@1924
  2308
                    return GPG_ERR_GENERAL;
krista@1924
  2309
                }
krista@1924
  2310
                gpg.gpgme_io_write(fd, "O\n", 2);
krista@1924
  2311
                handle->state = replace_uid_select_for_delete;
krista@1924
  2312
            }
krista@1924
  2313
            break;
kgrothoff@1926
  2314
	    */
krista@1924
  2315
krista@1924
  2316
        case replace_uid_select_for_delete:
krista@1924
  2317
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2318
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2319
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2320
                    handle->state = replace_uid_error;
krista@1924
  2321
                    return GPG_ERR_GENERAL;
krista@1924
  2322
                }
krista@1924
  2323
                gpg.gpgme_io_write(fd, "uid 1\n", 6);
krista@1924
  2324
                handle->state = replace_uid_delete;
krista@1924
  2325
            }
krista@1924
  2326
            break;
krista@1924
  2327
krista@1924
  2328
        case replace_uid_delete:
krista@1924
  2329
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2330
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2331
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2332
                    handle->state = replace_uid_error;
krista@1924
  2333
                    return GPG_ERR_GENERAL;
krista@1924
  2334
                }
krista@1924
  2335
                gpg.gpgme_io_write(fd, "deluid\n", 7);
krista@1924
  2336
                handle->state = replace_uid_delete_confirm;
krista@1924
  2337
            }
krista@1924
  2338
            break;
krista@1924
  2339
krista@1924
  2340
        case replace_uid_delete_confirm:
kgrothoff@1926
  2341
            if (statuscode == GPGME_STATUS_GET_BOOL) {
krista@1924
  2342
                assert(strcmp(args, "keyedit.remove.uid.okay") == 0);
krista@1924
  2343
                if (strcmp(args, "keyedit.remove.uid.okay")) {
krista@1924
  2344
                    handle->state = replace_uid_error;
krista@1924
  2345
                    return GPG_ERR_GENERAL;
krista@1924
  2346
                }
krista@1924
  2347
                gpg.gpgme_io_write(fd, "Y\n", 2);
krista@1924
  2348
                handle->state = replace_uid_select_for_trust;
krista@1924
  2349
            }
krista@1924
  2350
            break;
krista@1924
  2351
krista@1924
  2352
        case replace_uid_select_for_trust:
krista@1924
  2353
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2354
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2355
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2356
                    handle->state = replace_uid_error;
krista@1924
  2357
                    return GPG_ERR_GENERAL;
krista@1924
  2358
                }
kgrothoff@1926
  2359
                gpg.gpgme_io_write(fd, "uid 1\n", 6);
krista@1924
  2360
                handle->state = replace_uid_trust;
krista@1924
  2361
            }
krista@1924
  2362
            break;
krista@1924
  2363
krista@1924
  2364
        case replace_uid_trust:
krista@1924
  2365
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2366
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2367
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2368
                    handle->state = replace_uid_error;
krista@1924
  2369
                    return GPG_ERR_GENERAL;
krista@1924
  2370
                }
kgrothoff@1926
  2371
                gpg.gpgme_io_write(fd, "trust\n", 6);
krista@1924
  2372
                handle->state = replace_uid_trust_ultimate;
krista@1924
  2373
            }
krista@1924
  2374
            break;
krista@1924
  2375
krista@1924
  2376
        case replace_uid_trust_ultimate:
krista@1924
  2377
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2378
                assert(strcmp(args, "edit_ownertrust.value") == 0);
krista@1924
  2379
                if (strcmp(args, "edit_ownertrust.value")) {
krista@1924
  2380
                    handle->state = replace_uid_error;
krista@1924
  2381
                    return GPG_ERR_GENERAL;
krista@1924
  2382
                }
krista@1924
  2383
                gpg.gpgme_io_write(fd, "5\n", 2);
krista@1924
  2384
                handle->state = replace_uid_trust_ultimate_confirm;
krista@1924
  2385
            }
krista@1924
  2386
            break;
krista@1924
  2387
krista@1924
  2388
        case replace_uid_trust_ultimate_confirm:
kgrothoff@1926
  2389
            if (statuscode == GPGME_STATUS_GET_BOOL) {
krista@1924
  2390
                assert(strcmp(args, "edit_ownertrust.set_ultimate.okay") == 0);
krista@1924
  2391
                if (strcmp(args, "edit_ownertrust.set_ultimate.okay")) {
krista@1924
  2392
                    handle->state = replace_uid_error;
krista@1924
  2393
                    return GPG_ERR_GENERAL;
krista@1924
  2394
                }
krista@1924
  2395
                gpg.gpgme_io_write(fd, "Y\n", 2);
krista@1924
  2396
                handle->state = replace_uid_quit;
krista@1924
  2397
            }
krista@1924
  2398
            break;
krista@1924
  2399
krista@1924
  2400
        case replace_uid_quit:
krista@1924
  2401
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2402
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2403
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2404
                    handle->state = replace_uid_error;
krista@1924
  2405
                    return GPG_ERR_GENERAL;
krista@1924
  2406
                }
krista@1924
  2407
                gpg.gpgme_io_write(fd, "quit\n", 5);
krista@1924
  2408
                handle->state = replace_uid_save_okay;
krista@1924
  2409
            }
krista@1924
  2410
            break;
krista@1924
  2411
krista@1924
  2412
        case replace_uid_save_okay:
kgrothoff@1926
  2413
            if (statuscode == GPGME_STATUS_GET_BOOL) {
krista@1924
  2414
                assert(strcmp(args, "keyedit.save.okay") == 0);
krista@1924
  2415
                if (strcmp(args, "keyedit.save.okay")) {
krista@1924
  2416
                    handle->state = replace_uid_error;
krista@1924
  2417
                    return GPG_ERR_GENERAL;
krista@1924
  2418
                }
krista@1924
  2419
                gpg.gpgme_io_write(fd, "Y\n", 2);
krista@1924
  2420
                handle->state = replace_uid_exit;
krista@1924
  2421
            }
krista@1924
  2422
            break;
krista@1924
  2423
krista@1924
  2424
        case replace_uid_exit:
krista@1924
  2425
            break;
krista@1924
  2426
krista@1924
  2427
        case replace_uid_error:
krista@1924
  2428
            return GPG_ERR_GENERAL;
krista@1924
  2429
            
krista@1924
  2430
        default:
roker@2055
  2431
            break;
krista@1924
  2432
    }
krista@1924
  2433
    return GPG_ERR_NO_ERROR;
krista@1924
  2434
}
krista@1924
  2435
krista@1924
  2436
PEP_STATUS pgp_replace_only_uid(
krista@1924
  2437
        PEP_SESSION session,
krista@1924
  2438
        const char* fpr,
krista@1924
  2439
        const char* realname,
krista@1924
  2440
        const char* email
krista@1924
  2441
    )
krista@1924
  2442
{
krista@1924
  2443
    PEP_STATUS status = PEP_STATUS_OK;
krista@1924
  2444
    gpgme_error_t gpgme_error;
krista@1924
  2445
    gpgme_key_t key;
krista@1924
  2446
    gpgme_data_t output;
krista@1924
  2447
    replace_only_uid_state handle;
krista@1924
  2448
krista@1924
  2449
    assert(session);
krista@1924
  2450
    assert(fpr);
krista@1924
  2451
    assert(realname);
krista@1924
  2452
    assert(email);
krista@1924
  2453
    
krista@1924
  2454
    memset(&handle, 0, sizeof(replace_only_uid_state));
krista@1924
  2455
    handle.realname = realname;
krista@1924
  2456
    handle.email = email;
krista@1924
  2457
krista@1924
  2458
    status = find_single_key(session, fpr, &key);
krista@1924
  2459
    if (status != PEP_STATUS_OK)
krista@1924
  2460
        return status;
krista@1924
  2461
krista@1924
  2462
    struct gpgme_data_cbs data_cbs;
krista@1924
  2463
    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
krista@1924
  2464
    data_cbs.write = _nullwriter;
krista@1924
  2465
    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
krista@1924
  2466
krista@2553
  2467
    gpgme_error = _GPGERR(gpg.gpgme_op_edit(session->ctx, key, replace_only_uid_fsm, &handle,
krista@2553
  2468
            output));
krista@1924
  2469
    assert(gpgme_error == GPG_ERR_NO_ERROR);
krista@1924
  2470
    if(gpgme_error != GPG_ERR_NO_ERROR) {
krista@1924
  2471
        status = PEP_CANNOT_EDIT_KEY;
krista@1924
  2472
    }
krista@1924
  2473
krista@1924
  2474
    gpg.gpgme_data_release(output);
krista@1924
  2475
    gpg.gpgme_key_unref(key);
krista@1924
  2476
krista@1924
  2477
    return status;
krista@1924
  2478
}
krista@1924
  2479
krista@1924
  2480
vb@201
  2481
typedef struct _renew_state {
vb@211
  2482
    enum {
vb@200
  2483
        renew_command = 0,
vb@200
  2484
        renew_date,
vb@200
  2485
        renew_secret_key,
vb@200
  2486
        renew_command2,
vb@200
  2487
        renew_date2,
vb@200
  2488
        renew_quit,
vb@200
  2489
        renew_save,
vb@200
  2490
        renew_exit,
vb@200
  2491
        renew_error = -1
vb@200
  2492
    } state;
vb@201
  2493
    const char *date_ref;
vb@201
  2494
} renew_state;
vb@200
  2495
vb@201
  2496
static gpgme_error_t renew_fsm(
vb@200
  2497
        void *_handle,
vb@200
  2498
        gpgme_status_code_t statuscode,
vb@200
  2499
        const char *args,
vb@200
  2500
        int fd
vb@200
  2501
    )
vb@200
  2502
{
vb@201
  2503
    renew_state *handle = _handle;
vb@200
  2504
vb@200
  2505
    switch (handle->state) {
vb@200
  2506
        case renew_command:
vb@200
  2507
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2508
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  2509
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  2510
                    handle->state = renew_error;
vb@201
  2511
                    return GPG_ERR_GENERAL;
vb@201
  2512
                }
vb@223
  2513
                gpg.gpgme_io_write(fd, "expire\n", 7);
vb@200
  2514
                handle->state = renew_date;
vb@200
  2515
            }
vb@200
  2516
            break;
vb@200
  2517
vb@200
  2518
        case renew_date:
vb@200
  2519
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2520
                assert(strcmp(args, "keygen.valid") == 0);
vb@201
  2521
                if (strcmp(args, "keygen.valid")) {
vb@201
  2522
                    handle->state = renew_error;
vb@201
  2523
                    return GPG_ERR_GENERAL;
vb@201
  2524
                }
vb@223
  2525
                gpg.gpgme_io_write(fd, handle->date_ref, 11);
vb@200
  2526
                handle->state = renew_secret_key;
vb@200
  2527
            }
vb@200
  2528
            break;
vb@200
  2529
vb@200
  2530
        case renew_secret_key:
vb@200
  2531
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2532
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  2533
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  2534
                    handle->state = renew_error;
vb@201
  2535
                    return GPG_ERR_GENERAL;
vb@201
  2536
                }
vb@223
  2537
                gpg.gpgme_io_write(fd, "key 1\n", 6);
vb@200
  2538
                handle->state = renew_command2;
vb@200
  2539
            }
vb@200
  2540
            break;
vb@200
  2541
vb@200
  2542
        case renew_command2:
vb@200
  2543
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2544
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  2545
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  2546
                    handle->state = renew_error;
vb@201
  2547
                    return GPG_ERR_GENERAL;
vb@201
  2548
                }
vb@223
  2549
                gpg.gpgme_io_write(fd, "expire\n", 7);
vb@200
  2550
                handle->state = renew_date2;
vb@200
  2551
            }
vb@200
  2552
            break;
vb@200
  2553
vb@200
  2554
        case renew_date2:
vb@200
  2555
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2556
                assert(strcmp(args, "keygen.valid") == 0);
vb@201
  2557
                if (strcmp(args, "keygen.valid")) {
vb@201
  2558
                    handle->state = renew_error;
vb@201
  2559
                    return GPG_ERR_GENERAL;
vb@201
  2560
                }
vb@223
  2561
                gpg.gpgme_io_write(fd, handle->date_ref, 11);
vb@200
  2562
                handle->state = renew_quit;
vb@200
  2563
            }
vb@200
  2564
            break;
vb@200
  2565
vb@200
  2566
        case renew_quit:
vb@200
  2567
            if (statuscode == GPGME_STATUS_GET_LINE) {
vb@201
  2568
                assert(strcmp(args, "keyedit.prompt") == 0);
vb@201
  2569
                if (strcmp(args, "keyedit.prompt")) {
vb@201
  2570
                    handle->state = renew_error;
vb@201
  2571
                    return GPG_ERR_GENERAL;
vb@201
  2572
                }
vb@223
  2573
                gpg.gpgme_io_write(fd, "quit\n", 5);
vb@200
  2574
                handle->state = renew_save;
vb@200
  2575
            }
vb@200
  2576
            break;
vb@200
  2577
vb@200
  2578
        case renew_save:
vb@200
  2579
            if (statuscode == GPGME_STATUS_GET_BOOL) {
vb@201
  2580
                assert(strcmp(args, "keyedit.save.okay") == 0);
vb@201
  2581
                if (strcmp(args, "keyedit.save.okay")) {
vb@201
  2582
                    handle->state = renew_error;
vb@201
  2583
                    return GPG_ERR_GENERAL;
vb@201
  2584
                }
vb@223
  2585
                gpg.gpgme_io_write(fd, "Y\n", 2);
vb@200
  2586
                handle->state = renew_exit;
vb@200
  2587
            }
vb@200
  2588
            break;
vb@200
  2589
vb@200
  2590
        case renew_exit:
vb@200
  2591
            break;
vb@200
  2592
vb@200
  2593
        case renew_error:
vb@200
  2594
            return GPG_ERR_GENERAL;
vb@200
  2595
    }
vb@200
  2596
vb@200
  2597
    return GPG_ERR_NO_ERROR;
vb@200
  2598
}
vb@200
  2599
vb@200
  2600
vb@201
  2601
PEP_STATUS pgp_renew_key(
vb@201
  2602
        PEP_SESSION session,
vb@201
  2603
        const char *fpr,
vb@201
  2604
        const timestamp *ts
vb@201
  2605
    )
vb@200
  2606
{
vb@200
  2607
    PEP_STATUS status = PEP_STATUS_OK;
vb@200
  2608
    gpgme_error_t gpgme_error;
vb@200
  2609
    gpgme_key_t key;
vb@200
  2610
    gpgme_data_t output;
vb@201
  2611
    renew_state handle;
vb@203
  2612
    char date_text[12];
vb@200
  2613
vb@200
  2614
    assert(session);
vb@200
  2615
    assert(fpr);
vb@200
  2616
vb@201
  2617
    memset(&handle, 0, sizeof(renew_state));
vb@203
  2618
    snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
vb@201
  2619
            ts->tm_mon + 1, ts->tm_mday);
vb@201
  2620
    handle.date_ref = date_text;
vb@200
  2621
vb@200
  2622
    status = find_single_key(session, fpr, &key);
vb@200
  2623
    if (status != PEP_STATUS_OK)
vb@200
  2624
        return status;
vb@200
  2625
vb@200
  2626
    struct gpgme_data_cbs data_cbs;
vb@200
  2627
    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
vb@200
  2628
    data_cbs.write = _nullwriter;
vb@220
  2629
    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
vb@200<