src/pgp_netpgp.c
author Krista Bennett <krista@pep-project.org>
Tue, 01 Aug 2017 16:40:24 +0200
branchmessage-2.0
changeset 1979 3d0a778d035a
parent 1776 43db1100ebd2
child 2458 2dfe65bd3613
permissions -rw-r--r--
Changed name to ENGINE-214 for JIRA tracking - please use that branch instead.
vb@1513
     1
// This file is under GNU General Public License 3.0
vb@1513
     2
// see LICENSE.txt
vb@1513
     3
Edouard@174
     4
#include "pEp_internal.h"
Edouard@174
     5
#include "pgp_netpgp.h"
Edouard@174
     6
Edouard@174
     7
#include <limits.h>
Edouard@174
     8
Edouard@174
     9
#include "wrappers.h"
Edouard@174
    10
vb@334
    11
#include "netpgp.h"
dirk@533
    12
#include <netpgp/config.h>
dirk@533
    13
#include <netpgp/memory.h>
dirk@533
    14
#include <netpgp/crypto.h>
dirk@533
    15
#include <netpgp/netpgpsdk.h>
dirk@533
    16
#include <netpgp/validate.h>
dirk@533
    17
#include <netpgp/readerwriter.h>
Edouard@179
    18
Edouard@252
    19
#include <curl/curl.h>
Edouard@252
    20
#include <pthread.h>
Edouard@188
    21
#include <regex.h>
Edouard@188
    22
Edouard@252
    23
static netpgp_t netpgp;
Edouard@254
    24
static pthread_mutex_t netpgp_mutex;
Edouard@252
    25
Edouard@263
    26
static PEP_STATUS init_netpgp()
Edouard@174
    27
{
Edouard@174
    28
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@175
    29
    const char *home = NULL;
Edouard@179
    30
Edouard@252
    31
    if(pthread_mutex_init(&netpgp_mutex, NULL)){
Edouard@252
    32
        return PEP_OUT_OF_MEMORY;
Edouard@252
    33
    }
Edouard@252
    34
Edouard@263
    35
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
    36
        return PEP_UNKNOWN_ERROR;
Edouard@252
    37
    }
Edouard@252
    38
Edouard@263
    39
    if (strcmp(setlocale(LC_ALL, NULL), "C") == 0)
Edouard@263
    40
        setlocale(LC_ALL, "");
Edouard@252
    41
Edouard@263
    42
    memset(&netpgp, 0x0, sizeof(netpgp_t));
Edouard@252
    43
Edouard@263
    44
    // netpgp_setvar(&netpgp, "max mem alloc", "4194304");
Edouard@263
    45
    netpgp_setvar(&netpgp, "need seckey", "1");
Edouard@315
    46
    // netpgp_setvar(&netpgp, "need userid", "1");
Edouard@252
    47
Edouard@263
    48
    // NetPGP shares home with GPG
Edouard@263
    49
    home = gpg_home();
Edouard@263
    50
    if(home){
Edouard@263
    51
        netpgp_set_homedir(&netpgp,(char*)home, NULL, 0);
Edouard@263
    52
    }else{
Edouard@263
    53
        status = PEP_INIT_NO_GPG_HOME;
Edouard@263
    54
        goto unlock_netpgp;
Edouard@174
    55
    }
Edouard@174
    56
Edouard@263
    57
    // pair with gpg's cert-digest-algo
Edouard@263
    58
    netpgp_setvar(&netpgp, "hash", "SHA256");
Edouard@263
    59
Edouard@263
    60
    // subset of gpg's personal-cipher-preferences
Edouard@263
    61
    // here only one cipher can be selected
Edouard@263
    62
    netpgp_setvar(&netpgp, "cipher", "CAST5");
Edouard@263
    63
Edouard@263
    64
    if (!netpgp_init(&netpgp)) {
Edouard@263
    65
        status = PEP_INIT_NETPGP_INIT_FAILED;
Edouard@263
    66
        goto unlock_netpgp;
Edouard@263
    67
    }
Edouard@174
    68
Edouard@315
    69
    // netpgp_set_debug("packet-parse.c");
Edouard@315
    70
Edouard@252
    71
unlock_netpgp:
Edouard@252
    72
    pthread_mutex_unlock(&netpgp_mutex);
krista@1435
    73
Edouard@263
    74
    return status;
Edouard@263
    75
}
Edouard@180
    76
Edouard@263
    77
static void release_netpgp()
Edouard@263
    78
{
Edouard@263
    79
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@263
    80
        return;
Edouard@263
    81
    }
Edouard@263
    82
    netpgp_end(&netpgp);
Edouard@263
    83
    memset(&netpgp, 0x0, sizeof(netpgp_t));
Edouard@263
    84
Edouard@263
    85
    pthread_mutex_destroy(&netpgp_mutex);
Edouard@263
    86
Edouard@263
    87
    return;
Edouard@263
    88
}
Edouard@263
    89
Edouard@263
    90
static PEP_STATUS init_curl(
Edouard@263
    91
    pthread_mutex_t *curl_mutex,
Edouard@263
    92
    bool in_first)
Edouard@263
    93
{
Edouard@263
    94
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@263
    95
Edouard@263
    96
    if(pthread_mutex_init(curl_mutex, NULL)){
Edouard@263
    97
        return PEP_OUT_OF_MEMORY;
Edouard@174
    98
    }
Edouard@174
    99
Edouard@263
   100
    if(pthread_mutex_lock(curl_mutex)){
Edouard@263
   101
        return PEP_UNKNOWN_ERROR;
Edouard@263
   102
    }
Edouard@263
   103
Edouard@263
   104
    if(in_first){
Edouard@263
   105
        curl_global_init(CURL_GLOBAL_DEFAULT);
Edouard@263
   106
    }
Edouard@263
   107
Edouard@322
   108
    pthread_mutex_unlock(curl_mutex);
Edouard@322
   109
    return status;
Edouard@322
   110
}
Edouard@322
   111
Edouard@322
   112
static void release_curl(
krista@1435
   113
    pthread_mutex_t *curl_mutex,
Edouard@322
   114
    bool out_last)
Edouard@322
   115
{
Edouard@322
   116
    if(pthread_mutex_lock(curl_mutex)){
Edouard@322
   117
        return;
Edouard@322
   118
    }
Edouard@322
   119
Edouard@322
   120
    if(out_last){
Edouard@322
   121
        curl_global_cleanup();
Edouard@322
   122
    }
Edouard@322
   123
Edouard@322
   124
    pthread_mutex_destroy(curl_mutex);
Edouard@322
   125
Edouard@322
   126
    return;
Edouard@322
   127
}
Edouard@322
   128
Edouard@322
   129
static PEP_STATUS curl_get_ctx(
Edouard@322
   130
    CURL **curl)
Edouard@322
   131
{
Edouard@322
   132
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@322
   133
    struct curl_slist *headers=NULL;
Edouard@322
   134
Edouard@263
   135
    if ((*curl = curl_easy_init()) == NULL) {
Edouard@263
   136
        return PEP_OUT_OF_MEMORY;
Edouard@263
   137
    }
Edouard@263
   138
Edouard@263
   139
    curl_easy_setopt(*curl, CURLOPT_FOLLOWLOCATION, 1L);
Edouard@263
   140
    curl_easy_setopt(*curl, CURLOPT_MAXREDIRS, 3L);
Edouard@263
   141
Edouard@263
   142
    headers=curl_slist_append(headers,"Pragma: no-cache");
Edouard@263
   143
    if(headers)
Edouard@263
   144
        headers=curl_slist_append(headers,"Cache-Control: no-cache");
Edouard@263
   145
Edouard@263
   146
    if(!headers)
Edouard@263
   147
    {
Edouard@322
   148
        return PEP_OUT_OF_MEMORY;
Edouard@263
   149
    }
Edouard@263
   150
Edouard@263
   151
    curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
Edouard@263
   152
    curl_slist_free_all(headers);
Edouard@263
   153
Edouard@263
   154
    // TODO curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
Edouard@174
   155
    return status;
Edouard@174
   156
}
Edouard@174
   157
Edouard@322
   158
static void curl_release_ctx(
Edouard@322
   159
    CURL **curl)
Edouard@263
   160
{
Edouard@263
   161
    if(*curl)
Edouard@263
   162
        curl_easy_cleanup(*curl);
Edouard@263
   163
Edouard@263
   164
    *curl = NULL;
Edouard@263
   165
Edouard@263
   166
    return;
Edouard@263
   167
}
Edouard@263
   168
Edouard@263
   169
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
Edouard@263
   170
{
Edouard@263
   171
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@263
   172
Edouard@263
   173
    assert(session);
Edouard@661
   174
    if(!session) return PEP_ILLEGAL_VALUE;
Edouard@263
   175
Edouard@263
   176
    if (in_first) {
Edouard@263
   177
        if((status = init_netpgp()) != PEP_STATUS_OK)
Edouard@263
   178
        return status;
Edouard@263
   179
    }
Edouard@263
   180
Edouard@263
   181
    if((status = init_curl(
Edouard@263
   182
                    &session->ctx.curl_mutex,
Edouard@263
   183
                    in_first) != PEP_STATUS_OK)){
Edouard@263
   184
        if(in_first) release_netpgp();
Edouard@263
   185
        return status;
Edouard@263
   186
    }
Edouard@263
   187
Edouard@263
   188
    return PEP_STATUS_OK;
Edouard@263
   189
}
Edouard@263
   190
Edouard@174
   191
void pgp_release(PEP_SESSION session, bool out_last)
Edouard@174
   192
{
Edouard@179
   193
    assert(session);
Edouard@179
   194
    if(!session) return;
Edouard@179
   195
Edouard@263
   196
    if (out_last){
Edouard@263
   197
        release_netpgp();
Edouard@252
   198
    }
Edouard@322
   199
    release_curl(&session->ctx.curl_mutex, out_last);
Edouard@174
   200
}
Edouard@174
   201
Edouard@446
   202
// return 1 if the file contains ascii-armoured text
Edouard@188
   203
static unsigned
Edouard@188
   204
_armoured(const char *buf, size_t size, const char *pattern)
Edouard@188
   205
{
Edouard@188
   206
    unsigned armoured = 0;
Edouard@446
   207
    regex_t r;
Edouard@446
   208
    regcomp(&r, pattern, REG_EXTENDED|REG_NOSUB);
Edouard@446
   209
    if (regnexec(&r, buf, size, 0, NULL, 0) == 0) {
Edouard@446
   210
        armoured = 1;
Edouard@188
   211
    }
Edouard@446
   212
    regfree(&r);
Edouard@188
   213
    return armoured;
Edouard@188
   214
}
Edouard@188
   215
Edouard@393
   216
/* write key fingerprint hexdump as a string */
Edouard@393
   217
static unsigned
Edouard@393
   218
fpr_to_str (char **str, const uint8_t *fpr, size_t length)
Edouard@393
   219
{
Edouard@393
   220
    unsigned i;
Edouard@393
   221
    int	n;
krista@1435
   222
Edouard@491
   223
    /* 4 hexes per short + null */
Edouard@490
   224
    *str = malloc((length / 2) * 4 + 1);
krista@1435
   225
Edouard@393
   226
    if(*str == NULL)
Edouard@393
   227
        return 0;
krista@1435
   228
Edouard@489
   229
    for (n = 0, i = 0 ; i < length; i += 2) {
edouard@1695
   230
        n += snprintf(&((*str)[n]), 5, "%02X%02X", fpr[i], fpr[i+1]);
Edouard@393
   231
    }
krista@1435
   232
Edouard@393
   233
    return 1;
Edouard@393
   234
}
Edouard@393
   235
Edouard@393
   236
/* write key fingerprint bytes read from hex string
Edouard@393
   237
 * accept spaces and hexes */
Edouard@393
   238
static unsigned
Edouard@393
   239
