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