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