str_to_fpr (const char *str, uint8_t *fpr, size_t *length)
Edouard@393
   240
{
Edouard@393
   241
    unsigned i,j;
krista@1435
   242
Edouard@393
   243
    *length = 0;
edouard@1775
   244
    
edouard@1775
   245
    if (str == NULL)
edouard@1775
   246
        return 0;
krista@1435
   247
Edouard@393
   248
    while(*str && *length < PGP_FINGERPRINT_SIZE){
Edouard@393
   249
        while (*str == ' ') str++;
Edouard@393
   250
        for (j = 0; j < 2; j++) {
Edouard@393
   251
            uint8_t *byte = &fpr[*length];
Edouard@393
   252
            *byte = 0;
Edouard@393
   253
            for (i = 0; i < 2; i++) {
Edouard@393
   254
                if (i > 0)
Edouard@393
   255
                    *byte = *byte << 4;
Edouard@393
   256
                if (*str >= 'a' && *str <= 'f')
Edouard@393
   257
                    *byte += 10 + *str - 'a';
Edouard@393
   258
                else if (*str >= 'A' && *str <= 'F')
Edouard@393
   259
                    *byte += 10 + *str - 'A';
Edouard@393
   260
                else if (*str >= '0' && *str <= '9')
Edouard@393
   261
                    *byte += *str - '0';
Edouard@393
   262
                else
Edouard@393
   263
                    return 0;
Edouard@393
   264
                str++;
Edouard@393
   265
            }
Edouard@393
   266
            (*length)++;
Edouard@393
   267
        }
Edouard@393
   268
    }
Edouard@393
   269
    return 1;
Edouard@393
   270
}
Edouard@393
   271
krista@1435
   272
// Iterate through netpgp' reported valid signatures
Edouard@185
   273
// fill a list of valid figerprints
Edouard@185
   274
// returns PEP_STATUS_OK if all sig reported valid
Edouard@185
   275
// error status otherwise.
Edouard@279
   276
static PEP_STATUS _validation_results(
Edouard@279
   277
        netpgp_t *netpgp,
Edouard@279
   278
        pgp_validation_t *vresult,
edouard@1694
   279
        stringlist_t **keylist
Edouard@279
   280
    )
Edouard@185
   281
{
Edouard@188
   282
    time_t    now;
Edouard@188
   283
    time_t    t;
Edouard@185
   284
edouard@1694
   285
    *keylist = NULL;
edouard@1694
   286
Edouard@188
   287
    now = time(NULL);
Edouard@188
   288
    if (now < vresult->birthtime) {
Edouard@188
   289
        // signature is not valid yet
Edouard@431
   290
        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@188
   291
    }
Edouard@188
   292
    if (vresult->duration != 0 && now > vresult->birthtime + vresult->duration) {
Edouard@188
   293
        // signature has expired
Edouard@188
   294
        t = vresult->duration + vresult->birthtime;
Edouard@431
   295
        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@188
   296
    }
Edouard@185
   297
    if (vresult->validc && vresult->valid_sigs &&
Edouard@185
   298
        !vresult->invalidc && !vresult->unknownc ) {
roker@1559
   299
        
edouard@1694
   300
        stringlist_t *_keylist;
edouard@1694
   301
Edouard@185
   302
        // caller responsible to free
edouard@1694
   303
        _keylist = new_stringlist(NULL);
edouard@1694
   304
        assert(_keylist);
edouard@1694
   305
        if (_keylist == NULL) {
Edouard@185
   306
            return PEP_OUT_OF_MEMORY;
Edouard@185
   307
        }
roker@1559
   308
        
edouard@1694
   309
        stringlist_t *k = _keylist;
edouard@1694
   310
        unsigned c = 0;
roker@1559
   311
        for (unsigned n = 0; n < vresult->validc; ++n) {
Edouard@393
   312
            unsigned from = 0;
Edouard@393
   313
            const pgp_key_t	 *signer;
Edouard@393
   314
            char *fprstr = NULL;
Edouard@315
   315
            const uint8_t *keyid = vresult->valid_sigs[n].signer_id;
krista@1435
   316
Edouard@393
   317
            signer = pgp_getkeybyid(netpgp->io, netpgp->pubring,
Edouard@393
   318
                                    keyid, &from, NULL, NULL,
krista@1435
   319
                                    0, 0); /* check neither revocation nor expiry
Edouard@393
   320
                                              as is should be checked already */
Edouard@393
   321
            if(signer)
Edouard@393
   322
                fpr_to_str(&fprstr,
Edouard@393
   323
                           signer->pubkeyfpr.fingerprint,
Edouard@393
   324
                           signer->pubkeyfpr.length);
Edouard@393
   325
            else
edouard@1694
   326
                continue;
krista@1435
   327
edouard@1694
   328
            if (fprstr == NULL){
edouard@1694
   329
                free_stringlist(_keylist);
Edouard@393
   330
                return PEP_OUT_OF_MEMORY;
edouard@1694
   331
            }
krista@1435
   332
Edouard@393
   333
            k = stringlist_add(k, fprstr);
krista@1435
   334
Edouard@393
   335
            free(fprstr);
krista@1435
   336
Edouard@185
   337
            if(!k){
edouard@1694
   338
                free_stringlist(_keylist);
Edouard@185
   339
                return PEP_OUT_OF_MEMORY;
Edouard@185
   340
            }
edouard@1694
   341
edouard@1694
   342
            c++;
Edouard@185
   343
        }
edouard@1694
   344
        if(c > 0) {
edouard@1694
   345
            *keylist = _keylist;
edouard@1694
   346
            return PEP_STATUS_OK;
edouard@1694
   347
        }
edouard@1694
   348
edouard@1694
   349
        free_stringlist(_keylist);
edouard@1694
   350
        return PEP_VERIFY_NO_KEY;
Edouard@185
   351
    }
Edouard@185
   352
    if (vresult->validc + vresult->invalidc + vresult->unknownc == 0) {
Edouard@185
   353
        // No signatures found - is this memory signed?
krista@1435
   354
        return PEP_VERIFY_NO_KEY;
krista@1435
   355
    }
krista@1435
   356
Edouard@185
   357
    if (vresult->invalidc) {
Edouard@185
   358
        // some invalid signatures
Edouard@185
   359
        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@185
   360
    }
krista@1435
   361
Edouard@185
   362
    // only unknown sigs
Edouard@431
   363
    return PEP_DECRYPTED;
Edouard@185
   364
}
Edouard@185
   365
Edouard@389
   366
#define _ENDL    "\\s*(\r\n|\r|\n)"
Edouard@389
   367
#define ARMOR_HEAD    "^-----BEGIN PGP MESSAGE-----"_ENDL
Edouard@174
   368
PEP_STATUS pgp_decrypt_and_verify(
Edouard@174
   369
    PEP_SESSION session, const char *ctext, size_t csize,
krista@1435
   370
    const char *dsigtext, size_t dsigsize,
Edouard@174
   371
    char **ptext, size_t *psize, stringlist_t **keylist
Edouard@174
   372
    )
Edouard@174
   373
{
Edouard@180
   374
    char *_ptext = NULL;
Edouard@179
   375
Edouard@174
   376
    PEP_STATUS result;
Edouard@174
   377
    stringlist_t *_keylist = NULL;
Edouard@174
   378
Edouard@174
   379
    assert(session);
Edouard@174
   380
    assert(ctext);
Edouard@174
   381
    assert(csize);
Edouard@174
   382
    assert(ptext);
Edouard@174
   383
    assert(psize);
Edouard@174
   384
    assert(keylist);
Edouard@174
   385
krista@1435
   386
    if(!session || !ctext || !csize || !ptext || !psize || !keylist)
Edouard@661
   387
        return PEP_ILLEGAL_VALUE;
Edouard@179
   388
Edouard@263
   389
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   390
        return PEP_UNKNOWN_ERROR;
Edouard@252
   391
    }
Edouard@179
   392
Edouard@174
   393
    *ptext = NULL;
Edouard@174
   394
    *psize = 0;
Edouard@174
   395
    *keylist = NULL;
Edouard@174
   396
roker@1559
   397
    pgp_validation_t *vresult = malloc(sizeof(pgp_validation_t));
Edouard@185
   398
    memset(vresult, 0x0, sizeof(pgp_validation_t));
Edouard@182
   399
edouard@1694
   400
    key_id_t *recipients_key_ids = NULL;
edouard@1694
   401
    unsigned recipients_count = 0;
edouard@1694
   402
roker@1559
   403
    pgp_memory_t *mem = pgp_decrypt_and_validate_buf(netpgp.io, vresult, ctext, csize,
Edouard@252
   404
                netpgp.secring, netpgp.pubring,
Edouard@188
   405
                _armoured(ctext, csize, ARMOR_HEAD),
edouard@1694
   406
                 &recipients_key_ids, &recipients_count);
edouard@1694
   407
Edouard@179
   408
    if (mem == NULL) {
Edouard@252
   409
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   410
        goto unlock_netpgp;
Edouard@179
   411
    }
Edouard@179
   412
roker@1559
   413
    const size_t _psize = pgp_mem_len(mem);
Edouard@182
   414
    if (_psize){
Edouard@272
   415
        if ((_ptext = malloc(_psize + 1)) == NULL) {
Edouard@183
   416
            result = PEP_OUT_OF_MEMORY;
Edouard@183
   417
            goto free_pgp;
Edouard@182
   418
        }
Edouard@185
   419
        memcpy(_ptext, pgp_mem_data(mem), _psize);
Edouard@272
   420
        _ptext[_psize] = '\0'; // safeguard for naive users
Edouard@182
   421
        result = PEP_DECRYPTED;
Edouard@182
   422
    }else{
Edouard@183
   423
        result = PEP_DECRYPT_NO_KEY;
Edouard@183
   424
        goto free_pgp;
Edouard@182
   425
    }
Edouard@182
   426
Edouard@185
   427
    if (result == PEP_DECRYPTED) {
Edouard@252
   428
        result = _validation_results(&netpgp, vresult, &_keylist);
edouard@1694
   429
        if (result == PEP_DECRYPTED ||
edouard@1694
   430
            result == PEP_VERIFY_NO_KEY) {
edouard@1695
   431
            if((_keylist = new_stringlist("")) == NULL) {
edouard@1694
   432
                result = PEP_OUT_OF_MEMORY;
edouard@1695
   433
                goto free_ptext;
edouard@1694
   434
            }
Edouard@449
   435
            result = PEP_DECRYPTED;
Edouard@431
   436
        }else if (result != PEP_STATUS_OK) {
Edouard@185
   437
            goto free_ptext;
Edouard@431
   438
        }else{
Edouard@431
   439
            result = PEP_DECRYPTED_AND_VERIFIED;
Edouard@183
   440
        }
Edouard@180
   441
    }
Edouard@174
   442
edouard@1694
   443
    stringlist_t *k = _keylist;
edouard@1694
   444
    for (unsigned n = 0; n < recipients_count; ++n) {
edouard@1694
   445
        unsigned from = 0;
edouard@1694
   446
        const pgp_key_t	 *rcpt;
edouard@1694
   447
        char *fprstr = NULL;
edouard@1694
   448
        key_id_t *keyid = &recipients_key_ids[n];
edouard@1694
   449
edouard@1694
   450
        rcpt = pgp_getkeybyid(netpgp.io, netpgp.pubring,
edouard@1694
   451
                                *keyid, &from, NULL, NULL,
edouard@1694
   452
                                0, 0); /* check neither revocation nor expiry*/
edouard@1694
   453
        if(rcpt)
edouard@1694
   454
            fpr_to_str(&fprstr,
edouard@1694
   455
                       rcpt->pubkeyfpr.fingerprint,
edouard@1694
   456
                       rcpt->pubkeyfpr.length);
edouard@1694
   457
        else
edouard@1694
   458
            // if no key found put ID instead of fpr
edouard@1694
   459
            fpr_to_str(&fprstr,
edouard@1694
   460
                       *keyid,
edouard@1694
   461
                       sizeof(key_id_t));
edouard@1694
   462
edouard@1694
   463
        if (fprstr == NULL){
edouard@1695
   464
            result = PEP_OUT_OF_MEMORY;
edouard@1695
   465
            goto free_keylist;
edouard@1694
   466
        }
edouard@1694
   467
edouard@1694
   468
        k = stringlist_add_unique(k, fprstr);
edouard@1694
   469
edouard@1694
   470
        free(fprstr);
edouard@1694
   471
edouard@1694
   472
        if(!k){
edouard@1695
   473
            result = PEP_OUT_OF_MEMORY;
edouard@1695
   474
            goto free_keylist;
edouard@1694
   475
        }
edouard@1694
   476
    }
edouard@1694
   477
