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