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