Edouard@180
   478
    if (result == PEP_DECRYPTED_AND_VERIFIED
Edouard@180
   479
        || result == PEP_DECRYPTED) {
Edouard@180
   480
        *ptext = _ptext;
Edouard@180
   481
        *psize = _psize;
Edouard@180
   482
        (*ptext)[*psize] = 0; // safeguard for naive users
edouard@1695
   483
        *keylist = _keylist;
Edouard@183
   484
Edouard@183
   485
        /* _ptext and _keylist ownership transfer, don't free */
Edouard@183
   486
        goto free_pgp;
Edouard@180
   487
    }
Edouard@183
   488
edouard@1694
   489
free_keylist:
Edouard@183
   490
    free_stringlist(_keylist);
Edouard@183
   491
Edouard@183
   492
free_ptext:
Edouard@183
   493
    free(_ptext);
Edouard@183
   494
Edouard@183
   495
free_pgp:
Edouard@185
   496
    pgp_memory_free(mem);
Edouard@183
   497
    pgp_validate_result_free(vresult);
Edouard@183
   498
Edouard@252
   499
unlock_netpgp:
Edouard@252
   500
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   501
Edouard@174
   502
    return result;
Edouard@174
   503
}
Edouard@174
   504
Edouard@389
   505
#define ARMOR_SIG_HEAD    "^-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"_ENDL
Edouard@174
   506
PEP_STATUS pgp_verify_text(
Edouard@174
   507
    PEP_SESSION session, const char *text, size_t size,
Edouard@174
   508
    const char *signature, size_t sig_size, stringlist_t **keylist
Edouard@174
   509
    )
Edouard@174
   510
{
Edouard@185
   511
    pgp_memory_t *signedmem;
Edouard@185
   512
    pgp_memory_t *sig;
Edouard@185
   513
    pgp_validation_t *vresult;
Edouard@185
   514
Edouard@174
   515
    PEP_STATUS result;
Edouard@174
   516
    stringlist_t *_keylist;
Edouard@174
   517
Edouard@174
   518
    assert(session);
Edouard@174
   519
    assert(text);
Edouard@174
   520
    assert(size);
Edouard@174
   521
    assert(signature);
Edouard@174
   522
    assert(sig_size);
Edouard@174
   523
    assert(keylist);
Edouard@174
   524
krista@1435
   525
    if(!session || !text || !size || !signature || !sig_size || !keylist)
Edouard@661
   526
        return PEP_ILLEGAL_VALUE;
Edouard@185
   527
Edouard@263
   528
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   529
        return PEP_UNKNOWN_ERROR;
Edouard@252
   530
    }
Edouard@185
   531
Edouard@174
   532
    *keylist = NULL;
Edouard@185
   533
Edouard@185
   534
    vresult = malloc(sizeof(pgp_validation_t));
Edouard@276
   535
    if (vresult == NULL) {
Edouard@276
   536
        result = PEP_OUT_OF_MEMORY;
Edouard@276
   537
        goto unlock_netpgp;
Edouard@276
   538
    }
Edouard@185
   539
    memset(vresult, 0x0, sizeof(pgp_validation_t));
Edouard@185
   540
Edouard@185
   541
    signedmem = pgp_memory_new();
Edouard@185
   542
    if (signedmem == NULL) {
Edouard@252
   543
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   544
        goto unlock_netpgp;
Edouard@185
   545
    }
Edouard@185
   546
    pgp_memory_add(signedmem, (const uint8_t*)text, size);
Edouard@185
   547
Edouard@185
   548
    sig = pgp_memory_new();
Edouard@185
   549
    if (sig == NULL) {
Edouard@185
   550
        pgp_memory_free(signedmem);
Edouard@252
   551
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   552
        goto unlock_netpgp;
Edouard@185
   553
    }
Edouard@185
   554
    pgp_memory_add(sig, (const uint8_t*)signature, sig_size);
Edouard@185
   555
Edouard@252
   556
    pgp_validate_mem_detached(netpgp.io, vresult, sig,
Edouard@185
   557
                NULL,/* output */
Edouard@207
   558
                _armoured(signature, sig_size, ARMOR_SIG_HEAD),
Edouard@252
   559
                netpgp.pubring,
Edouard@185
   560
                signedmem);
Edouard@185
   561
Edouard@252
   562
    result = _validation_results(&netpgp, vresult, &_keylist);
Edouard@185
   563
    if (result != PEP_STATUS_OK) {
Edouard@185
   564
        goto free_pgp;
Edouard@185
   565
    }else{
Edouard@185
   566
        result = PEP_VERIFIED;
Edouard@185
   567
    }
Edouard@185
   568
Edouard@185
   569
    if (result == PEP_VERIFIED) {
Edouard@185
   570
        /* TODO : check trust level */
Edouard@185
   571
        result = PEP_VERIFIED_AND_TRUSTED;
Edouard@185
   572
    }
Edouard@185
   573
Edouard@185
   574
    if (result == PEP_VERIFIED || result == PEP_VERIFIED_AND_TRUSTED) {
Edouard@185
   575
        *keylist = _keylist;
Edouard@185
   576
Edouard@185
   577
        /* _keylist ownership transfer, don't free */
Edouard@185
   578
        goto free_pgp;
Edouard@185
   579
    }
Edouard@185
   580
Edouard@185
   581
    free_stringlist(_keylist);
Edouard@185
   582
Edouard@185
   583
free_pgp:
Edouard@187
   584
    // free done by pgp_validate_mem_detached
Edouard@187
   585
    // pgp_memory_free(sig);
Edouard@187
   586
    // pgp_memory_free(signedmem);
Edouard@185
   587
    pgp_validate_result_free(vresult);
Edouard@185
   588
Edouard@252
   589
unlock_netpgp:
Edouard@252
   590
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   591
Edouard@185
   592
    return result;
Edouard@174
   593
}
Edouard@174
   594
edouard@1693
   595
static PEP_STATUS _encrypt_and_sign(
Edouard@174
   596
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
edouard@1693
   597
    size_t psize, char **ctext, size_t *csize, bool do_sign
Edouard@174
   598
    )
Edouard@174
   599
{
Edouard@412
   600
    pgp_key_t *signer = NULL;
Edouard@412
   601
    pgp_seckey_t *seckey = NULL;
edouard@1693
   602
    pgp_memory_t *signedmem = NULL;
Edouard@209
   603
    pgp_memory_t *cmem;
Edouard@207
   604
    const char *hashalg;
Edouard@209
   605
    pgp_keyring_t *rcpts;
Edouard@207
   606
Edouard@174
   607
    PEP_STATUS result;
Edouard@174
   608
    const stringlist_t *_keylist;
Edouard@174
   609
Edouard@174
   610
    assert(session);
Edouard@174
   611
    assert(keylist);
Edouard@174
   612
    assert(ptext);
Edouard@174
   613
    assert(psize);
Edouard@174
   614
    assert(ctext);
Edouard@174
   615
    assert(csize);
Edouard@174
   616
krista@1435
   617
    if(!session || !ptext || !psize || !ctext || !csize || !keylist)
Edouard@661
   618
        return PEP_ILLEGAL_VALUE;
Edouard@207
   619
Edouard@263
   620
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   621
        return PEP_UNKNOWN_ERROR;
Edouard@252
   622
    }
Edouard@208
   623
Edouard@174
   624
    *ctext = NULL;
Edouard@174
   625
    *csize = 0;
Edouard@174
   626
Edouard@315
   627
    if ((rcpts = calloc(1, sizeof(*rcpts))) == NULL) {
Edouard@315
   628
        result = PEP_OUT_OF_MEMORY;
Edouard@391
   629
        goto unlock_netpgp;
Edouard@315
   630
    }
Edouard@315
   631
    for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
Edouard@315
   632
        assert(_keylist->value);
krista@1435
   633
Edouard@315
   634
        const pgp_key_t *key;
Edouard@391
   635
        uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@391
   636
        size_t fprlen;
Edouard@315
   637
        unsigned from = 0;
Edouard@315
   638
Edouard@391
   639
        if (str_to_fpr(_keylist->value, fpr, &fprlen)) {
Edouard@391
   640
            if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring,
Edouard@391
   641
                                                    fpr, fprlen, &from, NULL,
Edouard@391
   642
                                                    /* reject revoked, accept expired */
Edouard@391
   643
                                                    1,0)) == NULL) {
Edouard@391
   644
                result = PEP_KEY_NOT_FOUND;
Edouard@391
   645
                goto free_rcpts;
Edouard@391
   646
            }
Edouard@391
   647
        }else{
Edouard@315
   648
            result = PEP_ILLEGAL_VALUE;
Edouard@315
   649
            goto free_rcpts;
Edouard@315
   650
        }
Edouard@315
   651
Edouard@315
   652
        /* Signer is the first key in the list */
Edouard@315
   653
        if(signer == NULL){
Edouard@315
   654
            from = 0;
Edouard@391
   655
            signer = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.secring,
Edouard@391
   656
                                                  fpr, fprlen,
Edouard@391
   657
                                                  &from,
Edouard@391
   658
                                                  NULL,
Edouard@391
   659
                                                  0,0); /* accept any */
Edouard@315
   660
            if(signer == NULL){
Edouard@315
   661
                result = PEP_KEY_NOT_FOUND;
Edouard@315
   662
                goto free_rcpts;
Edouard@315
   663
            }
Edouard@315
   664
        }
Edouard@315
   665
Edouard@315
   666
        // add key to recipients/signers
Edouard@315
   667
        pgp_keyring_add(rcpts, key);
Edouard@315
   668
        if(rcpts->keys == NULL){
Edouard@315
   669
            result = PEP_OUT_OF_MEMORY;
Edouard@391
   670
            goto free_rcpts;
Edouard@315
   671
        }
Edouard@207
   672
    }
Edouard@209
   673
Edouard@315
   674
    /* Empty keylist ?*/
Edouard@315
   675
    if(rcpts->keyc == 0){
Edouard@315
   676
        result = PEP_ILLEGAL_VALUE;
Edouard@391
   677
        goto free_rcpts;
Edouard@315
   678
    }
Edouard@315
   679
Edouard@315
   680
    seckey = pgp_key_get_certkey(signer);
Edouard@315
   681
Edouard@315
   682
    /* No signig key. Revoked ? */
Edouard@315
   683
    if(seckey == NULL){
Edouard@315
   684
        result = PEP_GET_KEY_FAILED;
Edouard@391
   685
        goto free_rcpts;
Edouard@315
   686
    }
Edouard@286
   687
Edouard@252
   688
    hashalg = netpgp_getvar(&netpgp, "hash");
Edouard@207
   689
edouard@1693
   690
    const char *stext;
edouard@1693
   691
    size_t ssize;
edouard@1693
   692
    unsigned encrypt_raw_packet;
edouard@1693
   693
   
edouard@1693
   694
    if (do_sign) {  
edouard@1693
   695
        // Sign data
edouard@1693
   696
        signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
edouard@1693
   697
                    time(NULL), /* birthtime */
edouard@1693
   698
                    0 /* duration */,
edouard@1693
   699
                    hashalg,
edouard@1693
   700
                    0 /* armored */,
edouard@1693
   701
                    0 /* cleartext */);
Edouard@207
   702
edouard@1693
   703
        if (!signedmem) {
edouard@1693
   704
            result = PEP_UNENCRYPTED;
edouard@1693
   705
            goto free_rcpts;
edouard@1693
   706
        }
edouard@1693
   707
        stext = (char*) pgp_mem_data(signedmem);
edouard@1693
   708
        ssize = pgp_mem_len(signedmem);
edouard@1693
   709
        encrypt_raw_packet = 1 /* takes raw OpenPGP message */;
edouard@1693
   710
    } else {
edouard@1693
   711
        stext = ptext;
edouard@1693
   712
        ssize = psize;
edouard@1693
   713
        encrypt_raw_packet = 0 /* not a raw OpenPGP message */;
Edouard@207
   714
    }
Edouard@207
   715
edouard@1693
   716
    // Encrypt (maybe) signed data
Edouard@174
   717
edouard@1693
   718
    cmem = pgp_encrypt_buf(netpgp.io, stext,
edouard@1693
   719
            ssize, rcpts, 1 /* armored */,
krista@1435
   720
            netpgp_getvar(&netpgp, "cipher"),
edouard@1693
   721
            encrypt_raw_packet);
Edouard@174
   722
