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