Edouard@209
   723
    if (cmem == NULL) {
Edouard@209
   724
        result = PEP_OUT_OF_MEMORY;
Edouard@209
   725
        goto free_signedmem;
Edouard@209
   726
    }else{
Edouard@209
   727
Edouard@209
   728
        char *_buffer = NULL;
Edouard@209
   729
        size_t length = pgp_mem_len(cmem);
Edouard@209
   730
Edouard@209
   731
        // Allocate transferable buffer
Edouard@209
   732
        _buffer = malloc(length + 1);
Edouard@209
   733
        assert(_buffer);
Edouard@209
   734
        if (_buffer == NULL) {
Edouard@209
   735
            result = PEP_OUT_OF_MEMORY;
Edouard@209
   736
            goto free_cmem;
Edouard@209
   737
        }
Edouard@209
   738
Edouard@209
   739
        memcpy(_buffer, pgp_mem_data(cmem), length);
Edouard@209
   740
Edouard@209
   741
        *ctext = _buffer;
Edouard@209
   742
        *csize = length;
Edouard@209
   743
        (*ctext)[*csize] = 0; // safeguard for naive users
Edouard@209
   744
        result = PEP_STATUS_OK;
Edouard@174
   745
    }
Edouard@174
   746
Edouard@209
   747
free_cmem :
Edouard@209
   748
    pgp_memory_free(cmem);
Edouard@315
   749
free_signedmem :
edouard@1693
   750
    if (do_sign) {
edouard@1693
   751
        pgp_memory_free(signedmem);
edouard@1693
   752
    }
Edouard@209
   753
free_rcpts :
Edouard@209
   754
    pgp_keyring_free(rcpts);
Edouard@252
   755
unlock_netpgp:
Edouard@252
   756
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@175
   757
Edouard@174
   758
    return result;
Edouard@174
   759
}
Edouard@174
   760
edouard@1693
   761
PEP_STATUS pgp_encrypt_and_sign(
edouard@1693
   762
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
edouard@1693
   763
    size_t psize, char **ctext, size_t *csize
edouard@1693
   764
    )
edouard@1693
   765
{
edouard@1693
   766
    PEP_STATUS result;
edouard@1693
   767
    result = _encrypt_and_sign(session, keylist, ptext, psize, ctext, csize,
edouard@1693
   768
                               true);
edouard@1693
   769
    return result;
edouard@1693
   770
}
edouard@1693
   771
krista@1674
   772
PEP_STATUS pgp_encrypt_only(
krista@1674
   773
        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1674
   774
        size_t psize, char **ctext, size_t *csize
krista@1674
   775
    )
krista@1674
   776
{
edouard@1693
   777
    PEP_STATUS result;
edouard@1693
   778
    result = _encrypt_and_sign(session, keylist, ptext, psize, ctext, csize,
edouard@1693
   779
                               false);
edouard@1693
   780
    return result;
krista@1674
   781
}
krista@1674
   782
krista@1674
   783
Edouard@174
   784
PEP_STATUS pgp_generate_keypair(
Edouard@174
   785
    PEP_SESSION session, pEp_identity *identity
Edouard@174
   786
    )
Edouard@174
   787
{
Edouard@313
   788
    pgp_key_t	newseckey;
Edouard@316
   789
    pgp_key_t	*newpubkey;
Edouard@225
   790
Edouard@225
   791
    PEP_STATUS result;
Edouard@228
   792
    char newid[1024];
Edouard@225
   793
    const char *hashalg;
Edouard@225
   794
    const char *cipher;
Edouard@174
   795
Edouard@174
   796
    assert(session);
Edouard@174
   797
    assert(identity);
Edouard@174
   798
    assert(identity->address);
Edouard@174
   799
    assert(identity->fpr == NULL);
Edouard@174
   800
    assert(identity->username);
Edouard@174
   801
krista@1435
   802
    if(!session || !identity ||
Edouard@225
   803
       !identity->address || identity->fpr || !identity->username)
Edouard@661
   804
        return PEP_ILLEGAL_VALUE;
Edouard@174
   805
Edouard@263
   806
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   807
        return PEP_UNKNOWN_ERROR;
Edouard@252
   808
    }
Edouard@225
   809
Edouard@225
   810
    if(snprintf(newid, sizeof(newid),
Edouard@225
   811
        "%s <%s>", identity->username, identity->address) >= sizeof(newid)){
Edouard@252
   812
        result =  PEP_BUFFER_TOO_SMALL;
Edouard@252
   813
        goto unlock_netpgp;
Edouard@174
   814
    }
krista@1435
   815
Edouard@252
   816
    hashalg = netpgp_getvar(&netpgp, "hash");
Edouard@252
   817
    cipher = netpgp_getvar(&netpgp, "cipher");
Edouard@174
   818
Edouard@313
   819
    bzero(&newseckey, sizeof(newseckey));
Edouard@174
   820
Edouard@225
   821
    // Generate the key
Edouard@313
   822
    if (!pgp_rsa_generate_keypair(&newseckey, 4096, 65537UL, hashalg, cipher,
Edouard@327
   823
                                  (const uint8_t *) "", (const size_t) 0))
Edouard@327
   824
    {
Edouard@228
   825
        result = PEP_CANNOT_CREATE_KEY;
Edouard@313
   826
        goto free_seckey;
Edouard@228
   827
    }
Edouard@174
   828
Edouard@316
   829
    /* make a public key out of generated secret key */
Edouard@327
   830
    if((newpubkey = pgp_ensure_pubkey(
Edouard@316
   831
            netpgp.pubring,
Edouard@316
   832
            &newseckey.key.seckey.pubkey,
Edouard@327
   833
            newseckey.pubkeyid))==NULL)
Edouard@327
   834
    {
Edouard@316
   835
        result = PEP_OUT_OF_MEMORY;
Edouard@316
   836
        goto free_seckey;
Edouard@316
   837
    }
Edouard@316
   838
Edouard@328
   839
    // "Expire-Date: 1y\n";
krista@1435
   840
    if (!pgp_add_selfsigned_userid(&newseckey, newpubkey,
Edouard@329
   841
                                  (uint8_t *)newid, 365*24*3600))
Edouard@327
   842
    {
Edouard@327
   843
        result = PEP_CANNOT_CREATE_KEY;
Edouard@327
   844
        goto delete_pubkey;
Edouard@327
   845
    }
Edouard@174
   846
Edouard@327
   847
    if (newpubkey == NULL)
Edouard@327
   848
    {
Edouard@327
   849
        result = PEP_OUT_OF_MEMORY;
Edouard@327
   850
        goto delete_pubkey;
Edouard@327
   851
    }
Edouard@225
   852
Edouard@313
   853
    // Append key to netpgp's rings (key ownership transfered)
Edouard@313
   854
    if (!pgp_keyring_add(netpgp.secring, &newseckey)){
Edouard@313
   855
        result = PEP_OUT_OF_MEMORY;
Edouard@316
   856
        goto delete_pubkey;
krista@1435
   857
    }
Edouard@225
   858
krista@1435
   859
    // save rings
Edouard@313
   860
    if (netpgp_save_pubring(&netpgp) && netpgp_save_secring(&netpgp))
Edouard@313
   861
    {
Edouard@316
   862
        char *fprstr = NULL;
Edouard@316
   863
        fpr_to_str(&fprstr,
Edouard@316
   864
                   newseckey.pubkeyfpr.fingerprint,
Edouard@316
   865
                   newseckey.pubkeyfpr.length);
Edouard@316
   866
Edouard@316
   867
        if (fprstr == NULL) {
Edouard@316
   868
            result = PEP_OUT_OF_MEMORY;
Edouard@316
   869
            goto pop_secring;
krista@1435
   870
        }
Edouard@316
   871
Edouard@316
   872
        /* keys saved, pass fingerprint back */
Edouard@313
   873
        identity->fpr = fprstr;
Edouard@313
   874
        result = PEP_STATUS_OK;
Edouard@316
   875
Edouard@313
   876
        /* free nothing, everything transfered */
Edouard@313
   877
        goto unlock_netpgp;
Edouard@313
   878
    } else {
Edouard@313
   879
        /* XXX in case only pubring save succeed
Edouard@313
   880
         * pubring file is left as-is, but backup restore
Edouard@313
   881
         * could be attempted if such corner case matters */
Edouard@313
   882
        result = PEP_UNKNOWN_ERROR;
Edouard@313
   883
    }
Edouard@313
   884
Edouard@313
   885
pop_secring:
Edouard@313
   886
    ((pgp_keyring_t *)netpgp.secring)->keyc--;
Edouard@316
   887
delete_pubkey:
Edouard@316
   888
    pgp_deletekeybyfpr(netpgp.io,
krista@1435
   889
                    (pgp_keyring_t *)netpgp.pubring,
Edouard@316
   890
                    newseckey.pubkeyfpr.fingerprint,
Edouard@316
   891
                    newseckey.pubkeyfpr.length);
Edouard@313
   892
free_seckey:
Edouard@313
   893
    pgp_key_free(&newseckey);
Edouard@252
   894
unlock_netpgp:
Edouard@252
   895
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@228
   896
Edouard@225
   897
    return result;
Edouard@174
   898
}
Edouard@174
   899
Edouard@227
   900
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
Edouard@174
   901
{
Edouard@227
   902
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@227
   903
    size_t length;
Edouard@227
   904
Edouard@227
   905
    PEP_STATUS result;
Edouard@227
   906
Edouard@174
   907
    assert(session);
Edouard@386
   908
    assert(fprstr);
Edouard@174
   909
Edouard@386
   910
    if (!session || !fprstr)
Edouard@661
   911
        return PEP_ILLEGAL_VALUE;
Edouard@174
   912
Edouard@263
   913
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   914
        return PEP_UNKNOWN_ERROR;
Edouard@252
   915
    }
krista@1435
   916
Edouard@227
   917
    if (str_to_fpr(fprstr, fpr, &length)) {
Edouard@252
   918
        unsigned insec = pgp_deletekeybyfpr(netpgp.io,
krista@1435
   919
                                (pgp_keyring_t *)netpgp.secring,
Edouard@244
   920
                                (const uint8_t *)fpr, length);
Edouard@252
   921
        unsigned inpub = pgp_deletekeybyfpr(netpgp.io,
krista@1435
   922
                                (pgp_keyring_t *)netpgp.pubring,
Edouard@244
   923
                                (const uint8_t *)fpr, length);
Edouard@244
   924
        if(!insec && !inpub){
Edouard@244
   925
            result = PEP_KEY_NOT_FOUND;
Edouard@252
   926
            goto unlock_netpgp;
Edouard@244
   927
        } else {
Edouard@244
   928
            result = PEP_STATUS_OK;
Edouard@227
   929
        }
Edouard@227
   930
    }else{
Edouard@252
   931
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   932
        goto unlock_netpgp;
Edouard@227
   933
    }
Edouard@174
   934
krista@1435
   935
    // save rings
krista@1435
   936
    if (netpgp_save_pubring(&netpgp) &&
Edouard@252
   937
        netpgp_save_secring(&netpgp))
Edouard@227
   938
    {
Edouard@227
   939
        result = PEP_STATUS_OK;
Edouard@227
   940
    }else{
Edouard@227
   941
        result = PEP_UNKNOWN_ERROR;
Edouard@227
   942
    }
Edouard@227
   943
Edouard@252
   944
unlock_netpgp:
Edouard@252
   945
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   946
Edouard@227
   947
    return result;
Edouard@174
   948
}
Edouard@174
   949
Edouard@389
   950
#define ARMOR_KEY_HEAD    "^-----BEGIN PGP (PUBLIC|PRIVATE) KEY BLOCK-----"_ENDL
Edouard@279
   951
PEP_STATUS pgp_import_keydata(
Edouard@279
   952
        PEP_SESSION session,
krista@1435
   953
        const char *key_data,
edouard@1677
   954
        size_t size,
edouard@1677
   955
        identity_list **private_idents
Edouard@279
   956
    )
Edouard@174
   957
{
Edouard@228
   958
    pgp_memory_t *mem;
Edouard@228
   959
Edouard@271
   960
    PEP_STATUS result = PEP_STATUS_OK;
Edouard@228
   961
Edouard@174
   962
    assert(session);
Edouard@174
   963
    assert(key_data);
Edouard@174
   964
edouard@1677
   965
    // reporting imported private keys not supported
edouard@1677
   966
    // stub code to be reomoved
edouard@1677
   967
    if(private_idents)
edouard@1677
   968
        *private_idents = NULL;
edouard@1677
   969
krista@1435
   970
    if(!session || !key_data)
Edouard@661
   971
        return PEP_ILLEGAL_VALUE;
Edouard@228
   972
Edouard@263
   973
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   974
        return PEP_UNKNOWN_ERROR;
Edouard@252
   975
    }
Edouard@228
   976
Edouard@228
   977
    mem = pgp_memory_new();
Edouard@228
   978
    if (mem == NULL) {
Edouard@252
   979
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   980
        goto unlock_netpgp;
Edouard@228
   981
    }
Edouard@228
   982
    pgp_memory_add(mem, (const uint8_t*)key_data, size);
Edouard@228
   983
krista@1435
   984
    if (pgp_keyring_read_from_mem(netpgp.io, netpgp.pubring, netpgp.secring,
Edouard@228
   985
                                  _armoured(key_data, size, ARMOR_KEY_HEAD),
Edouard@228
   986
                                  mem) == 0){
Edouard@228
   987
        result = PEP_ILLEGAL_VALUE;
krista@1435
   988
    }
Edouard@313
   989
Edouard@228
   990
    pgp_memory_free(mem);
Edouard@228
   991
krista@1435
   992
    // save rings
krista@1435
   993
    if (netpgp_save_pubring(&netpgp) &&
Edouard@325
   994
        netpgp_save_secring(&netpgp))
Edouard@325
   995
    {
Edouard@325
   996
        result = PEP_STATUS_OK;
Edouard@325
   997
    }else{
Edouard@325
   998
        result = PEP_UNKNOWN_ERROR;
Edouard@325
   999
    }
Edouard@325
  1000
Edouard@252
  1001
unlock_netpgp:
Edouard@252
  1002
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
  1003
Edouard@228
  1004
    return result;
Edouard@174
  1005
}
Edouard@174
  1006
Edouard@318
  1007
static PEP_STATUS _export_keydata(
Edouard@318
  1008
    pgp_key_t *key,
Edouard@318
  1009
    char **buffer,
Edouard@318
  1010
    size_t *buflen
Edouard@318
  1011
    )
Edouard@318
  1012
{
Edouard@318
  1013
    PEP_STATUS result;
Edouard@318
  1014
	pgp_output_t *output;
Edouard@318
  1015
    pgp_memory_t *mem;
Edouard@318
  1016
	pgp_setup_memory_write(&output, &mem, 128);
Edouard@318
  1017
Edouard@318
  1018
    if (mem == NULL || output == NULL) {
Edouard@661
  1019
        return PEP_ILLEGAL_VALUE;
Edouard@318
  1020
    }
Edouard@318
  1021
Edouard@318
  1022
    if (!pgp_write_xfer_key(output, key, 1)) {
Edouard@318
  1023
        result = PEP_UNKNOWN_ERROR;
Edouard@318
  1024
        goto free_mem;
Edouard@318
  1025
    }
Edouard@318
  1026
Edouard@318
  1027
    *buffer = NULL;
Edouard@318
  1028
    *buflen = pgp_mem_len(mem);
Edouard@318
  1029
Edouard@318
  1030
    // Allocate transferable buffer
Edouard@318
  1031
    *buffer = malloc(*buflen + 1);
Edouard@318
  1032
    assert(*buffer);
Edouard@318
  1033
    if (*buffer == NULL) {
Edouard@318
  1034
        result = PEP_OUT_OF_MEMORY;
Edouard@318
  1035
        goto free_mem;
Edouard@318
  1036
    }
Edouard@318
  1037
Edouard@318
  1038
    memcpy(*buffer, pgp_mem_data(mem), *buflen);
Edouard@318
  1039
    (*buffer)[*buflen] = 0; // safeguard for naive users
Edouard@318
  1040
Edouard@318
  1041
    return PEP_STATUS_OK;
Edouard@318
  1042
Edouard@318
  1043
free_mem :
Edouard@318
  1044
	pgp_teardown_memory_write(output, mem);
Edouard@318
  1045
Edouard@318
  1046
    return result;
Edouard@318
  1047
}
Edouard@318
  1048
Edouard@179
  1049
PEP_STATUS pgp_export_keydata(
edouard@1677
  1050
    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size,
edouard@1677
  1051
    bool secret
Edouard@174
  1052
    )
Edouard@174
  1053
{
Edouard@228
  1054
    pgp_key_t *key;
Edouard@228
  1055
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@228
  1056
    size_t fprlen;
Edouard@228
  1057
Edouard@228
  1058
    PEP_STATUS result;
Edouard@174
  1059
    char *buffer;
Edouard@228
  1060
    size_t buflen;
edouard@1776
  1061
    const pgp_keyring_t *srcring;
Edouard@174
  1062
Edouard@174
  1063
    assert(session);
Edouard@243
  1064
    assert(fprstr);
Edouard@174
  1065
    assert(key_data);
Edouard@174
  1066
    assert(size);
Edouard@174
  1067
edouard@1677
  1068
    if (secret)
edouard@1776
  1069
        srcring = netpgp.secring;
edouard@1776
  1070
    else
edouard@1776
  1071
        srcring = netpgp.pubring;
edouard@1776
  1072
    
Edouard@243
  1073
    if (!session || !fprstr || !key_data || !size)
Edouard@661
  1074
        return PEP_ILLEGAL_VALUE;
Edouard@174
  1075
Edouard@263
  1076
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
  1077
        return PEP_UNKNOWN_ERROR;
Edouard@252
  1078
    }
Edouard@252
  1079
Edouard@228
  1080
    if (str_to_fpr(fprstr, fpr, &fprlen)) {
Edouard@391
  1081
        unsigned from = 0;
Edouard@391
  1082
edouard@1776
  1083
        if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, srcring,
Edouard@391
  1084
                                                fpr, fprlen, &from,
Edouard@391
  1085
                                                NULL,0,0)) == NULL) {
Edouard@252
  1086
            result = PEP_KEY_NOT_FOUND;
Edouard@252
  1087
            goto unlock_netpgp;
Edouard@228
  1088
        }
Edouard@228
  1089
    }else{
Edouard@252
  1090
        result = PEP_OUT_OF_MEMORY;
Edouard@252
  1091
        goto unlock_netpgp;
Edouard@228
  1092
    }
krista@1435
  1093
Edouard@318
  1094
    result = _export_keydata(key, &buffer, &buflen);
krista@1435
  1095
Edouard@318
  1096
    if(result == PEP_STATUS_OK)
Edouard@318
  1097
    {
Edouard@318
  1098
        *key_data = buffer;
Edouard@318
  1099
        *size = buflen;
Edouard@318
  1100
        result = PEP_STATUS_OK;
Edouard@174
  1101
    }
Edouard@174
  1102
Edouard@252
  1103
unlock_netpgp:
Edouard@252
  1104
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@228
  1105
Edouard@228
  1106
    return result;
Edouard@174
  1107
}
Edouard@174
  1108
Edouard@271
  1109
struct HKP_answer {
Edouard@271
  1110
  char *memory;
Edouard@271
  1111
  size_t size;
Edouard@271
  1112
};
krista@1435
  1113
Edouard@271
  1114
static size_t
Edouard@271
  1115
HKPAnswerWriter(void *contents, size_t size, size_t nmemb, void *userp)
Edouard@271
  1116
{
Edouard@271
  1117
  size_t realsize = size * nmemb;
Edouard@271
  1118
  struct HKP_answer *mem = (struct HKP_answer *)userp;
krista@1435
  1119
Edouard@271
  1120
  mem->memory = realloc(mem->memory, mem->size + realsize + 1);
Edouard@271
  1121
  if(mem->memory == NULL) {
Edouard@271
  1122
    mem->size = 0;
Edouard@271
  1123
    return 0;
Edouard@271
  1124
  }
krista@1435
  1125
Edouard@271
  1126
  memcpy(&(mem->memory[mem->size]), contents, realsize);
Edouard@271
  1127
  mem->size += realsize;
Edouard@271
  1128
  mem->memory[mem->size] = 0;
krista@1435
  1129
Edouard@271
  1130
  return realsize;
Edouard@271
  1131
}
Edouard@271
  1132
Edouard@323
  1133
#define HKP_SERVER "http://keys.gnupg.net:11371"
Edouard@323
  1134
// #define HKP_SERVER "http://127.0.0.1:11371"
Edouard@321
  1135
Edouard@174
  1136
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
Edouard@174
  1137
{
Edouard@321
  1138
    static const char *ks_cmd = HKP_SERVER
Edouard@321
  1139
                                "/pks/lookup?"
Edouard@271
  1140
                                "op=get&options=mr&exact=on&"
Edouard@271
  1141
                                "search=";
Edouard@271
  1142
    char *encoded_pattern;
Edouard@271
  1143
    char *request = NULL;
Edouard@271
  1144
    struct HKP_answer answer;
Edouard@271
  1145
    CURLcode curlres;
krista@1435
  1146
Edouard@271
  1147
    PEP_STATUS result;
Edouard@271
  1148
Edouard@271
  1149
    CURL *curl;
Edouard@271
  1150
Edouard@174
  1151
    assert(session);
Edouard@174
  1152
    assert(pattern);
Edouard@174
  1153
Edouard@271
  1154
    if (!session || !pattern )
Edouard@661
  1155
        return PEP_ILLEGAL_VALUE;
Edouard@271
  1156
Edouard@271
  1157
    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
Edouard@271
  1158
        return PEP_UNKNOWN_ERROR;
Edouard@271
  1159
    }
Edouard@271
  1160
Edouard@322
  1161
    result = curl_get_ctx(&curl);
Edouard@322
  1162
    if(result != PEP_STATUS_OK){
Edouard@322
  1163
        goto unlock_curl;
Edouard@322
  1164
    }
Edouard@252
  1165
Edouard@271
  1166
    encoded_pattern = curl_easy_escape(curl, (char*)pattern, 0);
Edouard@271
  1167
    if(!encoded_pattern){
Edouard@271
  1168
        result = PEP_OUT_OF_MEMORY;
Edouard@322
  1169
        goto release_curl_ctx;
Edouard@271
  1170
    }
Edouard@174
  1171
Edouard@271
  1172
    if((request = malloc(strlen(ks_cmd) + strlen(encoded_pattern) + 1))==NULL){
Edouard@271
  1173
        result = PEP_OUT_OF_MEMORY;
Edouard@271
  1174
        goto free_encoded_pattern;
Edouard@271
  1175
    }
Edouard@174
  1176
Edouard@271
  1177
    //(*stpcpy(stpcpy(request, ks_cmd), encoded_pattern)) = '\0';
Edouard@271
  1178
    stpcpy(stpcpy(request, ks_cmd), encoded_pattern);
Edouard@174
  1179
Edouard@271
  1180
    curl_easy_setopt(curl, CURLOPT_URL,request);
Edouard@271
  1181
Edouard@271
  1182
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HKPAnswerWriter);
Edouard@271
  1183
Edouard@271
  1184
    answer.memory = NULL;
Edouard@271
  1185
    answer.size = 0;
Edouard@271
  1186
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&answer);
Edouard@271
  1187
Edouard@271
  1188
    curlres = curl_easy_perform(curl);
Edouard@271
  1189
    if(curlres != CURLE_OK) {
Edouard@271
  1190
        result = PEP_GET_KEY_FAILED;
Edouard@271
  1191
        goto free_request;
Edouard@271
  1192
    }
Edouard@271
  1193
Edouard@271
  1194
    if(!answer.memory || !answer.size) {
Edouard@271
  1195
        result = PEP_OUT_OF_MEMORY;
Edouard@271
  1196
        goto free_request;
Edouard@271
  1197
    }
Edouard@271
  1198
krista@1435
  1199
    result = pgp_import_keydata(session,
krista@1435
  1200
                                answer.memory,
edouard@1677
  1201
                                answer.size,
edouard@1677
  1202
                                NULL);
Edouard@271
  1203
Edouard@271
  1204
    free(answer.memory);
Edouard@271
  1205
free_request:
Edouard@271
  1206
    free(request);
Edouard@271
  1207
free_encoded_pattern:
Edouard@271
  1208
    curl_free(encoded_pattern);
Edouard@322
  1209
release_curl_ctx:
Edouard@322
  1210
    curl_release_ctx(&curl);
Edouard@271
  1211
unlock_curl:
Edouard@271
  1212
    pthread_mutex_unlock(&session->ctx.curl_mutex);
Edouard@271
  1213
Edouard@271
  1214
    return result;
Edouard@174
  1215
}
Edouard@174
  1216
Edouard@277
  1217
typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
Edouard@277
  1218
edouard@1705
  1219
static PEP_STATUS find_keys_do(pgp_keyring_t* keyring,
Edouard@277
  1220
        const char *pattern, find_key_cb_t cb, void* cb_arg)
Edouard@254
  1221
{
Edouard@277
  1222
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@277
  1223
    size_t length;
Edouard@277
  1224
    pgp_key_t *key;
Edouard@277
  1225
Edouard@277
  1226
    PEP_STATUS result;
Edouard@277
  1227
Edouard@277
  1228
    // Try find a fingerprint in pattern
Edouard@277
  1229
    if (str_to_fpr(pattern, fpr, &length)) {
Edouard@391
  1230
        unsigned from = 0;
Edouard@391
  1231
Edouard@277
  1232
Edouard@277
  1233
        // Only one fingerprint can match
Edouard@277
  1234
        if ((key = (pgp_key_t *)pgp_getkeybyfpr(
Edouard@277
  1235
                        netpgp.io,
edouard@1705
  1236
                        keyring,
Edouard@277
  1237
                        (const uint8_t *)fpr, length,
Edouard@391
  1238
                        &from,
Edouard@391
  1239
                        NULL, 0, 0)) == NULL) {
Edouard@277
  1240
Edouard@277
  1241
            return PEP_KEY_NOT_FOUND;
Edouard@277
  1242
        }
Edouard@277
  1243
Edouard@277
  1244
        result = cb(cb_arg, key);
Edouard@277
  1245
Edouard@277
  1246
    } else {
Edouard@277
  1247
        // Search by name for pattern. Can match many.
Edouard@277
  1248
        unsigned from = 0;
Edouard@277
  1249
        result = PEP_KEY_NOT_FOUND;
Edouard@277
  1250
        while((key = (pgp_key_t *)pgp_getnextkeybyname(
Edouard@277
  1251
                        netpgp.io,
edouard@1705
  1252
                        keyring,
Edouard@277
  1253
			            (const char *)pattern,
Edouard@277
  1254
                        &from)) != NULL) {
Edouard@277
  1255
Edouard@277
  1256
            result = cb(cb_arg, key);
Edouard@277
  1257
            if (result != PEP_STATUS_OK)
Edouard@277
  1258
                break;
Edouard@277
  1259
Edouard@277
  1260
            from++;
Edouard@277
  1261
        }
Edouard@277
  1262
    }
Edouard@277
  1263
Edouard@277
  1264
    return result;
Edouard@277
  1265
}
Edouard@277
  1266
Edouard@277
  1267
static PEP_STATUS add_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
Edouard@277
  1268
{
Edouard@277
  1269
    stringlist_t **keylist = arg;
Edouard@254
  1270
    char *newfprstr = NULL;
Edouard@254
  1271
Edouard@254
  1272
    fpr_to_str(&newfprstr,
Edouard@313
  1273
               key->pubkeyfpr.fingerprint,
Edouard@313
  1274
               key->pubkeyfpr.length);
Edouard@254
  1275
Edouard@254
  1276
    if (newfprstr == NULL) {
Edouard@254
  1277
        return PEP_OUT_OF_MEMORY;
krista@1435
  1278
    } else {
Edouard@254
  1279
krista@1033
  1280
        stringlist_add(*keylist, newfprstr);
roker@868
  1281
        free(newfprstr);
Edouard@254
  1282
        if (*keylist == NULL) {
Edouard@254
  1283
            return PEP_OUT_OF_MEMORY;
Edouard@254
  1284
        }
Edouard@254
  1285
    }
Edouard@254
  1286
    return PEP_STATUS_OK;
Edouard@254
  1287
}
Edouard@254
  1288
krista@1362
  1289
static PEP_STATUS add_secret_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
krista@1362
  1290
{
krista@1362
  1291
    if (pgp_is_key_secret(key)) {
krista@1362
  1292
        stringlist_t **keylist = arg;
krista@1362
  1293
        char *newfprstr = NULL;
krista@1435
  1294
krista@1362
  1295
        fpr_to_str(&newfprstr,
krista@1362
  1296
                key->pubkeyfpr.fingerprint,
krista@1362
  1297
                key->pubkeyfpr.length);
krista@1435
  1298
krista@1362
  1299
        if (newfprstr == NULL) {
krista@1362
  1300
            return PEP_OUT_OF_MEMORY;
krista@1435
  1301
        } else {
krista@1362
  1302
            stringlist_add(*keylist, newfprstr);
krista@1362
  1303
            free(newfprstr);
krista@1362
  1304
            if (*keylist == NULL) {
krista@1362
  1305
                return PEP_OUT_OF_MEMORY;
krista@1362
  1306
            }
krista@1362
  1307
        }
krista@1362
  1308
    }
krista@1362
  1309
    return PEP_STATUS_OK;
krista@1362
  1310
}
krista@1362
  1311
krista@1031
  1312
static PEP_STATUS add_keyinfo_to_stringpair_list(void* arg, pgp_key_t *key) {
krista@1031
  1313
    stringpair_list_t** keyinfo_list = (stringpair_list_t**)arg;
krista@1033
  1314
    stringpair_t* pair = NULL;
krista@1031
  1315
    char* id_fpr = NULL;
krista@1031
  1316
    char* primary_userid = (char*)pgp_key_get_primary_userid(key);
krista@1435
  1317
hernani@1390
  1318
// Unused:
hernani@1389
  1319
//    bool key_revoked = false;
krista@1435
  1320
krista@1040
  1321
//    PEP_STATUS key_status = pgp_key_revoked(session, id_fpr, &key_revoked);
krista@1435
  1322
krista@1040
  1323
//    if (key_revoked || key_status == PEP_GET_KEY_FAILED)
krista@1040
  1324
//        return PEP_STATUS_OK; // we just move on
krista@1435
  1325
krista@1031
  1326
    fpr_to_str(&id_fpr, key->pubkeyfpr.fingerprint,
krista@1031
  1327
                key->pubkeyfpr.length);
krista@1031
  1328
krista@1031
  1329
    pair = new_stringpair(id_fpr, primary_userid);
krista@1435
  1330
krista@1031
  1331
    if (pair == NULL)
krista@1031
  1332
        return PEP_OUT_OF_MEMORY;
krista@1435
  1333
krista@1031
  1334
    *keyinfo_list = stringpair_list_add(*keyinfo_list, pair);
krista@1031
  1335
    free(id_fpr);
krista@1031
  1336
    if (*keyinfo_list == NULL)
krista@1031
  1337
        return PEP_OUT_OF_MEMORY;
krista@1031
  1338
    return PEP_STATUS_OK;
krista@1031
  1339
}
krista@1031
  1340
Edouard@174
  1341
PEP_STATUS pgp_find_keys(
Edouard@174
  1342
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
Edouard@174
  1343
    )
Edouard@174
  1344
{
Edouard@254
  1345
    stringlist_t *_keylist, *_k;
Edouard@254
  1346
Edouard@254
  1347
    PEP_STATUS result;
Edouard@174
  1348
Edouard@174
  1349
    assert(session);
Edouard@174
  1350
    assert(pattern);
Edouard@174
  1351
    assert(keylist);
Edouard@174
  1352
Edouard@254
  1353
    if (!session || !pattern || !keylist )
Edouard@661
  1354
    {
Edouard@661
  1355
        return PEP_ILLEGAL_VALUE;
Edouard@661
  1356
    }
Edouard@254
  1357
Edouard@661
  1358
    if (pthread_mutex_lock(&netpgp_mutex))
Edouard@661
  1359
    {
Edouard@254
  1360
        return PEP_UNKNOWN_ERROR;
Edouard@254
  1361
    }
Edouard@254
  1362
Edouard@174
  1363
    *keylist = NULL;
Edouard@254
  1364
    _keylist = new_stringlist(NULL);
Edouard@384
  1365
    if (_keylist == NULL) {
Edouard@254
  1366
        result = PEP_OUT_OF_MEMORY;
Edouard@254
  1367
        goto unlock_netpgp;
Edouard@254
  1368
    }
Edouard@254
  1369
    _k = _keylist;
Edouard@174
  1370
edouard@1705
  1371
    result = find_keys_do((pgp_keyring_t *)netpgp.pubring,
edouard@1705
  1372
                          pattern, &add_key_fpr_to_stringlist, &_k);
Edouard@254
  1373
Edouard@254
  1374
    if (result == PEP_STATUS_OK) {
Edouard@254
  1375
        *keylist = _keylist;
Edouard@254
  1376
        // Transfer ownership, no free
Edouard@254
  1377
        goto unlock_netpgp;
Edouard@254
  1378
    }
Edouard@254
  1379
Edouard@254
  1380
    free_stringlist(_keylist);
Edouard@254
  1381
Edouard@254
  1382
unlock_netpgp:
Edouard@254
  1383
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@254
  1384
Edouard@254
  1385
    return result;
Edouard@174
  1386
}
Edouard@174
  1387
Edouard@321
  1388
#define HKP_REQ_PREFIX "keytext="
Edouard@321
  1389
#define HKP_REQ_PREFIX_LEN 8
Edouard@321
  1390
Edouard@277
  1391
static PEP_STATUS send_key_cb(void *arg, pgp_key_t *key)
Edouard@277
  1392
{
Edouard@318
  1393
    char *buffer = NULL;
Edouard@318
  1394
    size_t buflen = 0;
Edouard@318
  1395
    PEP_STATUS result;
Edouard@318
  1396
    stringlist_t *encoded_keys;
Edouard@318
  1397
    encoded_keys = (stringlist_t*)arg;
Edouard@277
  1398
Edouard@318
  1399
    result = _export_keydata(key, &buffer, &buflen);
krista@1435
  1400
Edouard@318
  1401
    if(result == PEP_STATUS_OK){
roker@868
  1402
        char *encoded_key = curl_escape(buffer, (int)buflen);
Edouard@318
  1403
        if(!encoded_key){
Edouard@321
  1404
            result = PEP_OUT_OF_MEMORY;
Edouard@321
  1405
            goto free_buffer;
Edouard@318
  1406
        }
roker@868
  1407
        size_t encoded_key_len = strlen(encoded_key);
Edouard@321
  1408
roker@868
  1409
        char *request = calloc(1, HKP_REQ_PREFIX_LEN + encoded_key_len + 1);
Edouard@321
  1410
        if(!request){
Edouard@321
  1411
            result = PEP_OUT_OF_MEMORY;
Edouard@321
  1412
            goto free_encoded_key;
Edouard@321
  1413
        }
krista@1435
  1414
Edouard@321
  1415
        memcpy(request, HKP_REQ_PREFIX, HKP_REQ_PREFIX_LEN);
Edouard@321
  1416
        memcpy(request + HKP_REQ_PREFIX_LEN, encoded_key, encoded_key_len);
Edouard@321
  1417
        request[HKP_REQ_PREFIX_LEN + encoded_key_len] = '\0';
Edouard@321
  1418
Edouard@321
  1419
        if(!stringlist_add(encoded_keys, request)){
roker@868
  1420
            free(request);
Edouard@318
  1421
            result = PEP_OUT_OF_MEMORY;
Edouard@318
  1422
        }
Edouard@321
  1423
Edouard@321
  1424
        free(request);
Edouard@321
  1425
Edouard@321
  1426
free_encoded_key:
Edouard@318
  1427
        curl_free(encoded_key);
Edouard@321
  1428
krista@1435
  1429
free_buffer:
Edouard@321
  1430
        free(buffer);
Edouard@318
  1431
    }
Edouard@277
  1432
Edouard@318
  1433
    return result;
Edouard@277
  1434
}
Edouard@277
  1435
Edouard@174
  1436
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
Edouard@174
  1437
{
Edouard@321
  1438
    static const char *ks_cmd = HKP_SERVER "/pks/add";
Edouard@318
  1439
Edouard@277
  1440
    PEP_STATUS result;
roker@868
  1441
    CURL *curl = NULL;
Edouard@322
  1442
Edouard@174
  1443
    assert(session);
Edouard@174
  1444
    assert(pattern);
Edouard@174
  1445
Edouard@277
  1446
    if (!session || !pattern )
Edouard@661
  1447
        return PEP_ILLEGAL_VALUE;
Edouard@174
  1448
roker@868
  1449
    stringlist_t *encoded_keys = new_stringlist(NULL);
Edouard@318
  1450
    assert(encoded_keys);
Edouard@318
  1451
    if (encoded_keys == NULL) {
Edouard@318
  1452
        return PEP_OUT_OF_MEMORY;
Edouard@318
  1453
    }
Edouard@318
  1454
Edouard@277
  1455
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@322
  1456
        result = PEP_UNKNOWN_ERROR;
Edouard@322
  1457
        goto free_encoded_keys;
Edouard@277
  1458
    }
Edouard@277
  1459
edouard@1705
  1460
    result = find_keys_do((pgp_keyring_t *)netpgp.pubring,
edouard@1705
  1461
                          pattern, &send_key_cb, (void*)encoded_keys);
Edouard@277
  1462
Edouard@277
  1463
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@277
  1464
Edouard@322
  1465
    if(result != PEP_STATUS_OK){
Edouard@322
  1466
        goto free_encoded_keys;
Edouard@322
  1467
    }
Edouard@322
  1468
Edouard@318
  1469
    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
Edouard@322
  1470
        result = PEP_UNKNOWN_ERROR;
Edouard@322
  1471
        goto free_encoded_keys;
Edouard@322
  1472
    }
Edouard@322
  1473
Edouard@322
  1474
    result = curl_get_ctx(&curl);
Edouard@322
  1475
    if(result != PEP_STATUS_OK){
Edouard@322
  1476
        goto unlock_curl;
Edouard@318
  1477
    }
Edouard@318
  1478
Edouard@318
  1479
    if(result == PEP_STATUS_OK){
Edouard@318
  1480
        CURLcode curlres;
Edouard@318
  1481
roker@868
  1482
        for (const stringlist_t *post = encoded_keys; post != NULL; post = post->next) {
Edouard@318
  1483
            assert(post->value);
Edouard@318
  1484
Edouard@318
  1485
            curl_easy_setopt(curl, CURLOPT_URL, ks_cmd);
Edouard@318
  1486
            curl_easy_setopt(curl, CURLOPT_POST, 1L);
Edouard@318
  1487
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post->value);
Edouard@318
  1488
            curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
Edouard@318
  1489
Edouard@323
  1490
            // Uncomment if debugging
Edouard@323
  1491
            // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
Edouard@318
  1492
Edouard@318
  1493
            curlres = curl_easy_perform(curl);
Edouard@318
  1494
Edouard@318
  1495
            if(curlres != CURLE_OK) {
Edouard@318
  1496
Edouard@318
  1497
                result = PEP_CANNOT_SEND_KEY;
Edouard@322
  1498
                goto release_curl_ctx;
Edouard@318
  1499
            }
Edouard@318
  1500
        }
Edouard@318
  1501
    }
Edouard@318
  1502
Edouard@322
  1503
release_curl_ctx:
Edouard@322
  1504
    curl_release_ctx(&curl);
Edouard@322
  1505
unlock_curl:
Edouard@322
  1506
    pthread_mutex_unlock(&session->ctx.curl_mutex);
Edouard@318
  1507
free_encoded_keys:
Edouard@318
  1508
    free_stringlist(encoded_keys);
Edouard@318
  1509
Edouard@277
  1510
    return result;
Edouard@174
  1511
}
Edouard@174
  1512
Edouard@174
  1513
Edouard@174
  1514
PEP_STATUS pgp_get_key_rating(
Edouard@174
  1515
    PEP_SESSION session,
Edouard@384
  1516
    const char *fprstr,
Edouard@174
  1517
    PEP_comm_type *comm_type
Edouard@174
  1518
    )
Edouard@174
  1519
{
Edouard@412
  1520
    pgp_key_t *key;
Edouard@384
  1521
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@324
  1522
    unsigned from = 0;
Edouard@384
  1523
    size_t length;
Edouard@384
  1524
Edouard@324
  1525
Edouard@174
  1526
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@174
  1527
Edouard@174
  1528
    assert(session);
Edouard@384
  1529
    assert(fprstr);
Edouard@174
  1530
    assert(comm_type);
Edouard@174
  1531
Edouard@384
  1532
    if (!session || !fprstr || !comm_type )
Edouard@661
  1533
        return PEP_ILLEGAL_VALUE;
Edouard@174
  1534
Edouard@384
  1535
    *comm_type = PEP_ct_unknown;
Edouard@384
  1536
Edouard@324
  1537
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@324
  1538
        return PEP_UNKNOWN_ERROR;
Edouard@324
  1539
    }
Edouard@174
  1540
Edouard@384
  1541
    if (!str_to_fpr(fprstr, fpr, &length)) {
Edouard@324
  1542
        status = PEP_ILLEGAL_VALUE;
Edouard@324
  1543
        goto unlock_netpgp;
Edouard@324
  1544
    }
krista@1435
  1545
Edouard@384
  1546
    key = pgp_getkeybyfpr(
Edouard@384
  1547
           netpgp.io,
Edouard@384
  1548
           netpgp.pubring,
Edouard@391
  1549
           fpr, length, &from, NULL,0,0);
Edouard@324
  1550
Edouard@324
  1551
    if(key == NULL)
Edouard@324
  1552
    {
Edouard@324
  1553
        status = PEP_KEY_NOT_FOUND;
Edouard@324
  1554
        goto unlock_netpgp;
Edouard@324
  1555
    }
Edouard@324
  1556
Edouard@324
  1557
    switch(pgp_key_get_rating(key)){
Edouard@324
  1558
	case PGP_VALID:
Edouard@174
  1559
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
Edouard@174
  1560
        break;
Edouard@324
  1561
    case PGP_WEAK:
Edouard@324
  1562
        *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
Edouard@324
  1563
        break;
Edouard@324
  1564
    case PGP_TOOSHORT:
Edouard@324
  1565
        *comm_type = PEP_ct_key_too_short;
Edouard@324
  1566
        break;
Edouard@324
  1567
	case PGP_INVALID:
Edouard@324
  1568
        *comm_type = PEP_ct_key_b0rken;
Edouard@324
  1569
        break;
Edouard@324
  1570
	case PGP_EXPIRED:
Edouard@324
  1571
        *comm_type = PEP_ct_key_expired;
Edouard@324
  1572
        break;
Edouard@324
  1573
    case PGP_REVOKED:
Edouard@324
  1574
        *comm_type = PEP_ct_key_revoked;
Edouard@174
  1575
        break;
Edouard@174
  1576
    default:
Edouard@324
  1577
        break;
Edouard@174
  1578
    }
Edouard@174
  1579
Edouard@324
  1580
unlock_netpgp:
Edouard@324
  1581
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@174
  1582
Edouard@174
  1583
    return status;
Edouard@174
  1584
}
Edouard@210
  1585
Edouard@210
  1586
PEP_STATUS pgp_renew_key(
Edouard@210
  1587
        PEP_SESSION session,
Edouard@511
  1588
        const char *fprstr,
Edouard@210
  1589
        const timestamp *ts
Edouard@210
  1590
    )
Edouard@210
  1591
{
Edouard@329
  1592
    pgp_key_t *pkey;
Edouard@329
  1593
    pgp_key_t *skey;
Edouard@511
  1594
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@511
  1595
    size_t length;
Edouard@329
  1596
    unsigned from = 0;
Edouard@412
  1597
    time_t duration;
Edouard@412
  1598
    const uint8_t *primid;
Edouard@329
  1599
Edouard@210
  1600
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@210
  1601
Edouard@210
  1602
    assert(session);
Edouard@511
  1603
    assert(fprstr);
Edouard@210
  1604
Edouard@511
  1605
    if (!session || !fprstr )
Edouard@661
  1606
        return PEP_ILLEGAL_VALUE;
Edouard@210
  1607
Edouard@329
  1608
    if(ts)
Edouard@329
  1609
    {
Edouard@329
  1610
        time_t    now, when;
Edouard@329
  1611
        now = time(NULL);
Edouard@329
  1612
        when = mktime((struct tm*)ts);
Edouard@329
  1613
        if(now && when && when > now){
Edouard@412
  1614
            duration = when - now;
Edouard@329
  1615
        }else{
Edouard@329
  1616
            return PEP_ILLEGAL_VALUE;
Edouard@329
  1617
        }
Edouard@329
  1618
    }else{
Edouard@329
  1619
        /* Default 1 year from now */
Edouard@329
  1620
        duration = 365*24*3600;
Edouard@329
  1621
    }
Edouard@210
  1622
Edouard@329
  1623
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@210
  1624
        return PEP_UNKNOWN_ERROR;
Edouard@329
  1625
    }
Edouard@329
  1626
krista@1435
  1627
Edouard@511
  1628
    if (!str_to_fpr(fprstr, fpr, &length)) {
Edouard@329
  1629
        status = PEP_ILLEGAL_VALUE;
Edouard@329
  1630
        goto unlock_netpgp;
Edouard@329
  1631
    }
krista@1435
  1632
Edouard@511
  1633
    pkey = pgp_getkeybyfpr(
Edouard@511
  1634
                          netpgp.io,
Edouard@511
  1635
                          netpgp.pubring,
Edouard@511
  1636
                          fpr, length, &from, NULL,
Edouard@511
  1637
                          1, 0); /* reject revoked, accept expired */
Edouard@329
  1638
Edouard@329
  1639
    if(pkey == NULL)
Edouard@329
  1640
    {
Edouard@329
  1641
        status = PEP_KEY_NOT_FOUND;
Edouard@329
  1642
        goto unlock_netpgp;
Edouard@329
  1643
    }
Edouard@329
  1644
Edouard@329
  1645
    from = 0;
Edouard@511
  1646
    skey = pgp_getkeybyfpr(
Edouard@511
  1647
                           netpgp.io,
Edouard@521
  1648
                           netpgp.secring,
Edouard@511
  1649
                           fpr, length, &from, NULL,
Edouard@511
  1650
                           1, 0); /* reject revoked, accept expired */
Edouard@329
  1651
Edouard@329
  1652
    if(skey == NULL)
Edouard@329
  1653
    {
Edouard@329
  1654
        status = PEP_KEY_NOT_FOUND;
Edouard@329
  1655
        goto unlock_netpgp;
Edouard@329
  1656
    }
Edouard@329
  1657
Edouard@412
  1658
    if((primid = pgp_key_get_primary_userid(skey)) == NULL)
Edouard@329
  1659
    {
Edouard@329
  1660
        status = PEP_KEY_HAS_AMBIG_NAME;
Edouard@329
  1661
        goto unlock_netpgp;
Edouard@329
  1662
    }
Edouard@329
  1663
Edouard@522
  1664
    // FIXME : renew in a more gentle way
Edouard@329
  1665
    if (!pgp_add_selfsigned_userid(skey, pkey, primid, duration))
Edouard@329
  1666
    {
Edouard@329
  1667
        status = PEP_CANNOT_CREATE_KEY;
Edouard@329
  1668
        goto unlock_netpgp;
Edouard@329
  1669
    }
Edouard@329
  1670
Edouard@521
  1671
    // save rings
Edouard@521
  1672
    if (netpgp_save_pubring(&netpgp) &&
Edouard@521
  1673
        netpgp_save_secring(&netpgp))
Edouard@521
  1674
    {
Edouard@521
  1675
        status = PEP_STATUS_OK;
Edouard@521
  1676
    }else{
Edouard@521
  1677
        status = PEP_UNKNOWN_ERROR;
Edouard@521
  1678
    }
krista@1435
  1679
Edouard@329
  1680
unlock_netpgp:
Edouard@329
  1681
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@329
  1682
Edouard@329
  1683
    return status;
Edouard@210
  1684
}
Edouard@210
  1685
Edouard@226
  1686
PEP_STATUS pgp_revoke_key(
Edouard@226
  1687
        PEP_SESSION session,
Edouard@522
  1688
        const char *fprstr,
Edouard@226
  1689
        const char *reason
Edouard@226
  1690
    )
Edouard@210
  1691
{
Edouard@522
  1692
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@522
  1693
    size_t length;
Edouard@326
  1694
    unsigned from = 0;
Edouard@326
  1695
Edouard@210
  1696
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@326
  1697
Edouard@210
  1698
    assert(session);
Edouard@522
  1699
    assert(fprstr);
Edouard@210
  1700
Edouard@522
  1701
    if (!session || !fprstr)
Edouard@210
  1702
        return PEP_UNKNOWN_ERROR;
Edouard@210
  1703
Edouard@326
  1704
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@326
  1705
        return PEP_UNKNOWN_ERROR;
Edouard@326
  1706
    }
Edouard@326
  1707
Edouard@522
  1708
    // FIXME : deduplicate that code w/ renew
Edouard@522
  1709
    if (!str_to_fpr(fprstr, fpr, &length)) {
Edouard@326
  1710
        status = PEP_ILLEGAL_VALUE;
Edouard@326
  1711
        goto unlock_netpgp;
Edouard@326
  1712
    }
krista@1435
  1713
roker@868
  1714
    pgp_key_t *pkey = pgp_getkeybyfpr(
Edouard@522
  1715
                           netpgp.io,
Edouard@522
  1716
                           netpgp.pubring,
Edouard@522
  1717
                           fpr, length, &from, NULL,
Edouard@522
  1718
                           1, 0); /* reject revoked, accept expired */
krista@1435
  1719
Edouard@326
  1720
    if(pkey == NULL)
Edouard@326
  1721
    {
Edouard@326
  1722
        status = PEP_KEY_NOT_FOUND;
Edouard@326
  1723
        goto unlock_netpgp;
Edouard@326
  1724
    }
krista@1435
  1725
Edouard@326
  1726
    from = 0;
roker@868
  1727
    pgp_key_t *skey = pgp_getkeybyfpr(
Edouard@522
  1728
                           netpgp.io,
Edouard@522
  1729
                           netpgp.secring,
Edouard@522
  1730
                           fpr, length, &from, NULL,
Edouard@522
  1731
                           1, 0); /* reject revoked, accept expired */
krista@1435
  1732
Edouard@326
  1733
    if(skey == NULL)
Edouard@326
  1734
    {
Edouard@326
  1735
        status = PEP_KEY_NOT_FOUND;
Edouard@326
  1736
        goto unlock_netpgp;
Edouard@326
  1737
    }
Edouard@326
  1738
Edouard@326
  1739
    pgp_key_revoke(skey, pkey,
Edouard@326
  1740
                   0, /* no reason code specified */
Edouard@326
  1741
                   reason);
Edouard@326
  1742
Edouard@326
  1743
unlock_netpgp:
Edouard@326
  1744
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@326
  1745
Edouard@326
  1746
    return status;
Edouard@210
  1747
}
Edouard@210
  1748
Edouard@226
  1749
PEP_STATUS pgp_key_expired(
Edouard@226
  1750
        PEP_SESSION session,
Edouard@661
  1751
        const char *fprstr,
Edouard@701
  1752
        const time_t when,
Edouard@226
  1753
        bool *expired
Edouard@226
  1754
    )
Edouard@226
  1755
{
Edouard@226
  1756
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@325
  1757
    PEP_comm_type comm_type;
Edouard@226
  1758
Edouard@226
  1759
    assert(session);
Edouard@661
  1760
    assert(fprstr);
Edouard@226
  1761
    assert(expired);
Edouard@226
  1762
Edouard@661
  1763
    if (!session || !fprstr || !expired)
Edouard@661
  1764
        return PEP_UNKNOWN_ERROR;
Edouard@661
  1765
krista@1435
  1766
    // TODO : take "when" in account
Edouard@661
  1767
Edouard@226
  1768
    *expired = false;
Edouard@226
  1769
Edouard@661
  1770
    status = pgp_get_key_rating(session, fprstr, &comm_type);
Edouard@325
  1771
Edouard@226
  1772
    if (status != PEP_STATUS_OK)
Edouard@226
  1773
        return status;
Edouard@226
  1774
Edouard@325
  1775
    if (comm_type == PEP_ct_key_expired){
Edouard@325
  1776
        *expired = true;
Edouard@325
  1777
    }
Edouard@325
  1778
Edouard@226
  1779
    return PEP_STATUS_OK;
Edouard@226
  1780
}
Edouard@226
  1781
Edouard@661
  1782
PEP_STATUS pgp_key_revoked(
Edouard@661
  1783
        PEP_SESSION session,
Edouard@661
  1784
        const char *fprstr,
Edouard@661
  1785
        bool *revoked
Edouard@661
  1786
    )
Edouard@661
  1787
{
Edouard@661
  1788
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@661
  1789
    PEP_comm_type comm_type;
krista@1435
  1790
Edouard@661
  1791
    assert(session);
Edouard@661
  1792
    assert(fprstr);
Edouard@661
  1793
    assert(revoked);
krista@1435
  1794
Edouard@661
  1795
    *revoked = false;
krista@1435
  1796
Edouard@661
  1797
    status = pgp_get_key_rating(session, fprstr, &comm_type);
krista@1435
  1798
Edouard@661
  1799
    if (status != PEP_STATUS_OK)
Edouard@661
  1800
        return status;
krista@1435
  1801
Edouard@661
  1802
    if (comm_type == PEP_ct_key_revoked){
Edouard@661
  1803
        *revoked = true;
Edouard@661
  1804
    }
krista@1435
  1805
Edouard@661
  1806
    return PEP_STATUS_OK;
Edouard@661
  1807
}
krista@1010
  1808
dirk@973
  1809
PEP_STATUS pgp_key_created(
dirk@973
  1810
        PEP_SESSION session,
dirk@973
  1811
        const char *fprstr,
dirk@973
  1812
        time_t *created
dirk@973
  1813
    )
dirk@973
  1814
{
dirk@973
  1815
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
dirk@973
  1816
    pgp_key_t *key;
dirk@973
  1817
    size_t length;
dirk@973
  1818
    unsigned from = 0;
dirk@973
  1819
dirk@973
  1820
    PEP_STATUS status = PEP_STATUS_OK;
dirk@973
  1821
dirk@973
  1822
    assert(session);
dirk@973
  1823
    assert(fprstr);
dirk@973
  1824
    assert(created);
dirk@973
  1825
dirk@973
  1826
    if (!session || !fprstr || !created)
dirk@973
  1827
        return PEP_UNKNOWN_ERROR;
dirk@973
  1828
dirk@973
  1829
    *created = 0;
dirk@973
  1830
dirk@973
  1831
    if(pthread_mutex_lock(&netpgp_mutex)){
dirk@973
  1832
        return PEP_UNKNOWN_ERROR;
dirk@973
  1833
    }
dirk@973
  1834
dirk@973
  1835
    if (!str_to_fpr(fprstr, fpr, &length)) {
dirk@973
  1836
        status = PEP_ILLEGAL_VALUE;
dirk@973
  1837
        goto unlock_netpgp;
dirk@973
  1838
    }
krista@1435
  1839
dirk@973
  1840
    key = pgp_getkeybyfpr(
dirk@973
  1841
           netpgp.io,
dirk@973
  1842
           netpgp.pubring,
dirk@973
  1843
           fpr, length, &from, NULL,0,0);
dirk@973
  1844
dirk@973
  1845
    if (key)
dirk@973
  1846
    {
dirk@973
  1847
        *created = (time_t) key->key.pubkey.birthtime;
dirk@973
  1848
    }
dirk@973
  1849
    else
dirk@973
  1850
    {
dirk@973
  1851
        status = PEP_KEY_NOT_FOUND;
dirk@973
  1852
        goto unlock_netpgp;
dirk@973
  1853
    }
krista@1435
  1854
dirk@973
  1855
dirk@973
  1856
dirk@973
  1857
unlock_netpgp:
dirk@973
  1858
    pthread_mutex_unlock(&netpgp_mutex);
dirk@973
  1859
dirk@973
  1860
    return status;
dirk@973
  1861
}
roker@1057
  1862
krista@1018
  1863
krista@1030
  1864
PEP_STATUS pgp_list_keyinfo(
krista@1030
  1865
        PEP_SESSION session, const char* pattern, stringpair_list_t** keyinfo_list)
krista@1030
  1866
{
krista@1435
  1867
krista@1030
  1868
    if (!session || !keyinfo_list)
krista@1030
  1869
        return PEP_UNKNOWN_ERROR;
krista@1435
  1870
krista@1030
  1871
    if (pthread_mutex_lock(&netpgp_mutex))
krista@1030
  1872
    {
krista@1030
  1873
        return PEP_UNKNOWN_ERROR;
krista@1018
  1874
    }
krista@1435
  1875
hernani@1390
  1876
// Unused:
hernani@1390
  1877
//    pgp_key_t *key;
krista@1010
  1878
krista@1010
  1879
    PEP_STATUS result;
krista@1435
  1880
edouard@1705
  1881
    result = find_keys_do((pgp_keyring_t *)netpgp.pubring,
edouard@1705
  1882
                          pattern, &add_keyinfo_to_stringpair_list, (void*)keyinfo_list);
krista@1435
  1883
krista@1031
  1884
    if (!keyinfo_list)
krista@1031
  1885
        result = PEP_KEY_NOT_FOUND;
krista@1435
  1886
krista@1030
  1887
    pthread_mutex_unlock(&netpgp_mutex);
krista@1435
  1888
krista@1010
  1889
    return result;
krista@1010
  1890
}
krista@1362
  1891
krista@1362
  1892
/* copied from find_keys, but we need to use a callback that filters. */
krista@1363
  1893
PEP_STATUS pgp_find_private_keys(
krista@1362
  1894
    PEP_SESSION session, const char *pattern, stringlist_t **keylist)
krista@1362
  1895
{
krista@1362
  1896
    stringlist_t *_keylist, *_k;
krista@1435
  1897
krista@1362
  1898
    PEP_STATUS result;
krista@1435
  1899
krista@1362
  1900
    assert(session);
krista@1362
  1901
    assert(keylist);
krista@1435
  1902
edouard@1775
  1903
    if (!session || !keylist )
krista@1362
  1904
    {
krista@1362
  1905
        return PEP_ILLEGAL_VALUE;
krista@1362
  1906
    }
krista@1435
  1907
krista@1362
  1908
    if (pthread_mutex_lock(&netpgp_mutex))
krista@1362
  1909
    {
krista@1362
  1910
        return PEP_UNKNOWN_ERROR;
krista@1362
  1911
    }
krista@1435
  1912
krista@1362
  1913
    *keylist = NULL;
krista@1362
  1914
    _keylist = new_stringlist(NULL);
krista@1362
  1915
    if (_keylist == NULL) {
krista@1362
  1916
        result = PEP_OUT_OF_MEMORY;
krista@1362
  1917
        goto unlock_netpgp;
krista@1362
  1918
    }
krista@1362
  1919
    _k = _keylist;
krista@1435
  1920
edouard@1705
  1921
    result = find_keys_do((pgp_keyring_t *)netpgp.secring,
edouard@1705
  1922
                          pattern, &add_secret_key_fpr_to_stringlist, &_k);
krista@1435
  1923
krista@1362
  1924
    if (result == PEP_STATUS_OK) {
krista@1362
  1925
        *keylist = _keylist;
krista@1362
  1926
        // Transfer ownership, no free
krista@1362
  1927
        goto unlock_netpgp;
krista@1362
  1928
    }
krista@1435
  1929
krista@1362
  1930
    free_stringlist(_keylist);
krista@1435
  1931
krista@1362
  1932
unlock_netpgp:
krista@1362
  1933
    pthread_mutex_unlock(&netpgp_mutex);
krista@1435
  1934
krista@1435
  1935
    return result;
krista@1362
  1936
}
krista@1362
  1937
krista@1362
  1938
PEP_STATUS pgp_contains_priv_key(
krista@1435
  1939
    PEP_SESSION session,
krista@1362
  1940
    const char *fpr,
krista@1362
  1941
    bool *has_private) {
krista@1362
  1942
    stringlist_t* keylist = NULL;
krista@1363
  1943
    PEP_STATUS status = pgp_find_private_keys(session, fpr, &keylist);
krista@1362
  1944
    if (status == PEP_STATUS_OK && keylist) {
krista@1362
  1945
        free_stringlist(keylist);
krista@1362
  1946
        *has_private = true;
krista@1362
  1947
    }
krista@1362
  1948
    else {
krista@1362
  1949
        has_private = false;
krista@1362
  1950
    }
krista@1362
  1951
    return status;
krista@1362
  1952
}